package org.eclipse.swt.widgets; /* * Licensed Materials - Property of IBM, * SWT - The Simple Widget Toolkit, * (c) Copyright IBM Corp 1998, 1999. */ /** * The shell class implements a top level window * and dialog windows. * * Styles * * ON_TOP * DBCS * * Events * **/ /* Imports */ import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.motif.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.events.*; /* Class Definition */ public /*final*/ class Shell extends Decorations { Display display; int shellHandle; boolean reparented, realized; int oldX, oldY, oldWidth, oldHeight; Control lastFocus; /** * Creates a widget. */ public Shell () { this ((Display) null); } /** * Creates a widget. */ public Shell (int style) { this ((Display) null, style); } /** * Creates a widget. */ public Shell (Display display) { this (display, SWT.SHELL_TRIM); } /** * Creates a widget. *

* This method creates a top level shell widget on a * display using style bits to select a particular look * or set of properties. * * @param display the Display (or null for the default) * @param style the bitwise OR'ing of widget styles * * @exception SWTError(ERROR_ERROR_INVALID_PARENT) * when the parent is invalid * @exception SWTError(ERROR_THREAD_INVALID_ACCESS) * when called from the wrong thread */ public Shell (Display display, int style) { this (display, null, style, 0); } Shell (Display display, Shell parent, int style, int handle) { 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); } /** * Creates a widget. */ public Shell (Shell parent) { this (parent, SWT.DIALOG_TRIM); } /** * Creates a widget. */ public Shell (Shell parent, int style) { this (parent != null ? parent.getDisplay () : null, parent, style, 0); } static int checkStyle (int style) { style = Decorations.checkStyle (style); int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL; int bits = style & ~mask; if ((style & SWT.SYSTEM_MODAL) != 0) return bits | SWT.SYSTEM_MODAL; if ((style & SWT.APPLICATION_MODAL) != 0) return bits | SWT.APPLICATION_MODAL; if ((style & SWT.PRIMARY_MODAL) != 0) return bits | SWT.PRIMARY_MODAL; return bits; } public static Shell motif_new (Display display, int handle) { return new Shell (display, null, SWT.NO_TRIM, handle); } /** * Adds the listener to receive events. *

* * @param listener the listener * * @exception SWTError(ERROR_THREAD_INVALID_ACCESS) * when called from the wrong thread * @exception SWTError(ERROR_WIDGET_DISPOSED) * when the widget has been disposed * @exception SWTError(ERROR_NULL_ARGUMENT) * when listener is null */ public void addShellListener(ShellListener listener) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener(SWT.Activate,typedListener); addListener(SWT.Close,typedListener); addListener(SWT.Deactivate,typedListener); addListener(SWT.Iconify,typedListener); addListener(SWT.Deiconify,typedListener); } void adjustTrim () { if ((style & SWT.ON_TOP) != 0) return; /* Query the trim insets */ int shellWindow = OS.XtWindow (shellHandle); if (shellWindow == 0) return; int xDisplay = OS.XtDisplay (shellHandle); if (xDisplay == 0) return; /* Find the direct child of the root window */ int [] unused = new int [1]; int [] rootWindow = new int [1]; int [] parent = new int [1]; int [] ptr = new int [1]; int trimWindow = shellWindow; OS.XQueryTree (xDisplay, trimWindow, rootWindow, parent, ptr, unused); if (ptr [0] != 0) OS.XFree (ptr [0]); if (parent [0] == 0) return; while (parent [0] != rootWindow [0]) { trimWindow = parent [0]; OS.XQueryTree (xDisplay, trimWindow, unused, parent, ptr, unused); if (ptr [0] != 0) OS.XFree (ptr [0]); if (parent [0] == 0) return; } /** * Translate the coordinates of the shell window to the * coordinates of the direct child of the root window */ if (shellWindow == trimWindow) return; /* Query the border width of the direct child of the root window */ int [] trimBorder = new int [1]; int [] trimWidth = new int [1]; int [] trimHeight = new int [1]; OS.XGetGeometry (xDisplay, trimWindow, unused, unused, unused, trimWidth, trimHeight, trimBorder, unused); /* Query the border width of the direct child of the shell window */ int [] shellBorder = new int [1]; int [] shellWidth = new int [1]; int [] shellHeight = new int [1]; OS.XGetGeometry (xDisplay, shellWindow, unused, unused, unused, shellWidth, shellHeight, shellBorder, unused); /* Calculate the trim */ int width = (trimWidth [0] + (trimBorder [0] * 2)) - (shellWidth [0] + (shellBorder [0] * 2)); int height = (trimHeight [0] + (trimBorder [0] * 2)) - (shellHeight [0] + (shellBorder [0] * 2)); /* Update the trim guesses to match the query */ boolean hasTitle = false, hasResize = false, hasBorder = false; if ((style & SWT.NO_TRIM) == 0) { hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) != 0; hasResize = (style & SWT.RESIZE) != 0; hasBorder = (style & SWT.BORDER) != 0; } if (hasTitle) { if (hasResize) { display.titleResizeTrimWidth = width; display.titleResizeTrimHeight = height; return; } if (hasBorder) { display.titleBorderTrimWidth = width; display.titleBorderTrimHeight = height; return; } display.titleTrimWidth = width; display.titleTrimHeight = height; return; } if (hasResize) { display.resizeTrimWidth = width; display.resizeTrimHeight = height; return; } if (hasBorder) { display.borderTrimWidth = width; display.borderTrimHeight = height; return; } } public void close () { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); closeWidget (); } void closeWidget () { if (!isEnabled ()) return; Control widget = parent; while (widget != null && !(widget.getShell ().isModal ())) { widget = widget.parent; } if (widget == null) { Shell [] shells = getShells (); for (int i=0; i * @return the dialog shells * * @exception SWTError(ERROR_ERROR_INVALID_PARENT) * when the parent is invalid * @exception SWTError(ERROR_THREAD_INVALID_ACCESS) * when called from the wrong thread */ public Shell [] getShells () { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); int count = 0; Shell [] shells = display.getShells (); for (int i=0; i * * @param listener the listener * * @exception SWTError(ERROR_THREAD_INVALID_ACCESS) * when called from the wrong thread * @exception SWTError(ERROR_WIDGET_DISPOSED) * when the widget has been disposed * @exception SWTError(ERROR_NULL_ARGUMENT) * when listener is null */ public void removeShellListener(ShellListener listener) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); if (eventTable == null) return; eventTable.unhook(SWT.Activate, listener); eventTable.unhook(SWT.Close, listener); eventTable.unhook(SWT.Deactivate, listener); eventTable.unhook(SWT.Iconify,listener); eventTable.unhook(SWT.Deiconify,listener); } void saveBounds () { if (!reparented) return; short [] root_x = new short [1], root_y = new short [1]; OS.XtTranslateCoords (scrolledHandle, (short) 0, (short) 0, root_x, root_y); int [] argList = {OS.XmNwidth, 0, OS.XmNheight, 0}; OS.XtGetValues (scrolledHandle, argList, argList.length / 2); int trimWidth = trimWidth (), trimHeight = trimHeight (); oldX = root_x [0] - trimWidth; oldY = root_y [0] - trimHeight; oldWidth = argList [1]; oldHeight = argList [3]; } public void setBounds (int x, int y, int width, int height) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); /* * Feature in Motif. Motif will not allow a window * to have a zero width or zero height. The fix is * to ensure these values are never zero. */ saveBounds (); int newWidth = Math.max (width - trimWidth (), 1); int newHeight = Math.max (height - trimHeight (), 1); if (!reparented) { super.setBounds (x, y, newWidth, newHeight); return; } boolean isFocus = caret != null && caret.isFocusCaret (); if (isFocus) caret.killFocus (); OS.XtConfigureWidget (shellHandle, x, y, newWidth, newHeight, 0); if (isFocus) caret.setFocus (); } public void setImeInputMode (int mode) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); } public void setLocation (int x, int y) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); saveBounds (); if (!reparented) { super.setLocation(x, y); return; } boolean isFocus = caret != null && caret.isFocusCaret (); if (isFocus) caret.killFocus (); OS.XtMoveWidget (shellHandle, x, y); if (isFocus) caret.setFocus (); } public void setMinimized (boolean minimized) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); /* * Bug in MOTIF. For some reason, the receiver does not keep the * value of the XmNiconic resource up to date when the user minimizes * and restores the window. As a result, a window that is minimized * by the user and then restored by the programmer is not restored. * This happens because the XmNiconic resource is unchanged when the * window is minimized by the user and subsequent attempts to set the * resource fail because the new value of the resource is the same as * the old value. The fix is to force XmNiconic to be up to date * before setting the desired value. */ int [] argList = {OS.XmNiconic, 0}; OS.XtGetValues (shellHandle, argList, argList.length / 2); if ((argList [1] != 0) != this.minimized) { argList [1] = this.minimized ? 1 : 0; OS.XtSetValues (shellHandle, argList, argList.length / 2); } /* Minimize or restore the shell */ argList [1] = (this.minimized = minimized) ? 1 : 0; OS.XtSetValues (shellHandle, argList, argList.length / 2); /* Force the XWindowAttributes to be up to date */ int xDisplay = OS.XtDisplay (handle); if (xDisplay != 0) OS.XSync (xDisplay, false); } public void setSize (int width, int height) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); /* * Feature in Motif. Motif will not allow a window * to have a zero width or zero height. The fix is * to ensure these values are never zero. */ saveBounds (); int newWidth = Math.max (width - trimWidth (), 1); int newHeight = Math.max (height - trimHeight (), 1); if (!reparented) { super.setSize(newWidth, newHeight); return; } boolean isFocus = caret != null && caret.isFocusCaret (); if (isFocus) caret.killFocus (); OS.XtResizeWidget (shellHandle, newWidth, newHeight, 0); if (isFocus) caret.setFocus (); } 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); /* * Feature in Motif. It is not possible to set a shell * title to an empty string. The fix is to set the title * to be a single space. */ if (string.length () == 0) string = " "; byte [] buffer1 = Converter.wcsToMbcs (null, string, true); int length = buffer1.length - 1; /* * Bug in Motif. For some reason, if the title string * length is not a multiple of 4, Motif occasionally * draws garbage after the last character in the title. * The fix is to pad the title. */ byte [] buffer2 = buffer1; if ((length % 4) != 0) { buffer2 = new byte [(length + 3) / 4 * 4]; System.arraycopy (buffer1, 0, buffer2, 0, length); } /* Set the title for the shell */ int ptr = OS.XtMalloc (buffer2.length + 1); OS.memmove (ptr, buffer2, buffer2.length); int [] argList = {OS.XmNtitle, ptr}; OS.XtSetValues (shellHandle, argList, argList.length / 2); OS.XtFree (ptr); } public void setVisible (boolean visible) { if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); realizeWidget (); /* Show the shell */ if (visible) { /* Map the widget */ OS.XtSetMappedWhenManaged (shellHandle, true); if (OS.XtIsTopLevelShell (shellHandle)) { OS.XtMapWidget (shellHandle); } else { OS.XtPopup (shellHandle, OS.XtGrabNone); } /* * Force the shell to be fully exposed before returning. * This ensures that the shell coordinates are correct * when queried directly after showing the shell. */ do { display.update (); } while (!isVisible ()); adjustTrim (); /* Set the saved focus widget */ if (savedFocus != null && !savedFocus.isDisposed ()) { savedFocus.setFocus (); } savedFocus = null; sendEvent (SWT.Show); return; } /* Hide the shell */ OS.XtSetMappedWhenManaged (shellHandle, false); if (OS.XtIsTopLevelShell (shellHandle)) { OS.XtUnmapWidget (shellHandle); } else { OS.XtPopdown (shellHandle); } /* If the shell is iconified, hide the icon */ int xDisplay = OS.XtDisplay (shellHandle); if (xDisplay == 0) return; int xWindow = OS.XtWindow (shellHandle); if (xWindow == 0) return; OS.XWithdrawWindow (xDisplay, xWindow, OS.XDefaultScreen (xDisplay)); sendEvent (SWT.Hide); } int topHandle () { return shellHandle; } int trimHeight () { if ((style & SWT.NO_TRIM) != 0) return 0; boolean hasTitle = false, hasResize = false, hasBorder = false; hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) != 0; hasResize = (style & SWT.RESIZE) != 0; hasBorder = (style & SWT.BORDER) != 0; if (hasTitle) { if (hasResize) return display.titleResizeTrimHeight; if (hasBorder) return display.titleBorderTrimHeight; return display.titleTrimHeight; } if (hasResize) return display.resizeTrimHeight; if (hasBorder) return display.borderTrimHeight; return 0; } int trimWidth () { if ((style & SWT.NO_TRIM) != 0) return 0; boolean hasTitle = false, hasResize = false, hasBorder = false; hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) != 0; hasResize = (style & SWT.RESIZE) != 0; hasBorder = (style & SWT.BORDER) != 0; if (hasTitle) { if (hasResize) return display.titleResizeTrimWidth; if (hasBorder) return display.titleBorderTrimWidth; return display.titleTrimWidth; } if (hasResize) return display.resizeTrimWidth; if (hasBorder) return display.borderTrimWidth; return 0; } }