package org.eclipse.swt.widgets; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved | |
*/ | |
import org.eclipse.swt.internal.motif.*; | |
import org.eclipse.swt.*; | |
import org.eclipse.swt.graphics.*; | |
/** | |
* Instances of this class provide the appearance and | |
* behavior of <code>Shells</code>, but are not top | |
* level shells or dialogs. Class <code>Shell</code> | |
* shares a significant amount of code with this class, | |
* and is a subclass. | |
* <p> | |
* Instances are always displayed in one of the maximized, | |
* minimized or normal states: | |
* <ul> | |
* <li> | |
* When an instance is marked as <em>maximized</em>, the | |
* window manager will typically resize it to fill the | |
* entire visible area of the display, and the instance | |
* is usually put in a state where it can not be resized | |
* (even if it has style <code>RESIZE</code>) until it is | |
* no longer maximized. | |
* </li><li> | |
* When an instance is in the <em>normal</em> state (neither | |
* maximized or minimized), its appearance is controlled by | |
* the style constants which were specified when it was created | |
* and the restrictions of the window manager (see below). | |
* </li><li> | |
* When an instance has been marked as <em>minimized</em>, | |
* its contents (client area) will usually not be visible, | |
* and depending on the window manager, it may be | |
* "iconified" (that is, replaced on the desktop by a small | |
* simplified representation of itself), relocated to a | |
* distinguished area of the screen, or hidden. Combinations | |
* of these changes are also possible. | |
* </li> | |
* </ul> | |
* </p> | |
* Note: The styles supported by this class must be treated | |
* as <em>HINT</em>s, since the window manager for the | |
* desktop on which the instance is visible has ultimate | |
* control over the appearance and behavior of decorations. | |
* For example, some window managers only support resizable | |
* windows and will always assume the RESIZE style, even if | |
* it is not set. | |
* <dl> | |
* <dt><b>Styles:</b></dt> | |
* <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE</dd> | |
* <dt><b>Events:</b></dt> | |
* <dd>(none)</dd> | |
* </dl> | |
* Class <code>SWT</code> provides two "convenience constants" | |
* for the most commonly required style combinations: | |
* <dl> | |
* <dt><code>SHELL_TRIM</code></dt> | |
* <dd> | |
* the result of combining the constants which are required | |
* to produce a typical application top level shell: (that | |
* is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>) | |
* </dd> | |
* <dt><code>DIALOG_TRIM</code></dt> | |
* <dd> | |
* the result of combining the constants which are required | |
* to produce a typical application dialog shell: (that | |
* is, <code>TITLE | CLOSE | BORDER</code>) | |
* </dd> | |
* </dl> | |
* <p> | |
* IMPORTANT: This class is intended to be subclassed <em>only</em> | |
* within the SWT implementation. | |
* </p> | |
* | |
* @see #getMinimized | |
* @see #getMaximized | |
* @see Shell | |
* @see SWT | |
*/ | |
public class Decorations extends Canvas { | |
String label; | |
Image image; | |
int dialogHandle; | |
boolean minimized, maximized; | |
Menu menuBar; | |
Menu [] menus; | |
Control savedFocus; | |
Button defaultButton, saveDefault; | |
Decorations () { | |
/* Do nothing */ | |
} | |
/** | |
* Constructs a new instance of this class given its parent | |
* and a style value describing its behavior and appearance. | |
* <p> | |
* The style value is either one of the style constants defined in | |
* class <code>SWT</code> which is applicable to instances of this | |
* class, or must be built by <em>bitwise OR</em>'ing together | |
* (that is, using the <code>int</code> "|" operator) two or more | |
* of those <code>SWT</code> 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. | |
* </p> | |
* | |
* @param parent a composite control which will be the parent of the new instance (cannot be null) | |
* @param style the style of control to construct | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
* </ul> | |
* | |
* @see SWT | |
* @see Widget#checkSubclass | |
* @see Widget#getStyle | |
*/ | |
public Decorations (Composite parent, int style) { | |
super (parent, checkStyle (style)); | |
} | |
void add (Menu menu) { | |
if (menus == null) menus = new Menu [4]; | |
for (int i=0; i<menus.length; i++) { | |
if (menus [i] == null) { | |
menus [i] = menu; | |
return; | |
} | |
} | |
Menu [] newMenus = new Menu [menus.length + 4]; | |
newMenus [menus.length] = menu; | |
System.arraycopy (menus, 0, newMenus, 0, menus.length); | |
menus = newMenus; | |
} | |
void bringToTop () { | |
/* | |
* Feature in X. Calling XSetInputFocus() when the | |
* widget is not viewable causes an X bad match error. | |
* The fix is to call XSetInputFocus() when the widget | |
* is viewable. | |
*/ | |
if (minimized) return; | |
if (!isVisible ()) return; | |
int display = OS.XtDisplay (handle); | |
if (display == 0) return; | |
int window = OS.XtWindow (handle); | |
if (window == 0) return; | |
OS.XSetInputFocus (display, window, OS.RevertToParent, OS.CurrentTime); | |
} | |
static int checkStyle (int style) { | |
if ((style & (SWT.MENU | SWT.MIN | SWT.MAX | SWT.CLOSE)) != 0) { | |
style |= SWT.TITLE; | |
} | |
return style; | |
} | |
protected void checkSubclass () { | |
if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); | |
} | |
Control computeTabGroup () { | |
return this; | |
} | |
Control computeTabRoot () { | |
return this; | |
} | |
public Rectangle computeTrim (int x, int y, int width, int height) { | |
checkWidget(); | |
Rectangle trim = super.computeTrim (x, y, width, height); | |
if (menuBar != null) { | |
XtWidgetGeometry request = new XtWidgetGeometry (); | |
XtWidgetGeometry result = new XtWidgetGeometry (); | |
request.request_mode = OS.CWWidth; | |
request.width = trim.width; | |
OS.XtQueryGeometry (menuBar.handle, request, result); | |
trim.height += result.height; | |
} | |
return trim; | |
} | |
void createHandle (int index) { | |
state |= HANDLE | CANVAS; | |
createScrolledHandle (parent.handle); | |
} | |
void createWidget (int index) { | |
super.createWidget (index); | |
label = ""; | |
} | |
int dialogHandle () { | |
if (dialogHandle != 0) return dialogHandle; | |
return dialogHandle = OS.XmCreateDialogShell (handle, null, null, 0); | |
} | |
/** | |
* Returns the receiver's default button if one had | |
* previously been set, otherwise returns null. | |
* | |
* @return the default button or null | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
* | |
* @see #setDefaultButton | |
*/ | |
public Button getDefaultButton () { | |
checkWidget(); | |
return defaultButton; | |
} | |
/** | |
* Returns the receiver's image if it had previously been | |
* set using <code>setImage()</code>. The image is typically | |
* displayed by the window manager when the instance is | |
* marked as iconified, and may also be displayed somewhere | |
* in the trim when the instance is in normal or maximized | |
* states. | |
* <p> | |
* Note: This method will return null if called before | |
* <code>setImage()</code> is called. It does not provide | |
* access to a window manager provided, "default" image | |
* even if one exists. | |
* </p> | |
* | |
* @return the image | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public Image getImage () { | |
checkWidget(); | |
return image; | |
} | |
/** | |
* Returns <code>true</code> if the receiver is currently | |
* maximized, and false otherwise. | |
* <p> | |
* | |
* @return the maximized state | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
* | |
* @see #setMaximized | |
*/ | |
public boolean getMaximized () { | |
checkWidget(); | |
return maximized; | |
} | |
/** | |
* Returns the receiver's menu bar if one had previously | |
* been set, otherwise returns null. | |
* | |
* @return the menu bar or null | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public Menu getMenuBar () { | |
checkWidget(); | |
return menuBar; | |
} | |
/** | |
* Returns <code>true</code> if the receiver is currently | |
* minimized, and false otherwise. | |
* <p> | |
* | |
* @return the minimized state | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
* | |
* @see #setMinimized | |
*/ | |
public boolean getMinimized () { | |
checkWidget(); | |
return minimized; | |
} | |
String getNameText () { | |
return getText (); | |
} | |
/** | |
* Returns the receiver's text, which is the string that the | |
* window manager will typically display as the receiver's | |
* <em>title</em>. If the text has not previously been set, | |
* returns an empty string. | |
* | |
* @return the text | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public String getText () { | |
checkWidget(); | |
return label; | |
} | |
Decorations menuShell () { | |
return this; | |
} | |
void propagateWidget (boolean enabled) { | |
super.propagateWidget (enabled); | |
int [] argList = {OS.XmNmenuBar, 0}; | |
OS.XtGetValues (scrolledHandle, argList, argList.length / 2); | |
if (argList [1] != 0) propagateHandle (enabled, argList [1]); | |
} | |
void releaseHandle () { | |
super.releaseHandle (); | |
dialogHandle = 0; | |
} | |
void releaseWidget () { | |
if (menus != null) { | |
for (int i=0; i<menus.length; i++) { | |
Menu menu = menus [i]; | |
if (menu != null && !menu.isDisposed ()) { | |
menu.releaseWidget (); | |
menu.releaseHandle (); | |
} | |
} | |
} | |
menuBar = null; | |
menus = null; | |
super.releaseWidget (); | |
defaultButton = saveDefault = null; | |
label = null; | |
} | |
void remove (Menu menu) { | |
if (menus == null) return; | |
for (int i=0; i<menus.length; i++) { | |
if (menus [i] == menu) { | |
menus [i] = null; | |
return; | |
} | |
} | |
} | |
/** | |
* If the argument is not null, sets the receiver's default | |
* button to the argument, and if the argument is null, sets | |
* the receiver's default button to the first button which | |
* was set as the receiver's default button (called the | |
* <em>saved default button</em>). If no default button had | |
* previously been set, or the saved default button was | |
* disposed, the receiver's default button will be set to | |
* null. | |
* | |
* @param the new default button | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_INVALID_ARGUMENT - if the button has been disposed</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setDefaultButton (Button button) { | |
checkWidget(); | |
setDefaultButton (button, true); | |
} | |
void setDefaultButton (Button button, boolean save) { | |
if (button == null) { | |
if (defaultButton == saveDefault) return; | |
} else { | |
if (button.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); | |
if ((button.style & SWT.PUSH) == 0) return; | |
if (button == defaultButton) return; | |
} | |
if (defaultButton != null) { | |
if (!defaultButton.isDisposed ()) defaultButton.setDefault (false); | |
} | |
if ((defaultButton = button) == null) defaultButton = saveDefault; | |
if (defaultButton != null) { | |
if (!defaultButton.isDisposed ()) defaultButton.setDefault (true); | |
} | |
if (save || saveDefault == null) saveDefault = defaultButton; | |
if (saveDefault != null && saveDefault.isDisposed ()) saveDefault = null; | |
} | |
/** | |
* Sets the receiver's image to the argument, which may | |
* be null. The image is typically displayed by the window | |
* manager when the instance is marked as iconified, and | |
* may also be displayed somewhere in the trim when the | |
* instance is in normal or maximized states. | |
* | |
* @param image the new image (or null) | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setImage (Image image) { | |
checkWidget(); | |
int pixmap = 0, mask = 0; | |
if (image != null) { | |
if (image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); | |
switch (image.type) { | |
case SWT.BITMAP: | |
pixmap = image.pixmap; | |
break; | |
case SWT.ICON: | |
pixmap = image.pixmap; | |
mask = image.mask; | |
break; | |
default: | |
error (SWT.ERROR_INVALID_IMAGE); | |
} | |
} | |
this.image = image; | |
int [] argList = { | |
OS.XmNiconPixmap, pixmap, | |
OS.XmNiconMask, mask, | |
}; | |
int topHandle = topHandle (); | |
OS.XtSetValues (topHandle, argList, argList.length / 2); | |
} | |
/** | |
* Sets the maximized state of the receiver. | |
* If the argument is <code>true</code> causes the receiver | |
* to switch to the maximized state, and if the argument is | |
* <code>false</code> and the receiver was previously maximized, | |
* causes the receiver to switch back to either the minimized | |
* or normal states. | |
* <p> | |
* Note: The result of intermixing calls to<code>setMaximized(true)</code> | |
* and <code>setMinimized(true)</code> will vary by platform. Typically, | |
* the behavior will match the platform user's expectations, but not | |
* always. This should be avoided if possible. | |
* </p> | |
* | |
* @param the new maximized state | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
* | |
* @see #setMinimized | |
*/ | |
public void setMaximized (boolean maximized) { | |
checkWidget(); | |
this.maximized = maximized; | |
} | |
/** | |
* Sets the receiver's menu bar to the argument, which | |
* may be null. | |
* | |
* @param menu the new menu bar | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li> | |
* <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setMenuBar (Menu menu) { | |
checkWidget(); | |
if (menuBar == menu) return; | |
if (menu != null) { | |
if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); | |
if ((menu.style & SWT.BAR) == 0) error (SWT.ERROR_MENU_NOT_BAR); | |
if (menu.parent != this) error (SWT.ERROR_INVALID_PARENT); | |
} | |
/* Ensure the new menu bar is correctly enabled */ | |
if (menuBar != null) { | |
if (!isEnabled () && menuBar.getEnabled ()) { | |
propagateHandle (true, menuBar.handle); | |
} | |
} | |
if (menu != null) { | |
if (!isEnabled ()) { | |
propagateHandle (false, menu.handle); | |
} | |
} | |
/* | |
* Bug in Motif. When a XmMainWindowSetAreas () is used | |
* to replace an existing menu, both menus must be managed | |
* before the call to XmMainWindowSetAreas () or the new | |
* menu will not be layed out properly. | |
*/ | |
int newHandle = (menu != null) ? menu.handle : 0; | |
int oldHandle = (menuBar != null) ? menuBar.handle : 0; | |
menuBar = menu; | |
int hHandle = (horizontalBar != null) ? horizontalBar.handle : 0; | |
int vHandle = (verticalBar != null) ? verticalBar.handle : 0; | |
if (newHandle != 0) { | |
OS.XtSetMappedWhenManaged (newHandle, false); | |
OS.XtManageChild (newHandle); | |
} | |
int clientHandle = (formHandle != 0) ? formHandle : handle; | |
OS.XmMainWindowSetAreas (scrolledHandle, newHandle, 0, hHandle, vHandle, clientHandle); | |
if (oldHandle != 0) OS.XtUnmanageChild (oldHandle); | |
if (newHandle != 0) { | |
OS.XtSetMappedWhenManaged (newHandle, true); | |
} | |
/* | |
* Bug in Motif. When a menu bar is removed after the | |
* main window has been realized, the main window does | |
* not layout the new menu bar or the work window. | |
* The fix is to force a layout by temporarily resizing | |
* the main window. | |
*/ | |
if (newHandle == 0 && OS.XtIsRealized (scrolledHandle)) { | |
int [] argList = {OS.XmNwidth, 0, OS.XmNheight, 0, OS.XmNborderWidth, 0}; | |
OS.XtGetValues (scrolledHandle, argList, argList.length / 2); | |
OS.XtResizeWidget (scrolledHandle, argList [1] + 1, argList [3], argList [5]); | |
OS.XtResizeWidget (scrolledHandle, argList [1], argList [3], argList [5]); | |
} | |
} | |
/** | |
* Sets the minimized stated of the receiver. | |
* If the argument is <code>true</code> causes the receiver | |
* to switch to the minimized state, and if the argument is | |
* <code>false</code> and the receiver was previously minimized, | |
* causes the receiver to switch back to either the maximized | |
* or normal states. | |
* <p> | |
* Note: The result of intermixing calls to<code>setMaximized(true)</code> | |
* and <code>setMinimized(true)</code> will vary by platform. Typically, | |
* the behavior will match the platform user's expectations, but not | |
* always. This should be avoided if possible. | |
* </p> | |
* | |
* @param the new maximized state | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
* | |
* @see #setMaximized | |
*/ | |
public void setMinimized (boolean minimized) { | |
checkWidget(); | |
this.minimized = minimized; | |
} | |
void setSavedFocus (Control control) { | |
if (this == control) return; | |
savedFocus = control; | |
} | |
/** | |
* Sets the receiver's text, which is the string that the | |
* window manager will typically display as the receiver's | |
* <em>title</em>, to the argument, which may not be null. | |
* | |
* @param text the new text | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setText (String string) { | |
checkWidget(); | |
if (string == null) error (SWT.ERROR_NULL_ARGUMENT); | |
label = string; | |
} | |
public void setVisible (boolean visible) { | |
super.setVisible (visible); | |
if (!visible) return; | |
if (savedFocus != null && !savedFocus.isDisposed ()) { | |
savedFocus.setFocus (); | |
} | |
savedFocus = null; | |
} | |
boolean traverseItem (boolean next) { | |
return false; | |
} | |
} |