/******************************************************************************* * Copyright (c) 2000, 2016 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.widgets; import org.eclipse.swt.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.win32.*; /** * 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:

* *

* The modality of an instance may be specified using * style bits. The modality style bits are used to determine * whether input is blocked for other shells on the display. * The PRIMARY_MODAL style allows an instance to block * input to its parent. The APPLICATION_MODAL style * allows an instance to block input to every other shell in the * display. The SYSTEM_MODAL style allows an instance * to block input to all shells, including shells belonging to * different applications. *

* Note: The styles supported by this class are 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. * A modality style may also be "downgraded" to a less * restrictive style. For example, most operating systems * no longer support SYSTEM_MODAL because * it can freeze up the desktop, so this is typically * downgraded to APPLICATION_MODAL.

*
*
Styles:
*
BORDER, CLOSE, MIN, MAX, NO_MOVE, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL, SHEET
*
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 * @see Shell snippets * @see SWT Example: ControlExample * @see Sample code and further information * @noextend This class is not intended to be subclassed by clients. */ public class Shell extends Decorations { Menu activeMenu; ToolTip [] toolTips; long hIMC, hwndMDIClient, lpstrTip, toolTipHandle, balloonTipHandle, menuItemToolTipHandle; int minWidth = SWT.DEFAULT, minHeight = SWT.DEFAULT; long [] brushes; boolean showWithParent, fullScreen, wasMaximized, modified, center; String toolTitle, balloonTitle; long toolIcon, balloonIcon; long windowProc; Control lastActive; static /*final*/ long ToolTipProc; static final long DialogProc; static final TCHAR DialogClass = new TCHAR (0, "#32770", true); final static int [] SYSTEM_COLORS = { OS.COLOR_BTNFACE, OS.COLOR_WINDOW, OS.COLOR_BTNTEXT, OS.COLOR_WINDOWTEXT, OS.COLOR_HIGHLIGHT, OS.COLOR_SCROLLBAR, }; final static int BRUSHES_SIZE = 32; static { WNDCLASS lpWndClass = new WNDCLASS (); OS.GetClassInfo (0, DialogClass, lpWndClass); DialogProc = lpWndClass.lpfnWndProc; } /** * 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 * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. *

* * @param style the style of control to construct * * @exception SWTException * * @see SWT#BORDER * @see SWT#CLOSE * @see SWT#MIN * @see SWT#MAX * @see SWT#RESIZE * @see SWT#TITLE * @see SWT#TOOL * @see SWT#NO_TRIM * @see SWT#NO_MOVE * @see SWT#SHELL_TRIM * @see SWT#DIALOG_TRIM * @see SWT#ON_TOP * @see SWT#MODELESS * @see SWT#PRIMARY_MODAL * @see SWT#APPLICATION_MODAL * @see SWT#SYSTEM_MODAL * @see SWT#SHEET */ 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 * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. *

* 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 * * @see SWT#BORDER * @see SWT#CLOSE * @see SWT#MIN * @see SWT#MAX * @see SWT#RESIZE * @see SWT#TITLE * @see SWT#TOOL * @see SWT#NO_TRIM * @see SWT#NO_MOVE * @see SWT#SHELL_TRIM * @see SWT#DIALOG_TRIM * @see SWT#ON_TOP * @see SWT#MODELESS * @see SWT#PRIMARY_MODAL * @see SWT#APPLICATION_MODAL * @see SWT#SYSTEM_MODAL * @see SWT#SHEET */ public Shell (Display display, int style) { this (display, null, style, 0, false); } Shell (Display display, Shell parent, int style, long handle, boolean embedded) { super (); checkSubclass (); if (display == null) display = Display.getCurrent (); if (display == null) display = Display.getDefault (); if (!display.isValidThread ()) { error (SWT.ERROR_THREAD_INVALID_ACCESS); } if (parent != null && parent.isDisposed ()) { error (SWT.ERROR_INVALID_ARGUMENT); } this.center = parent != null && (style & SWT.SHEET) != 0; this.style = checkStyle (parent, style); this.parent = parent; this.display = display; this.handle = handle; if (handle != 0 && !embedded) { state |= FOREIGN_HANDLE; } reskinWidget(); createWidget (); } /** * 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.DIALOG_TRIM); } /** * 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 * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. *

* 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 IllegalArgumentException * @exception SWTException * * @see SWT#BORDER * @see SWT#CLOSE * @see SWT#MIN * @see SWT#MAX * @see SWT#RESIZE * @see SWT#TITLE * @see SWT#NO_TRIM * @see SWT#NO_MOVE * @see SWT#SHELL_TRIM * @see SWT#DIALOG_TRIM * @see SWT#ON_TOP * @see SWT#TOOL * @see SWT#MODELESS * @see SWT#PRIMARY_MODAL * @see SWT#APPLICATION_MODAL * @see SWT#SYSTEM_MODAL * @see SWT#SHEET */ public Shell (Shell parent, int style) { this (parent != null ? parent.display : null, parent, style, 0, false); } /** * Invokes platform specific functionality to allocate a new shell * that is embedded. *

* IMPORTANT: This method is not part of the public * API for Shell. It is marked public only so that it * can be shared within the packages provided by SWT. It is not * available on all platforms, and should never be called from * application code. *

* * @param display the display for the shell * @param handle the handle for the shell * @return a new shell object containing the specified display and handle * * @noreference This method is not intended to be referenced by clients. */ public static Shell win32_new (Display display, long handle) { return new Shell (display, null, SWT.NO_TRIM, handle, true); } /** * Invokes platform specific functionality to allocate a new shell * that is not embedded. *

* IMPORTANT: This method is not part of the public * API for Shell. It is marked public only so that it * can be shared within the packages provided by SWT. It is not * available on all platforms, and should never be called from * application code. *

* * @param display the display for the shell * @param handle the handle for the shell * @return a new shell object containing the specified display and handle * * @noreference This method is not intended to be referenced by clients. * * @since 3.3 */ public static Shell internal_new (Display display, long handle) { return new Shell (display, null, SWT.NO_TRIM, handle, false); } static int checkStyle (Shell parent, int style) { style = Decorations.checkStyle (style); style &= ~SWT.TRANSPARENT; int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL; if ((style & SWT.SHEET) != 0) { style &= ~SWT.SHEET; style |= parent == null ? SWT.SHELL_TRIM : SWT.DIALOG_TRIM; if ((style & mask) == 0) { style |= parent == null ? 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; } /** * 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); } long balloonTipHandle () { if (balloonTipHandle == 0) createBalloonTipHandle (); return balloonTipHandle; } @Override long callWindowProc (long hwnd, int msg, long wParam, long lParam) { if (handle == 0) return 0; if (hwnd == toolTipHandle || hwnd == balloonTipHandle || hwnd == menuItemToolTipHandle) { return OS.CallWindowProc (ToolTipProc, hwnd, msg, wParam, lParam); } if (hwndMDIClient != 0) { return OS.DefFrameProc (hwnd, hwndMDIClient, msg, wParam, lParam); } if (windowProc != 0) { return OS.CallWindowProc (windowProc, hwnd, msg, wParam, lParam); } if ((style & SWT.TOOL) != 0) { int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.BORDER | SWT.RESIZE; if ((style & trim) == 0) return OS.DefWindowProc (hwnd, msg, wParam, lParam); } if ((style & SWT.NO_MOVE) != 0) { setItemEnabled (OS.SC_MOVE, false); } if (parent != null) { switch (msg) { case OS.WM_KILLFOCUS: case OS.WM_SETFOCUS: return OS.DefWindowProc (hwnd, msg, wParam, lParam); } return OS.CallWindowProc (DialogProc, hwnd, msg, wParam, lParam); } return OS.DefWindowProc (hwnd, msg, wParam, lParam); } void center () { if (parent == null) return; Rectangle rect = getBoundsInPixels (); Rectangle parentRect = display.mapInPixels (parent, null, parent.getClientAreaInPixels()); int x = Math.max (parentRect.x, parentRect.x + (parentRect.width - rect.width) / 2); int y = Math.max (parentRect.y, parentRect.y + (parentRect.height - rect.height) / 2); Rectangle monitorRect = parent.getMonitor ().getClientArea(); if (x + rect.width > monitorRect.x + monitorRect.width) { x = Math.max (monitorRect.x, monitorRect.x + monitorRect.width - rect.width); } else { x = Math.max (x, monitorRect.x); } if (y + rect.height > monitorRect.y + monitorRect.height) { y = Math.max (monitorRect.y, monitorRect.y + monitorRect.height - rect.height); } else { y = Math.max (y, monitorRect.y); } setLocationInPixels (x, y); } /** * 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 * * @see SWT#Close * @see #dispose */ public void close () { checkWidget (); closeWidget (); } void createBalloonTipHandle () { balloonTipHandle = OS.CreateWindowEx ( 0, new TCHAR (0, OS.TOOLTIPS_CLASS, true), null, OS.TTS_ALWAYSTIP | OS.TTS_NOPREFIX | OS.TTS_BALLOON, OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0, handle, 0, OS.GetModuleHandle (null), null); if (balloonTipHandle == 0) error (SWT.ERROR_NO_HANDLES); if (ToolTipProc == 0) { ToolTipProc = OS.GetWindowLongPtr (balloonTipHandle, OS.GWLP_WNDPROC); } /* * Feature in Windows. Despite the fact that the * tool tip text contains \r\n, the tooltip will * not honour the new line unless TTM_SETMAXTIPWIDTH * is set. The fix is to set TTM_SETMAXTIPWIDTH to * a large value. */ OS.SendMessage (balloonTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF); display.addControl (balloonTipHandle, this); OS.SetWindowLongPtr (balloonTipHandle, OS.GWLP_WNDPROC, display.windowProc); } @Override void createHandle () { boolean embedded = handle != 0 && (state & FOREIGN_HANDLE) == 0; /* * On Windows 98 and NT, setting a window to be the * top most window using HWND_TOPMOST can result in a * parent dialog shell being moved behind its parent * if the dialog has a sibling that is currently on top * This only occurs using SetWindowPos (), not when the * handle is created. */ /* * The following code is intentionally commented. */ // if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = true; if (handle == 0 || embedded) { super.createHandle (); } else { state |= CANVAS; if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) { state |= THEME_BACKGROUND; } windowProc = OS.GetWindowLongPtr (handle, OS.GWL_WNDPROC); } /* * The following code is intentionally commented. */ // if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = false; if (!embedded) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); bits &= ~(OS.WS_OVERLAPPED | OS.WS_CAPTION); bits |= OS.WS_POPUP; if ((style & SWT.TITLE) != 0) bits |= OS.WS_CAPTION; if ((style & SWT.NO_TRIM) == 0) { if ((style & (SWT.BORDER | SWT.RESIZE)) == 0) bits |= OS.WS_BORDER; } /* * Bug in Windows. When the WS_CAPTION bits are cleared using * SetWindowLong(), Windows does not resize the client area of * the window to get rid of the caption until the first resize. * The fix is to use SetWindowPos() with SWP_DRAWFRAME to force * the frame to be redrawn and resized. */ OS.SetWindowLong (handle, OS.GWL_STYLE, bits); int flags = OS.SWP_DRAWFRAME | OS.SWP_NOMOVE | OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE; OS.SetWindowPos (handle, 0, 0, 0, 0, 0, flags); } if (OS.IsDBLocale) { hIMC = OS.ImmCreateContext (); if (hIMC != 0) OS.ImmAssociateContext (handle, hIMC); } } void createMenuItemToolTipHandle() { menuItemToolTipHandle = createToolTipHandle (0); } void createToolTip (ToolTip toolTip) { int id = 0; if (toolTips == null) toolTips = new ToolTip [4]; while (id < toolTips.length && toolTips [id] != null) id++; if (id == toolTips.length) { ToolTip [] newToolTips = new ToolTip [toolTips.length + 4]; System.arraycopy (toolTips, 0, newToolTips, 0, toolTips.length); toolTips = newToolTips; } toolTips [id] = toolTip; toolTip.id = id + Display.ID_START; TOOLINFO lpti = new TOOLINFO (); lpti.cbSize = TOOLINFO.sizeof; lpti.hwnd = handle; lpti.uId = toolTip.id; lpti.uFlags = OS.TTF_TRACK; lpti.lpszText = OS.LPSTR_TEXTCALLBACK; OS.SendMessage (toolTip.hwndToolTip (), OS.TTM_ADDTOOL, 0, lpti); } void createToolTipHandle () { toolTipHandle = createToolTipHandle (handle); } long createToolTipHandle (long parent) { long toolTipHandle = OS.CreateWindowEx ( 0, new TCHAR (0, OS.TOOLTIPS_CLASS, true), null, OS.TTS_ALWAYSTIP | OS.TTS_NOPREFIX, OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0, parent, 0, OS.GetModuleHandle (null), null); if (toolTipHandle == 0) error (SWT.ERROR_NO_HANDLES); if (ToolTipProc == 0) { ToolTipProc = OS.GetWindowLongPtr (toolTipHandle, OS.GWLP_WNDPROC); } /* * Feature in Windows. Despite the fact that the * tool tip text contains \r\n, the tooltip will * not honour the new line unless TTM_SETMAXTIPWIDTH * is set. The fix is to set TTM_SETMAXTIPWIDTH to * a large value. */ OS.SendMessage (toolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF); display.addControl (toolTipHandle, this); OS.SetWindowLongPtr (toolTipHandle, OS.GWLP_WNDPROC, display.windowProc); return toolTipHandle; } @Override void deregister () { super.deregister (); if (toolTipHandle != 0) display.removeControl (toolTipHandle); if (balloonTipHandle != 0) display.removeControl (balloonTipHandle); if (menuItemToolTipHandle != 0) display.removeControl (menuItemToolTipHandle); } void destroyToolTip (ToolTip toolTip) { if (toolTips == null) return; toolTips [toolTip.id - Display.ID_START] = null; if (balloonTipHandle != 0) { TOOLINFO lpti = new TOOLINFO (); lpti.cbSize = TOOLINFO.sizeof; lpti.uId = toolTip.id; lpti.hwnd = handle; OS.SendMessage (balloonTipHandle, OS.TTM_DELTOOL, 0, lpti); } toolTip.id = -1; } @Override void destroyWidget () { fixActiveShell (); super.destroyWidget (); /* * Destroy context only after the controls that used it were destroyed. * Technically, that shouldn't be necessary, because 'Control.releaseWidget' * clears up association by calling 'OS.ImmAssociateContext (handle, 0)'. * However, there's a bug in Windows 10 (see bug 526758), and this is the workaround. */ if (OS.IsDBLocale) { if (hIMC != 0) OS.ImmDestroyContext (hIMC); } } @Override public void dispose () { /* * This code is intentionally commented. On some * platforms, the owner window is repainted right * away when a dialog window exits. This behavior * is currently unspecified. */ // /* // * Note: It is valid to attempt to dispose a widget // * more than once. If this happens, fail silently. // */ // if (!isValidWidget ()) return; // if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); // Display oldDisplay = display; super.dispose (); // widget is disposed at this point // if (oldDisplay != null) oldDisplay.update (); } @Override void enableWidget (boolean enabled) { if (enabled) { state &= ~DISABLED; } else { state |= DISABLED; } if (Display.TrimEnabled) { if (isActive ()) setItemEnabled (OS.SC_CLOSE, enabled); } else { OS.EnableWindow (handle, enabled); } } @Override long findBrush (long value, int lbStyle) { if (lbStyle == OS.BS_SOLID) { for (int i=0; i