Mercurial > projects > dwt-win
diff dwt/widgets/Shell.d @ 31:92c102dd64a3
Added all widgets modules as dummy. Most modules of accessible are equal to the linux version, except Accessible.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 28 Jan 2008 04:47:28 +0100 |
parents | |
children | 39a9959ef14d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/widgets/Shell.d Mon Jan 28 04:47:28 2008 +0100 @@ -0,0 +1,2306 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.widgets.Shell; + +import dwt.widgets.Decorations; +class Shell : Decorations { + void checkWidget (); +} +/++ +import dwt.DWT; +import dwt.DWTException; +import dwt.events.ShellListener; +import dwt.graphics.Cursor; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.graphics.Region; +import dwt.internal.win32.CREATESTRUCT; +import dwt.internal.win32.LOGBRUSH; +import dwt.internal.win32.LRESULT; +import dwt.internal.win32.MINMAXINFO; +import dwt.internal.win32.MSG; +import dwt.internal.win32.NMTTDISPINFO; +import dwt.internal.win32.OS; +import dwt.internal.win32.POINT; +import dwt.internal.win32.RECT; +import dwt.internal.win32.SHACTIVATEINFO; +import dwt.internal.win32.SIPINFO; +import dwt.internal.win32.STARTUPINFO; +import dwt.internal.win32.TCHAR; +import dwt.internal.win32.TOOLINFO; +import dwt.internal.win32.WINDOWPOS; +import dwt.internal.win32.WNDCLASS; + +/** + * 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 + * <code>Display</code> as the argument) are described + * as <em>top level</em> shells. Instances that do have + * a parent are described as <em>secondary</em> or + * <em>dialog</em> shells. + * <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><p> + * The <em>modality</em> 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 <code>PRIMARY_MODAL</code> style allows an instance to block + * input to its parent. The <code>APPLICATION_MODAL</code> style + * allows an instance to block input to every other shell in the + * display. The <code>SYSTEM_MODAL</code> style allows an instance + * to block input to all shells, including shells belonging to + * different applications. + * </p><p> + * Note: The styles supported by this class are 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 + * 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 <code>PRIMARY_MODAL</code> is not supported, + * it would be upgraded to <code>APPLICATION_MODAL</code>. + * A modality style may also be "downgraded" to a less + * restrictive style. For example, most operating systems + * no longer support <code>SYSTEM_MODAL</code> because + * it can freeze up the desktop, so this is typically + * downgraded to <code>APPLICATION_MODAL</code>. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd> + * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd> + * <dt><b>Events:</b></dt> + * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd> + * </dl> + * Class <code>DWT</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> + * <p> + * Note: Only one of the styles APPLICATION_MODAL, MODELESS, + * PRIMARY_MODAL and SYSTEM_MODAL may be specified. + * </p><p> + * IMPORTANT: This class is not intended to be subclassed. + * </p> + * + * @see Decorations + * @see DWT + */ +public class Shell extends Decorations { + Menu activeMenu; + ToolTip [] toolTips; + int hIMC, hwndMDIClient, lpstrTip, toolTipHandle, balloonTipHandle; + int minWidth = DWT.DEFAULT, minHeight = DWT.DEFAULT; + int [] brushes; + bool showWithParent; + String toolTitle, balloonTitle; + int toolIcon, balloonIcon; + int windowProc; + Control lastActive, lockToolTipControl; + SHACTIVATEINFO psai; + Region region; + static /*final*/ int ToolTipProc; + static final int DialogProc; + static final TCHAR DialogClass = new TCHAR (0, OS.IsWinCE ? "Dialog" : "#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 <code>Shell((Display) null)</code>. + * + * @exception DWTException <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> + */ +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 <code>Shell((Display) null, style)</code>. + * <p> + * The style value is either one of the style constants defined in + * class <code>DWT</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>DWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p> + * + * @param style the style of control to construct + * + * @exception DWTException <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 DWT#BORDER + * @see DWT#CLOSE + * @see DWT#MIN + * @see DWT#MAX + * @see DWT#RESIZE + * @see DWT#TITLE + * @see DWT#NO_TRIM + * @see DWT#SHELL_TRIM + * @see DWT#DIALOG_TRIM + * @see DWT#MODELESS + * @see DWT#PRIMARY_MODAL + * @see DWT#APPLICATION_MODAL + * @see DWT#SYSTEM_MODAL + */ +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 <code>DWT.SHELL_TRIM</code>. + * <p> + * 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. <b>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 DWT.</b> + * </p> + * + * @param display the display to create the shell on + * + * @exception DWTException <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> + */ +public Shell (Display display) { + this (display, OS.IsWinCE ? DWT.NONE : DWT.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. + * <p> + * The style value is either one of the style constants defined in + * class <code>DWT</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>DWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p><p> + * 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. <b>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 DWT.</b> + * </p> + * + * @param display the display to create the shell on + * @param style the style of control to construct + * + * @exception DWTException <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 DWT#BORDER + * @see DWT#CLOSE + * @see DWT#MIN + * @see DWT#MAX + * @see DWT#RESIZE + * @see DWT#TITLE + * @see DWT#NO_TRIM + * @see DWT#SHELL_TRIM + * @see DWT#DIALOG_TRIM + * @see DWT#MODELESS + * @see DWT#PRIMARY_MODAL + * @see DWT#APPLICATION_MODAL + * @see DWT#SYSTEM_MODAL + */ +public Shell (Display display, int style) { + this (display, null, style, 0, false); +} + +Shell (Display display, Shell parent, int style, int handle, bool embedded) { + super (); + checkSubclass (); + if (display is null) display = Display.getCurrent (); + if (display is null) display = Display.getDefault (); + if (!display.isValidThread ()) { + error (DWT.ERROR_THREAD_INVALID_ACCESS); + } + if (parent !is null && parent.isDisposed ()) { + error (DWT.ERROR_INVALID_ARGUMENT); + } + this.style = checkStyle (style); + this.parent = parent; + this.display = display; + this.handle = handle; + if (handle !is 0 && !embedded) { + state |= FOREIGN_HANDLE; + } + createWidget (); +} + +/** + * Constructs a new instance of this class given only its + * parent. It is created with style <code>DWT.DIALOG_TRIM</code>. + * <p> + * 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. <b>Passing in null as + * the parent is not considered to be good coding style, + * and may not be supported in a future release of DWT.</b> + * </p> + * + * @param parent a shell which will be the parent of the new instance + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> + * </ul> + * @exception DWTException <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> + */ +public Shell (Shell parent) { + this (parent, OS.IsWinCE ? DWT.NONE : DWT.DIALOG_TRIM); +} + +/** + * 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>DWT</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>DWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p><p> + * 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. <b>Passing in null as + * the parent is not considered to be good coding style, + * and may not be supported in a future release of DWT.</b> + * </p> + * + * @param parent a shell which will be the parent of the new instance + * @param style the style of control to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> + * </ul> + * @exception DWTException <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 DWT#BORDER + * @see DWT#CLOSE + * @see DWT#MIN + * @see DWT#MAX + * @see DWT#RESIZE + * @see DWT#TITLE + * @see DWT#NO_TRIM + * @see DWT#SHELL_TRIM + * @see DWT#DIALOG_TRIM + * @see DWT#ON_TOP + * @see DWT#TOOL + * @see DWT#MODELESS + * @see DWT#PRIMARY_MODAL + * @see DWT#APPLICATION_MODAL + * @see DWT#SYSTEM_MODAL + */ +public Shell (Shell parent, int style) { + this (parent !is null ? parent.display : null, parent, style, 0, false); +} + +/** + * Invokes platform specific functionality to allocate a new shell. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Shell</code>. It is marked public only so that it + * can be shared within the packages provided by DWT. It is not + * available on all platforms, and should never be called from + * application code. + * </p> + * + * @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 + */ +public static Shell win32_new (Display display, int handle) { + return new Shell (display, null, DWT.NO_TRIM, handle, true); +} + +public static Shell internal_new (Display display, int handle) { + return new Shell (display, null, DWT.NO_TRIM, handle, false); +} + +static int checkStyle (int style) { + style = Decorations.checkStyle (style); + int mask = DWT.SYSTEM_MODAL | DWT.APPLICATION_MODAL | DWT.PRIMARY_MODAL; + int bits = style & ~mask; + if ((style & DWT.SYSTEM_MODAL) !is 0) return bits | DWT.SYSTEM_MODAL; + if ((style & DWT.APPLICATION_MODAL) !is 0) return bits | DWT.APPLICATION_MODAL; + if ((style & DWT.PRIMARY_MODAL) !is 0) return bits | DWT.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 + * <code>ShellListener</code> interface. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <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 ShellListener + * @see #removeShellListener + */ +public void addShellListener (ShellListener listener) { + checkWidget (); + if (listener is null) error (DWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (DWT.Close,typedListener); + addListener (DWT.Iconify,typedListener); + addListener (DWT.Deiconify,typedListener); + addListener (DWT.Activate, typedListener); + addListener (DWT.Deactivate, typedListener); +} + +int balloonTipHandle () { + if (balloonTipHandle is 0) createBalloonTipHandle (); + return balloonTipHandle; +} + +int callWindowProc (int hwnd, int msg, int wParam, int lParam) { + if (handle is 0) return 0; + if (hwnd is toolTipHandle || hwnd is balloonTipHandle) { + return OS.CallWindowProc (ToolTipProc, hwnd, msg, wParam, lParam); + } + if (hwndMDIClient !is 0) { + return OS.DefFrameProc (hwnd, hwndMDIClient, msg, wParam, lParam); + } + if (windowProc !is 0) { + return OS.CallWindowProc (windowProc, hwnd, msg, wParam, lParam); + } + if ((style & DWT.TOOL) !is 0) { + int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX | DWT.BORDER | DWT.RESIZE; + if ((style & trim) is 0) return OS.DefWindowProc (hwnd, msg, wParam, lParam); + } + if (parent !is 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); +} + +/** + * 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 DWTException <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 DWT#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_BALLOON, + OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0, + handle, + 0, + OS.GetModuleHandle (null), + null); + if (balloonTipHandle is 0) error (DWT.ERROR_NO_HANDLES); + if (ToolTipProc is 0) { + ToolTipProc = OS.GetWindowLong (balloonTipHandle, OS.GWL_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.SetWindowLong (balloonTipHandle, OS.GWL_WNDPROC, display.windowProc); +} + +void createHandle () { + bool embedded = handle !is 0 && (state & FOREIGN_HANDLE) is 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 & DWT.ON_TOP) !is 0) display.lockActiveWindow = true; + if (handle is 0 || embedded) { + super.createHandle (); + } else { + state |= CANVAS; + if ((style & (DWT.H_SCROLL | DWT.V_SCROLL)) is 0) { + state |= THEME_BACKGROUND; + } + windowProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + } + + /* + * The following code is intentionally commented. + */ +// if ((style & DWT.ON_TOP) !is 0) display.lockActiveWindow = false; + + if (!embedded) { + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + bits &= ~(OS.WS_OVERLAPPED | OS.WS_CAPTION); + if (!OS.IsWinCE) bits |= OS.WS_POPUP; + if ((style & DWT.TITLE) !is 0) bits |= OS.WS_CAPTION; + if ((style & DWT.NO_TRIM) is 0) { + if ((style & (DWT.BORDER | DWT.RESIZE)) is 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; + SetWindowPos (handle, 0, 0, 0, 0, 0, flags); + if (OS.IsWinCE) _setMaximized (true); + if (OS.IsPPC) { + psai = new SHACTIVATEINFO (); + psai.cbSize = SHACTIVATEINFO.sizeof; + } + } + if (OS.IsDBLocale) { + hIMC = OS.ImmCreateContext (); + if (hIMC !is 0) OS.ImmAssociateContext (handle, hIMC); + } +} + +void createToolTip (ToolTip toolTip) { + int id = 0; + if (toolTips is null) toolTips = new ToolTip [4]; + while (id < toolTips.length && toolTips [id] !is null) id++; + if (id is 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; + if (OS.IsWinCE) return; + 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 = OS.CreateWindowEx ( + 0, + new TCHAR (0, OS.TOOLTIPS_CLASS, true), + null, + OS.TTS_ALWAYSTIP, + OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0, + handle, + 0, + OS.GetModuleHandle (null), + null); + if (toolTipHandle is 0) error (DWT.ERROR_NO_HANDLES); + if (ToolTipProc is 0) { + ToolTipProc = OS.GetWindowLong (toolTipHandle, OS.GWL_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.SetWindowLong (toolTipHandle, OS.GWL_WNDPROC, display.windowProc); +} + +void deregister () { + super.deregister (); + if (toolTipHandle !is 0) display.removeControl (toolTipHandle); + if (balloonTipHandle !is 0) display.removeControl (balloonTipHandle); +} + +void destroyToolTip (ToolTip toolTip) { + if (toolTips is null) return; + toolTips [toolTip.id - Display.ID_START] = null; + if (OS.IsWinCE) return; + if (balloonTipHandle !is 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; +} + +void destroyWidget () { + fixActiveShell (); + super.destroyWidget (); +} + +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 (DWT.ERROR_THREAD_INVALID_ACCESS); +// Display oldDisplay = display; + super.dispose (); + // widget is disposed at this point +// if (oldDisplay !is null) oldDisplay.update (); +} + +void enableWidget (bool enabled) { + if (enabled) { + state &= ~DISABLED; + } else { + state |= DISABLED; + } + if (Display.TrimEnabled) { + if (isActive ()) setItemEnabled (OS.SC_CLOSE, enabled); + } else { + OS.EnableWindow (handle, enabled); + } +} + +int findBrush (int value, int lbStyle) { + if (lbStyle is OS.BS_SOLID) { + for (int i=0; i<SYSTEM_COLORS.length; i++) { + if (value is OS.GetSysColor (SYSTEM_COLORS [i])) { + return OS.GetSysColorBrush (SYSTEM_COLORS [i]); + } + } + } + if (brushes is null) brushes = new int [BRUSHES_SIZE]; + LOGBRUSH logBrush = new LOGBRUSH (); + for (int i=0; i<brushes.length; i++) { + int hBrush = brushes [i]; + if (hBrush is 0) break; + OS.GetObject (hBrush, LOGBRUSH.sizeof, logBrush); + switch (logBrush.lbStyle) { + case OS.BS_SOLID: + if (lbStyle is OS.BS_SOLID) { + if (logBrush.lbColor is value) return hBrush; + } + break; + case OS.BS_PATTERN: + if (lbStyle is OS.BS_PATTERN) { + if (logBrush.lbHatch is value) return hBrush; + } + break; + } + } + int length = brushes.length; + int hBrush = brushes [--length]; + if (hBrush !is 0) OS.DeleteObject (hBrush); + System.arraycopy (brushes, 0, brushes, 1, length); + switch (lbStyle) { + case OS.BS_SOLID: + hBrush = OS.CreateSolidBrush (value); + break; + case OS.BS_PATTERN: + hBrush = OS.CreatePatternBrush (value); + break; + } + return brushes [0] = hBrush; +} + +Control findBackgroundControl () { + return background !is -1 || backgroundImage !is null ? this : null; +} + +Cursor findCursor () { + return cursor; +} + +Control findThemeControl () { + return null; +} + +ToolTip findToolTip (int id) { + if (toolTips is null) return null; + id = id - Display.ID_START; + return 0 <= id && id < toolTips.length ? toolTips [id] : null; +} + +void fixActiveShell () { + /* + * Feature in Windows. When the active shell is disposed + * or hidden, Windows normally makes the parent shell active + * and assigns focus. This does not happen when the parent + * shell is disabled. Instead, Windows assigns focus to the + * next shell on the desktop (possibly a shell in another + * application). The fix is to activate the disabled parent + * shell before disposing or hiding the active shell. + */ + int hwndParent = OS.GetParent (handle); + if (hwndParent !is 0 && handle is OS.GetActiveWindow ()) { + if (!OS.IsWindowEnabled (hwndParent) && OS.IsWindowVisible (hwndParent)) { + OS.SetActiveWindow (hwndParent); + } + } +} + +void fixShell (Shell newShell, Control control) { + if (this is newShell) return; + if (control is lastActive) setActiveControl (null); + String toolTipText = control.toolTipText; + if (toolTipText !is null) { + control.setToolTipText (this, null); + control.setToolTipText (newShell, toolTipText); + } +} + +void fixToolTip () { + /* + * Bug in Windows. On XP, when a tooltip is + * hidden due to a time out or mouse press, + * the tooltip remains active although no + * longer visible and won't show again until + * another tooltip becomes active. If there + * is only one tooltip in the window, it will + * never show again. The fix is to remove the + * current tooltip and add it again every time + * the mouse leaves the control. + */ + if (OS.COMCTL32_MAJOR >= 6) { + if (toolTipHandle is 0) return; + TOOLINFO lpti = new TOOLINFO (); + lpti.cbSize = TOOLINFO.sizeof; + if (OS.SendMessage (toolTipHandle, OS.TTM_GETCURRENTTOOL, 0, lpti) !is 0) { + if ((lpti.uFlags & OS.TTF_IDISHWND) !is 0) { + OS.SendMessage (toolTipHandle, OS.TTM_DELTOOL, 0, lpti); + OS.SendMessage (toolTipHandle, OS.TTM_ADDTOOL, 0, lpti); + } + } + } +} + +/** + * If the receiver is visible, moves it to the top of the + * drawing order for the display on which it was created + * (so that all other shells on that display, which are not + * the receiver's children will be drawn behind it) and forces + * the window manager to make the shell active. + * + * @exception DWTException <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> + * + * @since 2.0 + * @see Control#moveAbove + * @see Control#setFocus + * @see Control#setVisible + * @see Display#getActiveShell + * @see Decorations#setDefaultButton(Button) + * @see Shell#open + * @see Shell#setActive + */ +public void forceActive () { + checkWidget (); + if(!isVisible()) return; + OS.SetForegroundWindow (handle); +} + +void forceResize () { + /* Do nothing */ +} + +public Rectangle getBounds () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) return super.getBounds (); + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Rectangle (rect.left, rect.top, width, height); +} + +ToolTip getCurrentToolTip () { + if (toolTipHandle !is 0) { + ToolTip tip = getCurrentToolTip (toolTipHandle); + if (tip !is null) return tip; + } + if (balloonTipHandle !is 0) { + ToolTip tip = getCurrentToolTip (balloonTipHandle); + if (tip !is null) return tip; + } + return null; +} + +ToolTip getCurrentToolTip (int hwndToolTip) { + if (hwndToolTip is 0) return null; + if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, 0) !is 0) { + TOOLINFO lpti = new TOOLINFO (); + lpti.cbSize = TOOLINFO.sizeof; + if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, lpti) !is 0) { + if ((lpti.uFlags & OS.TTF_IDISHWND) is 0) return findToolTip (lpti.uId); + } + } + return null; +} + +public bool getEnabled () { + checkWidget (); + return (state & DISABLED) is 0; +} + +/** + * 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 + * <code>DWT</code>: + * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>, + * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>. + * + * @return the IME mode + * + * @exception DWTException <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 DWT + */ +public int getImeInputMode () { + checkWidget (); + if (!OS.IsDBLocale) return 0; + int hIMC = OS.ImmGetContext (handle); + int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1]; + bool open = OS.ImmGetOpenStatus (hIMC); + if (open) open = OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence); + OS.ImmReleaseContext (handle, hIMC); + if (!open) return DWT.NONE; + int result = 0; + if ((lpfdwConversion [0] & OS.IME_CMODE_ROMAN) !is 0) result |= DWT.ROMAN; + if ((lpfdwConversion [0] & OS.IME_CMODE_FULLSHAPE) !is 0) result |= DWT.DBCS; + if ((lpfdwConversion [0] & OS.IME_CMODE_KATAKANA) !is 0) return result | DWT.PHONETIC; + if ((lpfdwConversion [0] & OS.IME_CMODE_NATIVE) !is 0) return result | DWT.NATIVE; + return result | DWT.ALPHA; +} + +public Point getLocation () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + return super.getLocation (); + } + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + return new Point (rect.left, rect.top); +} + +/** + * Returns a point describing the minimum receiver's size. The + * x coordinate of the result is the minimum width of the receiver. + * The y coordinate of the result is the minimum height of the + * receiver. + * + * @return the receiver's size + * + * @exception DWTException <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> + * + * @since 3.1 + */ +public Point getMinimumSize () { + checkWidget (); + int width = Math.max (0, minWidth); + int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX; + if ((style & DWT.NO_TRIM) is 0 && (style & trim) !is 0) { + width = Math.max (width, OS.GetSystemMetrics (OS.SM_CXMINTRACK)); + } + int height = Math.max (0, minHeight); + if ((style & DWT.NO_TRIM) is 0 && (style & trim) !is 0) { + if ((style & DWT.RESIZE) !is 0) { + height = Math.max (height, OS.GetSystemMetrics (OS.SM_CYMINTRACK)); + } else { + RECT rect = new RECT (); + int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE); + int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE); + OS.AdjustWindowRectEx (rect, bits1, false, bits2); + height = Math.max (height, rect.bottom - rect.top); + } + } + return new Point (width, height); +} + +/** + * Returns the region that defines the shape of the shell, + * or null if the shell has the default shape. + * + * @return the region that defines the shape of the shell (or null) + * + * @exception DWTException <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> + * + * @since 3.0 + * + */ +public Region getRegion () { + checkWidget (); + return region; +} + +public Shell getShell () { + checkWidget (); + return this; +} + +public Point getSize () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) return super.getSize (); + } + RECT rect = new RECT (); + OS.GetWindowRect (handle, rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + return new Point (width, height); +} + +/** + * Returns an array containing all shells which are + * descendants of the receiver. + * <p> + * @return the dialog shells + * + * @exception DWTException <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 Shell [] getShells () { + checkWidget (); + int count = 0; + Shell [] shells = display.getShells (); + for (int i=0; i<shells.length; i++) { + Control shell = shells [i]; + do { + shell = shell.parent; + } while (shell !is null && shell !is this); + if (shell is this) count++; + } + int index = 0; + Shell [] result = new Shell [count]; + for (int i=0; i<shells.length; i++) { + Control shell = shells [i]; + do { + shell = shell.parent; + } while (shell !is null && shell !is this); + if (shell is this) { + result [index++] = shells [i]; + } + } + return result; +} + +Composite findDeferredControl () { + return layoutCount > 0 ? this : null; +} + +public bool isEnabled () { + checkWidget (); + return getEnabled (); +} + +public bool isVisible () { + checkWidget (); + return getVisible (); +} + +int hwndMDIClient () { + if (hwndMDIClient is 0) { + int widgetStyle = OS.MDIS_ALLCHILDSTYLES | OS.WS_CHILD | OS.WS_CLIPCHILDREN | OS.WS_CLIPSIBLINGS; + hwndMDIClient = OS.CreateWindowEx ( + 0, + new TCHAR (0, "MDICLIENT", true), + null, + widgetStyle, + 0, 0, 0, 0, + handle, + 0, + OS.GetModuleHandle (null), + new CREATESTRUCT ()); +// OS.ShowWindow (hwndMDIClient, OS.SW_SHOW); + } + return hwndMDIClient; +} + +/** + * Moves the receiver to the top of the drawing order for + * the display on which it was created (so that all other + * shells on that display, which are not the receiver's + * children will be drawn behind it), marks it visible, + * sets the focus and asks the window manager to make the + * shell active. + * + * @exception DWTException <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 Control#moveAbove + * @see Control#setFocus + * @see Control#setVisible + * @see Display#getActiveShell + * @see Decorations#setDefaultButton(Button) + * @see Shell#setActive + * @see Shell#forceActive + */ +public void open () { + checkWidget (); + STARTUPINFO lpStartUpInfo = Display.lpStartupInfo; + if (lpStartUpInfo is null || (lpStartUpInfo.dwFlags & OS.STARTF_USESHOWWINDOW) is 0) { + bringToTop (); + if (isDisposed ()) return; + } + /* + * Feature on WinCE PPC. A new application becomes + * the foreground application only if it has at least + * one visible window before the event loop is started. + * The workaround is to explicitly force the shell to + * be the foreground window. + */ + if (OS.IsWinCE) OS.SetForegroundWindow (handle); + OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0); + setVisible (true); + if (isDisposed ()) return; + /* + * Bug in Windows XP. Despite the fact that an icon has been + * set for a window, the task bar displays the wrong icon the + * first time the window is made visible with ShowWindow() after + * a call to BringToTop(), when a long time elapses between the + * ShowWindow() and the time the event queue is read. The icon + * in the window trimming is correct but the one in the task + * bar does not get updated. The fix is to call PeekMessage() + * with the flag PM_NOREMOVE and PM_QS_SENDMESSAGE to respond + * to a cross thread WM_GETICON. + * + * NOTE: This allows other cross thread messages to be delivered, + * most notably WM_ACTIVATE. + */ + MSG msg = new MSG (); + int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_SENDMESSAGE; + OS.PeekMessage (msg, 0, 0, 0, flags); + if (!restoreFocus () && !traverseGroup (true)) setFocus (); +} + +void register () { + super.register (); + if (toolTipHandle !is 0) display.addControl (toolTipHandle, this); + if (balloonTipHandle !is 0) display.addControl (balloonTipHandle, this); +} + +void releaseBrushes () { + if (brushes !is null) { + for (int i=0; i<brushes.length; i++) { + if (brushes [i] !is 0) OS.DeleteObject (brushes [i]); + } + } + brushes = null; +} + +void releaseChildren (bool destroy) { + Shell [] shells = getShells (); + for (int i=0; i<shells.length; i++) { + Shell shell = shells [i]; + if (shell !is null && !shell.isDisposed ()) { + shell.release (false); + } + } + if (toolTips !is null) { + for (int i=0; i<toolTips.length; i++) { + ToolTip toolTip = toolTips [i]; + if (toolTip !is null && !toolTip.isDisposed ()) { + toolTip.release (false); + } + } + } + toolTips = null; + super.releaseChildren (destroy); +} + +void releaseHandle () { + super.releaseHandle (); + hwndMDIClient = 0; +} + +void releaseParent () { + /* Do nothing */ +} + +void releaseWidget () { + super.releaseWidget (); + releaseBrushes (); + activeMenu = null; + display.clearModal (this); + if (lpstrTip !is 0) { + int hHeap = OS.GetProcessHeap (); + OS.HeapFree (hHeap, 0, lpstrTip); + } + lpstrTip = 0; + toolTipHandle = balloonTipHandle = 0; + if (OS.IsDBLocale) { + if (hIMC !is 0) OS.ImmDestroyContext (hIMC); + } + lastActive = null; + region = null; + toolTitle = balloonTitle = null; + lockToolTipControl = null; +} + +void removeMenu (Menu menu) { + super.removeMenu (menu); + if (menu is activeMenu) activeMenu = null; +} + +/** + * 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 <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <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 ShellListener + * @see #addShellListener + */ +public void removeShellListener (ShellListener listener) { + checkWidget (); + if (listener is null) error (DWT.ERROR_NULL_ARGUMENT); + if (eventTable is null) return; + eventTable.unhook (DWT.Close, listener); + eventTable.unhook (DWT.Iconify,listener); + eventTable.unhook (DWT.Deiconify,listener); + eventTable.unhook (DWT.Activate, listener); + eventTable.unhook (DWT.Deactivate, listener); +} + +LRESULT selectPalette (int hPalette) { + int hDC = OS.GetDC (handle); + int hOld = OS.SelectPalette (hDC, hPalette, false); + int result = OS.RealizePalette (hDC); + if (result > 0) { + OS.InvalidateRect (handle, null, true); + } else { + OS.SelectPalette (hDC, hOld, true); + OS.RealizePalette (hDC); + } + OS.ReleaseDC (handle, hDC); + return (result > 0) ? LRESULT.ONE : LRESULT.ZERO; +} + +/** + * If the receiver is visible, moves it to the top of the + * drawing order for the display on which it was created + * (so that all other shells on that display, which are not + * the receiver's children will be drawn behind it) and asks + * the window manager to make the shell active + * + * @exception DWTException <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> + * + * @since 2.0 + * @see Control#moveAbove + * @see Control#setFocus + * @see Control#setVisible + * @see Display#getActiveShell + * @see Decorations#setDefaultButton(Button) + * @see Shell#open + * @see Shell#setActive + */ +public void setActive () { + checkWidget (); + if (!isVisible ()) return; + bringToTop (); + // widget could be disposed at this point +} + +void setActiveControl (Control control) { + if (control !is null && control.isDisposed ()) control = null; + if (lastActive !is null && lastActive.isDisposed ()) lastActive = null; + if (lastActive is control) return; + + /* + * Compute the list of controls to be activated and + * deactivated by finding the first common parent + * control. + */ + Control [] activate = (control is null) ? new Control [0] : control.getPath (); + Control [] deactivate = (lastActive is null) ? new Control [0] : lastActive.getPath (); + lastActive = control; + int index = 0, length = Math.min (activate.length, deactivate.length); + while (index < length) { + if (activate [index] !is deactivate [index]) break; + index++; + } + + /* + * It is possible (but unlikely), that application + * code could have destroyed some of the widgets. If + * this happens, keep processing those widgets that + * are not disposed. + */ + for (int i=deactivate.length-1; i>=index; --i) { + if (!deactivate [i].isDisposed ()) { + deactivate [i].sendEvent (DWT.Deactivate); + } + } + for (int i=activate.length-1; i>=index; --i) { + if (!activate [i].isDisposed ()) { + activate [i].sendEvent (DWT.Activate); + } + } +} + +void setBounds (int x, int y, int width, int height, int flags, bool defer) { + super.setBounds (x, y, width, height, flags, false); +} + +public void setEnabled (bool enabled) { + checkWidget (); + if (((state & DISABLED) is 0) is enabled) return; + super.setEnabled (enabled); + if (enabled && handle is OS.GetActiveWindow ()) { + if (!restoreFocus ()) traverseGroup (true); + } +} + +/** + * 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 <code>DWT</code>: + * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>, + * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>. + * + * @param mode the new IME mode + * + * @exception DWTException <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 DWT + */ +public void setImeInputMode (int mode) { + checkWidget (); + if (!OS.IsDBLocale) return; + bool imeOn = mode !is DWT.NONE && mode !is DWT.ROMAN; + int hIMC = OS.ImmGetContext (handle); + OS.ImmSetOpenStatus (hIMC, imeOn); + if (imeOn) { + int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1]; + if (OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence)) { + int newBits = 0; + int oldBits = OS.IME_CMODE_NATIVE | OS.IME_CMODE_KATAKANA; + if ((mode & DWT.PHONETIC) !is 0) { + newBits = OS.IME_CMODE_KATAKANA | OS.IME_CMODE_NATIVE; + oldBits = 0; + } else { + if ((mode & DWT.NATIVE) !is 0) { + newBits = OS.IME_CMODE_NATIVE; + oldBits = OS.IME_CMODE_KATAKANA; + } + } + if ((mode & DWT.DBCS) !is 0) { + newBits |= OS.IME_CMODE_FULLSHAPE; + } else { + oldBits |= OS.IME_CMODE_FULLSHAPE; + } + if ((mode & DWT.ROMAN) !is 0) { + newBits |= OS.IME_CMODE_ROMAN; + } else { + oldBits |= OS.IME_CMODE_ROMAN; + } + lpfdwConversion [0] |= newBits; lpfdwConversion [0] &= ~oldBits; + OS.ImmSetConversionStatus (hIMC, lpfdwConversion [0], lpfdwSentence [0]); + } + } + OS.ImmReleaseContext (handle, hIMC); +} + +/** + * Sets the receiver's minimum size to the size specified by the arguments. + * If the new minimum size is larger than the current size of the receiver, + * the receiver is resized to the new minimum size. + * + * @param width the new minimum width for the receiver + * @param height the new minimum height for the receiver + * + * @exception DWTException <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> + * + * @since 3.1 + */ +public void setMinimumSize (int width, int height) { + checkWidget (); + int widthLimit = 0, heightLimit = 0; + int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX; + if ((style & DWT.NO_TRIM) is 0 && (style & trim) !is 0) { + widthLimit = OS.GetSystemMetrics (OS.SM_CXMINTRACK); + if ((style & DWT.RESIZE) !is 0) { + heightLimit = OS.GetSystemMetrics (OS.SM_CYMINTRACK); + } else { + RECT rect = new RECT (); + int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE); + int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE); + OS.AdjustWindowRectEx (rect, bits1, false, bits2); + heightLimit = rect.bottom - rect.top; + } + } + minWidth = Math.max (widthLimit, width); + minHeight = Math.max (heightLimit, height); + Point size = getSize (); + int newWidth = Math.max (size.x, minWidth); + int newHeight = Math.max (size.y, minHeight); + if (minWidth <= widthLimit) minWidth = DWT.DEFAULT; + if (minHeight <= heightLimit) minHeight = DWT.DEFAULT; + if (newWidth !is size.x || newHeight !is size.y) setSize (newWidth, newHeight); +} + +/** + * Sets the receiver's minimum size to the size specified by the argument. + * If the new minimum size is larger than the current size of the receiver, + * the receiver is resized to the new minimum size. + * + * @param size the new minimum size for the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception DWTException <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> + * + * @since 3.1 + */ +public void setMinimumSize (Point size) { + checkWidget (); + if (size is null) error (DWT.ERROR_NULL_ARGUMENT); + setMinimumSize (size.x, size.y); +} + +void setItemEnabled (int cmd, bool enabled) { + int hMenu = OS.GetSystemMenu (handle, false); + if (hMenu is 0) return; + int flags = OS.MF_ENABLED; + if (!enabled) flags = OS.MF_DISABLED | OS.MF_GRAYED; + OS.EnableMenuItem (hMenu, cmd, OS.MF_BYCOMMAND | flags); +} + +void setParent () { + /* Do nothing. Not necessary for Shells */ +} + +/** + * Sets the shape of the shell to the region specified + * by the argument. When the argument is null, the + * default shape of the shell is restored. The shell + * must be created with the style DWT.NO_TRIM in order + * to specify a region. + * + * @param region the region that defines the shape of the shell (or null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li> + * </ul> + * @exception DWTException <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> + * + * @since 3.0 + * + */ +public void setRegion (Region region) { + checkWidget (); + if ((style & DWT.NO_TRIM) is 0) return; + if (region !is null && region.isDisposed()) error (DWT.ERROR_INVALID_ARGUMENT); + int hRegion = 0; + if (region !is null) { + hRegion = OS.CreateRectRgn (0, 0, 0, 0); + OS.CombineRgn (hRegion, region.handle, hRegion, OS.RGN_OR); + } + OS.SetWindowRgn (handle, hRegion, true); + this.region = region; +} + +void setToolTipText (int hwnd, String text) { + if (OS.IsWinCE) return; + TOOLINFO lpti = new TOOLINFO (); + lpti.cbSize = TOOLINFO.sizeof; + lpti.hwnd = handle; + lpti.uId = hwnd; + int hwndToolTip = toolTipHandle (); + if (text is null) { + OS.SendMessage (hwndToolTip, OS.TTM_DELTOOL, 0, lpti); + } else { + if (OS.SendMessage (hwndToolTip, OS.TTM_GETTOOLINFO, 0, lpti) !is 0) { + OS.SendMessage (hwndToolTip, OS.TTM_UPDATE, 0, 0); + } else { + lpti.uFlags = OS.TTF_IDISHWND | OS.TTF_SUBCLASS; + lpti.lpszText = OS.LPSTR_TEXTCALLBACK; + OS.SendMessage (hwndToolTip, OS.TTM_ADDTOOL, 0, lpti); + } + } +} + +void setToolTipText (NMTTDISPINFO lpnmtdi, byte [] buffer) { + /* + * Ensure that the current position of the mouse + * is inside the client area of the shell. This + * prevents tool tips from popping up over the + * shell trimmings. + */ + if (!hasCursor ()) return; + int hHeap = OS.GetProcessHeap (); + if (lpstrTip !is 0) OS.HeapFree (hHeap, 0, lpstrTip); + int byteCount = buffer.length; + lpstrTip = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (lpstrTip, buffer, byteCount); + lpnmtdi.lpszText = lpstrTip; +} + +void setToolTipText (NMTTDISPINFO lpnmtdi, char [] buffer) { + /* + * Ensure that the current position of the mouse + * is inside the client area of the shell. This + * prevents tool tips from popping up over the + * shell trimmings. + */ + if (!hasCursor ()) return; + int hHeap = OS.GetProcessHeap (); + if (lpstrTip !is 0) OS.HeapFree (hHeap, 0, lpstrTip); + int byteCount = buffer.length * 2; + lpstrTip = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (lpstrTip, buffer, byteCount); + lpnmtdi.lpszText = lpstrTip; +} + +void setToolTipTitle (int hwndToolTip, String text, int icon) { + /* + * Bug in Windows. For some reason, when TTM_SETTITLE + * is used to set the title of a tool tip, Windows leaks + * GDI objects. This happens even when TTM_SETTITLE is + * called with TTI_NONE and NULL. The documentation + * states that Windows copies the icon and that the + * programmer must free the copy but does not provide + * API to get the icon. For example, when TTM_SETTITLE + * is called with ICON_ERROR, when TTM_GETTITLE is used + * to query the title and the icon, the uTitleBitmap + * field in the TTGETTITLE struct is zero. The fix + * is to remember these values, only set them when then + * change and leak less. + * + * NOTE: This only happens on Vista. + */ + if (hwndToolTip !is toolTipHandle && hwndToolTip !is balloonTipHandle) { + return; + } + if (hwndToolTip is toolTipHandle) { + if (text is toolTitle || (toolTitle !is null && toolTitle.equals (text))) { + if (icon is toolIcon) return; + } + toolTitle = text; + toolIcon = icon; + } else { + if (hwndToolTip is balloonTipHandle) { + if (text is balloonTitle || (balloonTitle !is null && balloonTitle.equals (text))) { + if (icon is toolIcon) return; + } + balloonTitle = text; + balloonIcon = icon; + } + } + if (text !is null) { + TCHAR pszTitle = new TCHAR (getCodePage (), text, true); + OS.SendMessage (hwndToolTip, OS.TTM_SETTITLE, icon, pszTitle); + } else { + OS.SendMessage (hwndToolTip, OS.TTM_SETTITLE, 0, 0); + } +} + +public void setVisible (bool visible) { + checkWidget (); + if (drawCount !is 0) { + if (((state & HIDDEN) is 0) is visible) return; + } else { + if (visible is OS.IsWindowVisible (handle)) return; + } + + /* + * Feature in Windows. When ShowWindow() is called used to hide + * a window, Windows attempts to give focus to the parent. If the + * parent is disabled by EnableWindow(), focus is assigned to + * another windows on the desktop. This means that if you hide + * a modal window before the parent is enabled, the parent will + * not come to the front. The fix is to change the modal state + * before hiding or showing a window so that this does not occur. + */ + int mask = DWT.PRIMARY_MODAL | DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL; + if ((style & mask) !is 0) { + if (visible) { + display.setModalShell (this); + Control control = display._getFocusControl (); + if (control !is null && !control.isActive ()) { + bringToTop (); + if (isDisposed ()) return; + } + int hwndShell = OS.GetActiveWindow (); + if (hwndShell is 0) { + if (parent !is null) hwndShell = parent.handle; + } + if (hwndShell !is 0) { + OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0); + } + OS.ReleaseCapture (); + } else { + display.clearModal (this); + } + } else { + updateModal (); + } + + /* + * Bug in Windows. Calling ShowOwnedPopups() to hide the + * child windows of a hidden window causes the application + * to be deactivated. The fix is to call ShowOwnedPopups() + * to hide children before hiding the parent. + */ + if (showWithParent && !visible) { + if (!OS.IsWinCE) OS.ShowOwnedPopups (handle, false); + } + if (!visible) fixActiveShell (); + super.setVisible (visible); + if (isDisposed ()) return; + if (showWithParent is visible) return; + showWithParent = visible; + if (visible) { + if (!OS.IsWinCE) OS.ShowOwnedPopups (handle, true); + } +} + +void subclass () { + super.subclass (); + if (ToolTipProc !is 0) { + int newProc = display.windowProc; + if (toolTipHandle !is 0) { + OS.SetWindowLong (toolTipHandle, OS.GWL_WNDPROC, newProc); + } + if (balloonTipHandle !is 0) { + OS.SetWindowLong (balloonTipHandle, OS.GWL_WNDPROC, newProc); + } + } +} + +int toolTipHandle () { + if (toolTipHandle is 0) createToolTipHandle (); + return toolTipHandle; +} + +bool translateAccelerator (MSG msg) { + if (!isEnabled () || !isActive ()) return false; + if (menuBar !is null && !menuBar.isEnabled ()) return false; + return translateMDIAccelerator (msg) || translateMenuAccelerator (msg); +} + +bool traverseEscape () { + if (parent is null) return false; + if (!isVisible () || !isEnabled ()) return false; + close (); + return true; +} + +void unsubclass () { + super.unsubclass (); + if (ToolTipProc !is 0) { + if (toolTipHandle !is 0) { + OS.SetWindowLong (toolTipHandle, OS.GWL_WNDPROC, ToolTipProc); + } + if (toolTipHandle !is 0) { + OS.SetWindowLong (toolTipHandle, OS.GWL_WNDPROC, ToolTipProc); + } + } +} + +void updateModal () { + if (Display.TrimEnabled) { + setItemEnabled (OS.SC_CLOSE, isActive ()); + } else { + OS.EnableWindow (handle, isActive ()); + } +} + +CREATESTRUCT widgetCreateStruct () { + return null; +} + +int widgetParent () { + if (handle !is 0) return handle; + return parent !is null ? parent.handle : 0; +} + +int widgetExtStyle () { + int bits = super.widgetExtStyle () & ~OS.WS_EX_MDICHILD; + if ((style & DWT.TOOL) !is 0) bits |= OS.WS_EX_TOOLWINDOW; + + /* + * Feature in Windows. When a window that does not have a parent + * is created, it is automatically added to the Windows Task Bar, + * even when it has no title. The fix is to use WS_EX_TOOLWINDOW + * which does not cause the window to appear in the Task Bar. + */ + if (!OS.IsWinCE) { + if (parent is null) { + if ((style & DWT.ON_TOP) !is 0) { + int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX; + if ((style & DWT.NO_TRIM) !is 0 || (style & trim) is 0) { + bits |= OS.WS_EX_TOOLWINDOW; + } + } + } + } + + /* + * Bug in Windows 98 and NT. Creating a window with the + * WS_EX_TOPMOST extended style can result in a dialog shell + * being moved behind its parent. The exact case where this + * happens is a shell with two dialog shell children where + * each dialog child has another hidden dialog child with + * the WS_EX_TOPMOST extended style. Clicking on either of + * the visible dialogs causes them to become active but move + * to the back, behind the parent shell. The fix is to + * disallow the WS_EX_TOPMOST extended style on Windows 98 + * and NT. + */ + if (parent !is null) { + if (OS.IsWin95) return bits; + if (OS.WIN32_VERSION < OS.VERSION (4, 10)) { + return bits; + } + } + if ((style & DWT.ON_TOP) !is 0) bits |= OS.WS_EX_TOPMOST; + return bits; +} + +TCHAR windowClass () { + if (OS.IsSP) return DialogClass; + if ((style & DWT.TOOL) !is 0) { + int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX | DWT.BORDER | DWT.RESIZE; + if ((style & trim) is 0) return display.windowShadowClass; + } + return parent !is null ? DialogClass : super.windowClass (); +} + +int windowProc () { + if (windowProc !is 0) return windowProc; + if (OS.IsSP) return DialogProc; + if ((style & DWT.TOOL) !is 0) { + int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX | DWT.BORDER | DWT.RESIZE; + if ((style & trim) is 0) super.windowProc (); + } + return parent !is null ? DialogProc : super.windowProc (); +} + +int windowProc (int hwnd, int msg, int wParam, int lParam) { + if (handle is 0) return 0; + if (hwnd is toolTipHandle || hwnd is balloonTipHandle) { + switch (msg) { + case OS.WM_TIMER: { + if (wParam !is ToolTip.TIMER_ID) break; + ToolTip tip = getCurrentToolTip (hwnd); + if (tip !is null && tip.autoHide) { + tip.setVisible (false); + } + break; + } + case OS.WM_LBUTTONDOWN: { + ToolTip tip = getCurrentToolTip (hwnd); + if (tip !is null) { + tip.setVisible (false); + tip.postEvent (DWT.Selection); + } + break; + } + } + return callWindowProc (hwnd, msg, wParam, lParam); + } + return super.windowProc (hwnd, msg, wParam, lParam); +} + +int widgetStyle () { + int bits = super.widgetStyle (); + if (handle !is 0) return bits | OS.WS_CHILD; + bits &= ~OS.WS_CHILD; + /* + * Feature in WinCE. Calling CreateWindowEx () with WS_OVERLAPPED + * and a parent window causes the new window to become a WS_CHILD of + * the parent instead of a dialog child. The fix is to use WS_POPUP + * for a window with a parent. + * + * Feature in WinCE PPC. A window without a parent with WS_POPUP + * always shows on top of the Pocket PC 'Today Screen'. The fix + * is to not set WS_POPUP for a window without a parent on WinCE + * devices. + * + * NOTE: WS_POPUP causes CreateWindowEx () to ignore CW_USEDEFAULT + * and causes the default window location and size to be zero. + */ + if (OS.IsWinCE) { + if (OS.IsSP) return bits | OS.WS_POPUP; + return parent is null ? bits : bits | OS.WS_POPUP; + } + + /* + * Use WS_OVERLAPPED for all windows, either dialog or top level + * so that CreateWindowEx () will respect CW_USEDEFAULT and set + * the default window location and size. + * + * NOTE: When a WS_OVERLAPPED window is created, Windows gives + * the new window WS_CAPTION style bits. These two constants are + * as follows: + * + * WS_OVERLAPPED = 0 + * WS_CAPTION = WS_BORDER | WS_DLGFRAME + * + */ + return bits | OS.WS_OVERLAPPED | OS.WS_CAPTION; +} + +LRESULT WM_ACTIVATE (int wParam, int lParam) { + if (OS.IsPPC) { + /* + * Note: this does not work when we get WM_ACTIVATE prior + * to adding a listener. + */ + if (hooks (DWT.HardKeyDown) || hooks (DWT.HardKeyUp)) { + int fActive = wParam & 0xFFFF; + int hwnd = fActive !is 0 ? handle : 0; + for (int bVk=OS.VK_APP1; bVk<=OS.VK_APP6; bVk++) { + OS.SHSetAppKeyWndAssoc ((byte) bVk, hwnd); + } + } + /* Restore SIP state when window is activated */ + if ((wParam & 0xFFFF) !is 0) { + OS.SHSipPreference (handle, psai.fSipUp is 0 ? OS.SIP_DOWN : OS.SIP_UP); + } + } + + /* + * Bug in Windows XP. When a Shell is deactivated, the + * IME composition window does not go away. This causes + * repaint issues. The fix is to close the IME to cause + * the composition string to be committed. + * + * Note. The IME needs to be reopened in order to preserve + * the input method status. + */ + if (OS.WIN32_VERSION >= OS.VERSION (5, 1)) { + if ((wParam & 0xFFFF) is 0 && OS.IsDBLocale && hIMC !is 0) { + if (OS.ImmGetOpenStatus(hIMC)) { + OS.ImmSetOpenStatus (hIMC, false); + OS.ImmSetOpenStatus (hIMC, true); + } + } + } + + /* Process WM_ACTIVATE */ + LRESULT result = super.WM_ACTIVATE (wParam, lParam); + if ((wParam & 0xFFFF) is 0) { + if (lParam is 0 || (lParam !is toolTipHandle && lParam !is balloonTipHandle)) { + ToolTip tip = getCurrentToolTip (); + if (tip !is null) tip.setVisible (false); + } + } + return parent !is null ? LRESULT.ZERO : result; +} + +LRESULT WM_COMMAND (int wParam, int lParam) { + if (OS.IsPPC) { + /* + * Note in WinCE PPC: Close the Shell when the "Done Button" has + * been pressed. lParam is either 0 (PocketPC 2002) or the handle + * to the Shell (PocketPC). + */ + int loWord = wParam & 0xFFFF; + if (loWord is OS.IDOK && (lParam is 0 || lParam is handle)) { + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); + return LRESULT.ZERO; + } + } + /* + * Feature in Windows. On PPC, the menu is not actually an HMENU. + * By observation, it is a tool bar that is configured to look like + * a menu. Therefore, when the PPC menu sends WM_COMMAND messages, + * lParam is not zero because the WM_COMMAND was not sent from a menu. + * Sub menu item events originate from the menu bar. Top menu items + * events originate from a tool bar. The fix is to detect the source + * of the WM_COMMAND and set lParam to zero to pretend that the message + * came from a real Windows menu, not a tool bar. + */ + if (OS.IsPPC || OS.IsSP) { + if (menuBar !is null) { + int hwndCB = menuBar.hwndCB; + if (lParam !is 0 && hwndCB !is 0) { + if (lParam is hwndCB) { + return super.WM_COMMAND (wParam, 0); + } else { + int hwndChild = OS.GetWindow (hwndCB, OS.GW_CHILD); + if (lParam is hwndChild) return super.WM_COMMAND (wParam, 0); + } + } + } + } + return super.WM_COMMAND (wParam, lParam); +} + +LRESULT WM_DESTROY (int wParam, int lParam) { + LRESULT result = super.WM_DESTROY (wParam, lParam); + /* + * When the shell is a WS_CHILD window of a non-DWT + * window, the destroy code does not get called because + * the non-DWT window does not call dispose (). Instead, + * the destroy code is called here in WM_DESTROY. + */ + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits & OS.WS_CHILD) !is 0) { + releaseParent (); + release (false); + } + return result; +} + +LRESULT WM_ERASEBKGND (int wParam, int lParam) { + LRESULT result = super.WM_ERASEBKGND (wParam, lParam); + if (result !is null) return result; + /* + * Feature in Windows. When a shell is resized by dragging + * the resize handles, Windows temporarily fills in black + * rectangles where the new contents of the shell should + * draw. The fix is to always draw the background of shells. + * + * NOTE: This only happens on Vista. + */ + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { + drawBackground (wParam); + return LRESULT.ONE; + } + return result; +} + +LRESULT WM_ENTERIDLE (int wParam, int lParam) { + LRESULT result = super.WM_ENTERIDLE (wParam, lParam); + if (result !is null) return result; + if (OS.IsWinCE && display.runMessages) { + if (display.runAsyncMessages (true)) display.wakeThread (); + } + return result; +} + +LRESULT WM_GETMINMAXINFO (int wParam, int lParam) { + LRESULT result = super.WM_GETMINMAXINFO (wParam, lParam); + if (result !is null) return result; + if (minWidth !is DWT.DEFAULT || minHeight !is DWT.DEFAULT) { + MINMAXINFO info = new MINMAXINFO (); + OS.MoveMemory (info, lParam, MINMAXINFO.sizeof); + if (minWidth !is DWT.DEFAULT) info.ptMinTrackSize_x = minWidth; + if (minHeight !is DWT.DEFAULT) info.ptMinTrackSize_y = minHeight; + OS.MoveMemory (lParam, info, MINMAXINFO.sizeof); + return LRESULT.ZERO; + } + return result; +} + +LRESULT WM_MOUSEACTIVATE (int wParam, int lParam) { + LRESULT result = super.WM_MOUSEACTIVATE (wParam, lParam); + if (result !is null) return result; + + /* + * Check for WM_MOUSEACTIVATE when an MDI shell is active + * and stop the normal shell activation but allow the mouse + * down to be delivered. + */ + int hittest = (short) (lParam & 0xFFFF); + switch (hittest) { + case OS.HTERROR: + case OS.HTTRANSPARENT: + case OS.HTNOWHERE: + break; + default: { + Control control = display._getFocusControl (); + if (control !is null) { + Decorations decorations = control.menuShell (); + if (decorations.getShell () is this && decorations !is this) { + display.ignoreRestoreFocus = true; + display.lastHittest = hittest; + display.lastHittestControl = null; + if (hittest is OS.HTMENU || hittest is OS.HTSYSMENU) { + display.lastHittestControl = control; + return null; + } + if (OS.IsWin95 && hittest is OS.HTCAPTION) { + display.lastHittestControl = control; + } + return new LRESULT (OS.MA_NOACTIVATE); + } + } + } + } + if (hittest is OS.HTMENU) return null; + + /* + * Get the current location of the cursor, + * not the location of the cursor when the + * WM_MOUSEACTIVATE was generated. This is + * strictly incorrect but is necessary in + * order to support Activate and Deactivate + * events for embedded widgets that have + * their own event loop. In that case, the + * cursor location reported by GetMessagePos() + * is the one for our event loop, not the + * embedded widget's event loop. + */ + POINT pt = new POINT (); + if (!OS.GetCursorPos (pt)) { + int pos = OS.GetMessagePos (); + pt.x = (short) (pos & 0xFFFF); + pt.y = (short) (pos >> 16); + } + int hwnd = OS.WindowFromPoint (pt); + if (hwnd is 0) return null; + Control control = display.findControl (hwnd); + + /* + * When a shell is created with DWT.ON_TOP and DWT.NO_FOCUS, + * do not activate the shell when the user clicks on the + * the client area or on the border or a control within the + * shell that does not take focus. + */ + if (control !is null && (control.state & CANVAS) !is 0) { + if ((control.style & DWT.NO_FOCUS) !is 0) { + int bits = DWT.ON_TOP | DWT.NO_FOCUS; + if ((style & bits) is bits) { + if (hittest is OS.HTBORDER || hittest is OS.HTCLIENT) { + return new LRESULT (OS.MA_NOACTIVATE); + } + } + } + } + + setActiveControl (control); + return null; +} + +LRESULT WM_MOVE (int wParam, int lParam) { + LRESULT result = super.WM_MOVE (wParam, lParam); + if (result !is null) return result; + ToolTip tip = getCurrentToolTip (); + if (tip !is null) tip.setVisible (false); + return result; +} + +LRESULT WM_NCACTIVATE (int wParam, int lParam) { + Display display = this.display; + LRESULT result = super.WM_NCACTIVATE (wParam, lParam); + if (display.isXMouseActive ()) { + if (lockToolTipControl !is null) { + if (OS.GetAsyncKeyState (OS.VK_LBUTTON) < 0) return result; + if (OS.GetAsyncKeyState (OS.VK_MBUTTON) < 0) return result; + if (OS.GetAsyncKeyState (OS.VK_RBUTTON) < 0) return result; + if (OS.GetAsyncKeyState (OS.VK_XBUTTON1) < 0) return result; + if (OS.GetAsyncKeyState (OS.VK_XBUTTON2) < 0) return result; + return LRESULT.ZERO; + } + } + return result; +} + +LRESULT WM_NCHITTEST (int wParam, int lParam) { + if (!OS.IsWindowEnabled (handle)) return null; + if (!isEnabled () || !isActive ()) { + if (!Display.TrimEnabled) return new LRESULT (OS.HTNOWHERE); + int hittest = callWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam); + if (hittest is OS.HTCLIENT || hittest is OS.HTMENU) hittest = OS.HTBORDER; + return new LRESULT (hittest); + } + if (menuBar !is null && !menuBar.getEnabled ()) { + int hittest = callWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam); + if (hittest is OS.HTMENU) hittest = OS.HTBORDER; + return new LRESULT (hittest); + } + return null; +} + +LRESULT WM_NCLBUTTONDOWN (int wParam, int lParam) { + LRESULT result = super.WM_NCLBUTTONDOWN (wParam, lParam); + if (result !is null) return result; + /* + * When the normal activation was interrupted in WM_MOUSEACTIVATE + * because the active shell was an MDI shell, set the active window + * to the top level shell but lock the active window and stop focus + * changes. This allows the user to interact the top level shell + * in the normal manner. + */ + if (!display.ignoreRestoreFocus) return result; + Display display = this.display; + int hwndActive = 0; + bool fixActive = OS.IsWin95 && display.lastHittest is OS.HTCAPTION; + if (fixActive) hwndActive = OS.SetActiveWindow (handle); + display.lockActiveWindow = true; + int code = callWindowProc (handle, OS.WM_NCLBUTTONDOWN, wParam, lParam); + display.lockActiveWindow = false; + if (fixActive) OS.SetActiveWindow (hwndActive); + Control focusControl = display.lastHittestControl; + if (focusControl !is null && !focusControl.isDisposed ()) { + focusControl.setFocus (); + } + display.lastHittestControl = null; + display.ignoreRestoreFocus = false; + return new LRESULT (code); +} + +LRESULT WM_PALETTECHANGED (int wParam, int lParam) { + if (wParam !is handle) { + int hPalette = display.hPalette; + if (hPalette !is 0) return selectPalette (hPalette); + } + return super.WM_PALETTECHANGED (wParam, lParam); +} + +LRESULT WM_QUERYNEWPALETTE (int wParam, int lParam) { + int hPalette = display.hPalette; + if (hPalette !is 0) return selectPalette (hPalette); + return super.WM_QUERYNEWPALETTE (wParam, lParam); +} + +LRESULT WM_SETCURSOR (int wParam, int lParam) { + /* + * Feature in Windows. When the shell is disabled + * by a Windows standard dialog (like a MessageBox + * or FileDialog), clicking in the shell does not + * bring the shell or the dialog to the front. The + * fix is to detect this case and bring the shell + * forward. + */ + int msg = (short) (lParam >> 16); + if (msg is OS.WM_LBUTTONDOWN) { + if (!Display.TrimEnabled) { + Shell modalShell = display.getModalShell (); + if (modalShell !is null && !isActive ()) { + int hwndModal = modalShell.handle; + if (OS.IsWindowEnabled (hwndModal)) { + OS.SetActiveWindow (hwndModal); + } + } + } + if (!OS.IsWindowEnabled (handle)) { + if (!OS.IsWinCE) { + int hwndPopup = OS.GetLastActivePopup (handle); + if (hwndPopup !is 0 && hwndPopup !is handle) { + if (display.getControl (hwndPopup) is null) { + if (OS.IsWindowEnabled (hwndPopup)) { + OS.SetActiveWindow (hwndPopup); + } + } + } + } + } + } + /* + * When the shell that contains a cursor is disabled, + * WM_SETCURSOR is called with HTERROR. Normally, + * when a control is disabled, the parent will get + * mouse and cursor events. In the case of a disabled + * shell, there is no enabled parent. In order to + * show the cursor when a shell is disabled, it is + * necessary to override WM_SETCURSOR when called + * with HTERROR to set the cursor but only when the + * mouse is in the client area of the shell. + */ + int hitTest = (short) (lParam & 0xFFFF); + if (hitTest is OS.HTERROR) { + if (!getEnabled ()) { + Control control = display.getControl (wParam); + if (control is this && cursor !is null) { + POINT pt = new POINT (); + int pos = OS.GetMessagePos (); + pt.x = (short) (pos & 0xFFFF); + pt.y = (short) (pos >> 16); + OS.ScreenToClient (handle, pt); + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + if (OS.PtInRect (rect, pt)) { + OS.SetCursor (cursor.handle); + switch (msg) { + case OS.WM_LBUTTONDOWN: + case OS.WM_RBUTTONDOWN: + case OS.WM_MBUTTONDOWN: + case OS.WM_XBUTTONDOWN: + OS.MessageBeep (OS.MB_OK); + } + return LRESULT.ONE; + } + } + } + } + return super.WM_SETCURSOR (wParam, lParam); +} + +LRESULT WM_SETTINGCHANGE (int wParam, int lParam) { + LRESULT result = super.WM_SETTINGCHANGE (wParam, lParam); + if (result !is null) return result; + if (OS.IsPPC) { + if (wParam is OS.SPI_SETSIPINFO) { + /* + * The SIP is in a new state. Cache its new value. + * Resize the Shell if it has the style DWT.RESIZE. + * Note that SHHandleWMSettingChange resizes the + * Shell and also updates the cached state. + */ + if ((style & DWT.RESIZE) !is 0) { + OS.SHHandleWMSettingChange (handle, wParam, lParam, psai); + return LRESULT.ZERO; + } else { + SIPINFO pSipInfo = new SIPINFO (); + pSipInfo.cbSize = SIPINFO.sizeof; + OS.SipGetInfo (pSipInfo); + psai.fSipUp = pSipInfo.fdwFlags & OS.SIPF_ON; + } + } + } + return result; +} + +LRESULT WM_SHOWWINDOW (int wParam, int lParam) { + LRESULT result = super.WM_SHOWWINDOW (wParam, lParam); + if (result !is null) return result; + /* + * Bug in Windows. If the shell is hidden while the parent + * is iconic, Windows shows the shell when the parent is + * deiconified. This does not happen if the shell is hidden + * while the parent is not an icon. The fix is to track + * visible state for the shell and refuse to show the shell + * when the parent is shown. + */ + if (lParam is OS.SW_PARENTOPENING) { + Control control = this; + while (control !is null) { + Shell shell = control.getShell (); + if (!shell.showWithParent) return LRESULT.ZERO; + control = control.parent; + } + } + return result; +} + +LRESULT WM_SYSCOMMAND (int wParam, int lParam) { + LRESULT result = super.WM_SYSCOMMAND (wParam, lParam); + if (result !is null) return result; + /* + * Feature in Windows. When the last visible window in + * a process minimized, Windows swaps out the memory for + * the process. The assumption is that the user can no + * longer interact with the window, so the memory can be + * released to other applications. However, for programs + * that use a lot of memory, swapping the memory back in + * can take a long time, sometimes minutes. The fix is + * to intercept WM_SYSCOMMAND looking for SC_MINIMIZE + * and use ShowWindow() with SW_SHOWMINIMIZED to minimize + * the window, rather than running the default window proc. + * + * NOTE: The default window proc activates the next + * top-level window in the Z-order while ShowWindow() + * with SW_SHOWMINIMIZED does not. There is no fix for + * this at this time. + */ + if (OS.IsWinNT) { + int cmd = wParam & 0xFFF0; + switch (cmd) { + case OS.SC_MINIMIZE: + long memory = Runtime.getRuntime ().totalMemory (); + if (memory >= 32 * 1024 * 1024) { + OS.ShowWindow (handle, OS.SW_SHOWMINIMIZED); + return LRESULT.ZERO; + } + } + } + return result; +} + +LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) { + LRESULT result = super.WM_WINDOWPOSCHANGING (wParam,lParam); + if (result !is null) return result; + WINDOWPOS lpwp = new WINDOWPOS (); + OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof); + if ((lpwp.flags & OS.SWP_NOSIZE) is 0) { + lpwp.cx = Math.max (lpwp.cx, minWidth); + int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX; + if ((style & DWT.NO_TRIM) is 0 && (style & trim) !is 0) { + lpwp.cx = Math.max (lpwp.cx, OS.GetSystemMetrics (OS.SM_CXMINTRACK)); + } + lpwp.cy = Math.max (lpwp.cy, minHeight); + if ((style & DWT.NO_TRIM) is 0 && (style & trim) !is 0) { + if ((style & DWT.RESIZE) !is 0) { + lpwp.cy = Math.max (lpwp.cy, OS.GetSystemMetrics (OS.SM_CYMINTRACK)); + } else { + RECT rect = new RECT (); + int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE); + int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE); + OS.AdjustWindowRectEx (rect, bits1, false, bits2); + lpwp.cy = Math.max (lpwp.cy, rect.bottom - rect.top); + } + } + OS.MoveMemory (lParam, lpwp, WINDOWPOS.sizeof); + } + return result; +} +} +++/