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;
}
}