package org.eclipse.swt.widgets; /* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html */ import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.events.*; /** * Instances of this class represent the "windows" * which the desktop or "window manager" is managing. * Instances that do not have a parent (that is, they * are built using the constructor, which takes a * Display as the argument) are described * as top level shells. Instances that do have * a parent are described as secondary or * dialog shells. *

* Instances are always displayed in one of the maximized, * minimized or normal states: *

*

*

* Note: The styles supported by this class must be treated * as HINTs, since the window manager for the * desktop on which the instance is visible has ultimate * control over the appearance and behavior of decorations * and modality. For example, some window managers only * support resizable windows and will always assume the * RESIZE style, even if it is not set. In addition, if a * modality style is not supported, it is "upgraded" to a * more restrictive modality style that is supported. For * example, if PRIMARY_MODAL is not supported, * it would be upgraded to APPLICATION_MODAL. *

*
Styles:
*
BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE
*
APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL
*
Events:
*
Activate, Close, Deactivate, Deiconify, Iconify
*
* Class SWT provides two "convenience constants" * for the most commonly required style combinations: *
*
SHELL_TRIM
*
* the result of combining the constants which are required * to produce a typical application top level shell: (that * is, CLOSE | TITLE | MIN | MAX | RESIZE) *
*
DIALOG_TRIM
*
* the result of combining the constants which are required * to produce a typical application dialog shell: (that * is, TITLE | CLOSE | BORDER) *
*
*

*

* Note: Only one of the styles APPLICATION_MODAL, MODELESS, * PRIMARY_MODAL and SYSTEM_MODAL may be specified. *

* IMPORTANT: This class is not intended to be subclassed. *

* * @see Decorations * @see SWT */ public class Shell extends Decorations { Display display; int vboxHandle; int modal; int accelGroup; Rectangle lastClientArea; boolean hasFocus; /* * === CONSTRUCTORS === */ /** * Constructs a new instance of this class. This is equivalent * to calling Shell((Display) null). * * @exception SWTException */ public Shell () { this ((Display) null); } /** * Constructs a new instance of this class given only the style * value describing its behavior and appearance. This is equivalent * to calling Shell((Display) null, style). *

* The style value is either one of the style constants defined in * class SWT which is applicable to instances of this * class, or must be built by bitwise OR'ing together * (that is, using the int "|" operator) two or more * of those SWT style constants. The class description * for all SWT widget classes should include a comment which * describes the style constants which are applicable to the class. *

* * @param style the style of control to construct * * @exception SWTException */ public Shell (int style) { this ((Display) null, style); } /** * Constructs a new instance of this class given only the display * to create it on. It is created with style SWT.SHELL_TRIM. *

* Note: Currently, null can be passed in for the display argument. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. Passing in null as * the display argument is not considered to be good coding style, * and may not be supported in a future release of SWT. *

* * @param display the display to create the shell on * * @exception SWTException */ public Shell (Display display) { this (display, SWT.SHELL_TRIM); } /** * Constructs a new instance of this class given the display * to create it on and a style value describing its behavior * and appearance. *

* The style value is either one of the style constants defined in * class SWT which is applicable to instances of this * class, or must be built by bitwise OR'ing together * (that is, using the int "|" operator) two or more * of those SWT style constants. The class description * for all SWT widget classes should include a comment which * describes the style constants which are applicable to the class. *

* Note: Currently, null can be passed in for the display argument. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. Passing in null as * the display argument is not considered to be good coding style, * and may not be supported in a future release of SWT. *

* * @param display the display to create the shell on * @param style the style of control to construct * * @exception SWTException */ public Shell (Display display, int style) { this (display, null, style); } Shell (Display display, Shell parent, int style) { super (); if (display == null) display = Display.getCurrent (); if (display == null) display = Display.getDefault (); if (!display.isValidThread ()) { error (SWT.ERROR_THREAD_INVALID_ACCESS); } this.style = checkStyle (style); this.parent = parent; this.display = display; this.handle = handle; createWidget (0); } /** * Constructs a new instance of this class given only its * parent. It is created with style SWT.DIALOG_TRIM. *

* Note: Currently, null can be passed in for the parent. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. Passing in null as * the parent is not considered to be good coding style, * and may not be supported in a future release of SWT. *

* * @param parent a shell which will be the parent of the new instance * * @exception IllegalArgumentException * @exception SWTException */ public Shell (Shell parent) { this (parent, SWT.TITLE | SWT.CLOSE | SWT.BORDER); } /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. *

* The style value is either one of the style constants defined in * class SWT which is applicable to instances of this * class, or must be built by bitwise OR'ing together * (that is, using the int "|" operator) two or more * of those SWT style constants. The class description * for all SWT widget classes should include a comment which * describes the style constants which are applicable to the class. *

* Note: Currently, null can be passed in for the parent. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. Passing in null as * the parent is not considered to be good coding style, * and may not be supported in a future release of SWT. *

* * @param parent a shell which will be the parent of the new instance * @param style the style of control to construct * * @exception SWTException */ public Shell (Shell parent, int style) { this (null, parent, style); } /** * Adds the listener to the collection of listeners who will * be notified when operations are performed on the receiver, * by sending the listener one of the messages defined in the * ShellListener interface. * * @param listener the listener which should be notified * * @exception IllegalArgumentException * @exception SWTException * * @see ShellListener * @see #removeShellListener */ public void addShellListener (ShellListener listener) { checkWidget(); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Close,typedListener); addListener (SWT.Iconify,typedListener); addListener (SWT.Deiconify,typedListener); addListener (SWT.Activate, typedListener); addListener (SWT.Deactivate, typedListener); } void bringToTop () { // OS.gtk_window_activate_focus (shellHandle); } /** * Requests that the window manager close the receiver in * the same way it would be closed when the user clicks on * the "close box" or performs some other platform specific * key or mouse combination that indicates the window * should be removed. * * @exception SWTException */ public void close () { checkWidget (); closeWidget (); } void closeWidget () { Event event = new Event (); event.time = OS.gdk_time_get (); sendEvent (SWT.Close, event); if (event.doit && !isDisposed ()) dispose (); } /* * === Handle code I: The createWidget() cycle. */ void createHandle (int index) { state |= HANDLE; topHandle = OS.gtk_window_new((parent==null)? OS.GTK_WINDOW_TOPLEVEL:OS.GTK_WINDOW_DIALOG); if (topHandle == 0) SWT.error (SWT.ERROR_NO_HANDLES); if (parent!=null) OS.gtk_window_set_transient_for(topHandle, parent.topHandle()); vboxHandle = OS.gtk_vbox_new(false,0); if (vboxHandle == 0) SWT.error (SWT.ERROR_NO_HANDLES); eventBoxHandle = OS.gtk_event_box_new (); if (eventBoxHandle == 0) error (SWT.ERROR_NO_HANDLES); fixedHandle = OS.gtk_fixed_new (); if (fixedHandle == 0) SWT.error (SWT.ERROR_NO_HANDLES); handle = OS.gtk_drawing_area_new(); if (handle == 0) SWT.error (SWT.ERROR_NO_HANDLES); accelGroup = OS.gtk_accel_group_new (); OS.gtk_window_add_accel_group (topHandle, accelGroup); OS.gtk_window_set_title (topHandle, new byte [1]); } void configure () { OS.gtk_container_add (topHandle, vboxHandle); OS.gtk_box_pack_end(vboxHandle, eventBoxHandle, true,true,0); OS.gtk_container_add (eventBoxHandle, fixedHandle); OS.gtk_fixed_put(fixedHandle, handle, (short)0,(short)0); } void showHandle() { OS.gtk_widget_realize (topHandle); // careful: NOT show _setStyle(); OS.gtk_widget_realize (vboxHandle); OS.gtk_widget_show_now (vboxHandle); OS.gtk_widget_realize (eventBoxHandle); OS.gtk_widget_show_now (eventBoxHandle); OS.gtk_widget_realize (fixedHandle); OS.gtk_widget_show_now (fixedHandle); OS.gtk_widget_realize (handle); OS.gtk_widget_show_now (handle); } void hookEvents () { super.hookEvents (); signal_connect(topHandle, "map_event", SWT.Deiconify, 3); signal_connect(topHandle, "unmap_event", SWT.Iconify, 3); signal_connect(topHandle, "size_allocate", SWT.Resize, 3); signal_connect(topHandle, "delete_event", SWT.Dispose, 3); } void register () { super.register (); WidgetTable.put (vboxHandle, this); } private void _setStyle() { boolean modal = ( ((style&SWT.PRIMARY_MODAL) != 0) || ((style&SWT.APPLICATION_MODAL) != 0) || ((style&SWT.SYSTEM_MODAL) != 0)); OS.gtk_window_set_modal(topHandle, modal); int decorations = 0; if ((style & SWT.NO_TRIM) == 0) { if ((style & SWT.MIN) != 0) decorations |= OS.GDK_DECOR_MINIMIZE; if ((style & SWT.MAX) != 0) decorations |= OS.GDK_DECOR_MAXIMIZE; if ((style & SWT.RESIZE) != 0) decorations |= OS.GDK_DECOR_RESIZEH; if ((style & SWT.BORDER) != 0) decorations |= OS.GDK_DECOR_BORDER; if ((style & SWT.MENU) != 0) decorations |= OS.GDK_DECOR_MENU; if ((style & SWT.TITLE) != 0) decorations |= OS.GDK_DECOR_TITLE; /* * Under some Window Managers (Sawmill), in order * to get any border at all from the window manager it is necessary * to set GDK_DECOR_BORDER. The fix is to force these bits when any * kind of border is requested. */ if ((style & SWT.RESIZE) != 0) decorations |= OS.GDK_DECOR_BORDER; } GtkWidget widget = new GtkWidget(); OS.memmove(widget, topHandle, GtkWidget.sizeof); int w = widget.window; // PANIC - this must absolutely never happen, so it's not NO_HANDLES actually if (w == 0) error(SWT.ERROR_NO_HANDLES); OS.gdk_window_set_decorations(w, decorations); } void _connectChild (int h) { OS.gtk_fixed_put (fixedHandle, h, (short)0, (short)0); } int topHandle () { return topHandle; } int parentingHandle() { return fixedHandle; } boolean isMyHandle(int h) { if (h == topHandle) return true; if (h == vboxHandle) return true; if (h == eventBoxHandle) return true; if (h == fixedHandle) return true; if (h == handle) return true; return false; } /* * === GEOMETRY === */ public Point _getLocation() { GtkWidget widget = new GtkWidget(); OS.memmove (widget, topHandle, GtkWidget.sizeof); int [] x = new int [1], y = new int [1]; OS.gdk_window_get_origin(widget.window, x,y); return new Point(x[0], y[0]); } public Point _getSize() { return UtilFuncs.getSize(vboxHandle); } public Rectangle _getClientArea () { Point clientSize = UtilFuncs.getSize(eventBoxHandle); return new Rectangle (0, 0, clientSize.x, clientSize.y); } boolean _setSize(int width, int height) { /* * API deficiency in GTK 1.2 - lacking gtk_window_resize. * We work around this by directly resizing the X window. * * First, we find out the GDK handle. */ GtkWidget gtkWidget = new GtkWidget(); OS.memmove(gtkWidget, topHandle, GtkWidget.sizeof); OS.gtk_signal_handler_block_by_data (topHandle, SWT.Resize); OS.gdk_window_resize(gtkWidget.window, width, height); UtilFuncs.setSize(vboxHandle, width, height); Point sz = UtilFuncs.getSize(eventBoxHandle); UtilFuncs.setSize(fixedHandle, sz.x, sz.y); UtilFuncs.setSize(handle, sz.x, sz.y); OS.gtk_signal_handler_unblock_by_data (topHandle, SWT.Resize); return true; } boolean _setLocation (int x, int y) { GtkWidget gtkWidget = new GtkWidget(); OS.memmove(gtkWidget, topHandle, GtkWidget.sizeof); OS.gdk_window_move(gtkWidget.window, x, y); return true; } void setInitialSize() { int width = OS.gdk_screen_width () * 5 / 8; int height = OS.gdk_screen_height () * 5 / 8; _setSize(width, height); OS.gtk_window_set_policy (topHandle, 1,1,0); } /* * We can't setInitialSize() before showHandle() in the case of Shell, * because we operate on the actual X window, so the shell must be * realized by that time. * This is a workaround until gtk_window_resize(). */ void createWidget (int index) { createHandle (index); hookEvents (); configure (); setHandleStyle (); register (); showHandle (); setInitialSize (); } public Display getDisplay () { if (display == null) error (SWT.ERROR_WIDGET_DISPOSED); return display; } /* * Return the control inside this shell that has the focus, * if there is one. Return null if there is no * such control - e.g., this shell is not active, or it is active * but the user clicked in a no-entry widget (like Label). */ Control getFocusControl() { GtkWindow shell = new GtkWindow(); OS.memmove(shell, topHandle, GtkWindow.sizeof); int focusHandle = shell.focus_widget; if (focusHandle==0) return null; return (Control)this.getDisplay().findWidget(focusHandle); } /** * Returns the receiver's input method editor mode. This * will be the result of bitwise OR'ing together one or * more of the following constants defined in class * SWT: * NONE, ROMAN, DBCS, * PHONETIC, NATIVE, ALPHA. * * @return the IME mode * * @exception SWTException * * @see SWT */ public int getImeInputMode () { checkWidget(); return SWT.NONE; } /** * Get the modal state. *

* @return the modal state * * @exception SWTError(ERROR_ERROR_INVALID_PARENT) * when the parent is invalid * @exception SWTError(ERROR_THREAD_INVALID_ACCESS) */ public int getModal () { checkWidget(); return modal; } Shell _getShell () { return this; } /** * Returns an array containing all shells which are * descendents of the receiver. *

* @return the dialog shells * * @exception SWTException

*/ public Shell [] getShells () { checkWidget(); int count = 0; Shell [] shells = display.getShells (); for (int i=0; i *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • * * * @see Control#setVisible * @see Decorations#setDefaultButton */ public void open () { checkWidget(); setVisible (true); } int processDispose (int int0, int int1, int int2) { closeWidget (); return 1; } int processFocusIn(int int0, int int1, int int2) { hasFocus=true; postEvent(SWT.Activate); return 0; } int processFocusOut(int int0, int int1, int int2) { hasFocus=false; postEvent(SWT.Deactivate); return 0; } int processPaint (int callData, int int2, int int3) { //if (!hooks (SWT.Paint)) return 1; GdkEventExpose gdkEvent = new GdkEventExpose (); OS.memmove (gdkEvent, callData, GdkEventExpose.sizeof); Event event = new Event (); event.count = gdkEvent.count; event.x = gdkEvent.x; event.y = gdkEvent.y; event.width = gdkEvent.width; event.height = gdkEvent.height; GC gc = event.gc = new GC (this); GdkRectangle rect = new GdkRectangle (); rect.x = gdkEvent.x; rect.y = gdkEvent.y; rect.width = gdkEvent.width; rect.height = gdkEvent.height; OS.gdk_gc_set_clip_rectangle (gc.handle, rect); gc.fillRectangle(rect.x, rect.y, rect.width, rect.height); sendEvent (SWT.Paint, event); gc.dispose (); event.gc = null; return 1; /*}else{ GdkRectangle gdkEvent = new GdkRectangle (); OS.memmove (gdkEvent, callData, GdkRectangle.sizeof); Event event = new Event (); // event.count = gdkEvent.count; event.x = gdkEvent.x; event.y = gdkEvent.y; event.width = gdkEvent.width; event.height = gdkEvent.height; GC gc = event.gc = new GC (this); OS.gdk_gc_set_clip_rectangle (gc.handle, gdkEvent); sendEvent (SWT.Paint, event); gc.dispose (); event.gc = null; return 1; } */ } /** * Removes the listener from the collection of listeners who will * be notified when operations are performed on the receiver. * * @param listener the listener which should no longer be notified * * @exception IllegalArgumentException * @exception SWTException * * @see ShellListener * @see #addShellListener */ public void removeShellListener (ShellListener listener) { checkWidget(); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); if (eventTable == null) return; eventTable.unhook (SWT.Close, listener); eventTable.unhook (SWT.Iconify,listener); eventTable.unhook (SWT.Deiconify,listener); eventTable.unhook (SWT.Activate, listener); eventTable.unhook (SWT.Deactivate, listener); } /** * Sets the input method editor mode to the argument which * should be the result of bitwise OR'ing together one or more * of the following constants defined in class SWT: * NONE, ROMAN, DBCS, * PHONETIC, NATIVE, ALPHA. * * @param mode the new IME mode * * @exception SWTException * * @see SWT */ public void setImeInputMode (int mode) { checkWidget(); } public void setMaximized (boolean maximized) { checkWidget(); /* * Out of luck on curent GDK. */ } public void setMenuBar (Menu menu) { checkWidget(); if (menuBar == menu) return; if (menu != null) { if ((menu.style & SWT.BAR) == 0) error (SWT.ERROR_MENU_NOT_BAR); if (menu.parent != this) error (SWT.ERROR_INVALID_PARENT); } if (menu == null) { if (menuBar != null) { OS.gtk_object_ref (menuBar.handle); OS.gtk_container_remove (vboxHandle, menuBar.handle); } } menuBar = menu; if (menuBar != null) { int menuHandle = menu.handle; OS.gtk_box_pack_start (vboxHandle, menuHandle, false, false, 0); } } public void setMinimized (boolean minimized) { checkWidget(); /* * In GDK, there is no way to iconify a shell. * If we wanted it really badly, on pure X this is done * by sending a client message - see ICCCM L.4.1.4. */ if (minimized) return; /* * At least we can force a deiconify */ GtkWidget w = new GtkWidget(); OS.memmove(w, topHandle, w.sizeof); OS.gdk_window_show(w.window); } /** * Set the modal state. *

    * @param modal the new modal state * * @exception SWTError(ERROR_ERROR_INVALID_PARENT) * when the parent is invalid * @exception SWTError(ERROR_THREAD_INVALID_ACCESS) */ public void setModal (int modal) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); this.modal = modal; } public void setText (String string) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); if (string == null) error (SWT.ERROR_NULL_ARGUMENT); super.setText (string); byte [] buffer = Converter.wcsToMbcs (null, string, true); OS.gtk_window_set_title (topHandle, buffer); } public void setVisible (boolean visible) { checkWidget(); if (visible) { OS.gtk_widget_show_now (topHandle); display.update(); sendEvent (SWT.Show); } else { OS.gtk_widget_hide (topHandle); sendEvent (SWT.Hide); } } /* * === DESTRUCTION === */ void deregister () { super.deregister (); WidgetTable.remove (vboxHandle); } void releaseHandle () { super.releaseHandle (); vboxHandle = 0; } void releaseShells () { Shell [] shells = getShells (); for (int i=0; i