Mercurial > projects > dwt2
diff org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/widgets/Decorations.d @ 0:6dd524f61e62
add dwt win and basic java stuff
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 02 Mar 2009 14:44:16 +0100 |
parents | |
children | d46287db17ed |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/widgets/Decorations.d Mon Mar 02 14:44:16 2009 +0100 @@ -0,0 +1,1833 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module org.eclipse.swt.widgets.Decorations; + + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.win32.OS; + +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Display; + +import java.lang.all; + +/** + * Instances of this class provide the appearance and + * behavior of <code>Shells</code>, but are not top + * level shells or dialogs. Class <code>Shell</code> + * shares a significant amount of code with this class, + * and is a subclass. + * <p> + * IMPORTANT: This class was intended to be abstract and + * should <em>never</em> be referenced or instantiated. + * Instead, the class <code>Shell</code> should be used. + * </p> + * <p> + * Instances are always displayed in one of the maximized, + * minimized or normal states: + * <ul> + * <li> + * When an instance is marked as <em>maximized</em>, the + * window manager will typically resize it to fill the + * entire visible area of the display, and the instance + * is usually put in a state where it can not be resized + * (even if it has style <code>RESIZE</code>) until it is + * no longer maximized. + * </li><li> + * When an instance is in the <em>normal</em> state (neither + * maximized or minimized), its appearance is controlled by + * the style constants which were specified when it was created + * and the restrictions of the window manager (see below). + * </li><li> + * When an instance has been marked as <em>minimized</em>, + * its contents (client area) will usually not be visible, + * and depending on the window manager, it may be + * "iconified" (that is, replaced on the desktop by a small + * simplified representation of itself), relocated to a + * distinguished area of the screen, or hidden. Combinations + * of these changes are also possible. + * </li> + * </ul> + * </p> + * Note: The styles supported by this class must be treated + * as <em>HINT</em>s, since the window manager for the + * desktop on which the instance is visible has ultimate + * control over the appearance and behavior of decorations. + * For example, some window managers only support resizable + * windows and will always assume the RESIZE style, even if + * it is not set. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * Class <code>SWT</code> provides two "convenience constants" + * for the most commonly required style combinations: + * <dl> + * <dt><code>SHELL_TRIM</code></dt> + * <dd> + * the result of combining the constants which are required + * to produce a typical application top level shell: (that + * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>) + * </dd> + * <dt><code>DIALOG_TRIM</code></dt> + * <dd> + * the result of combining the constants which are required + * to produce a typical application dialog shell: (that + * is, <code>TITLE | CLOSE | BORDER</code>) + * </dd> + * </dl> + * <p> + * IMPORTANT: This class is intended to be subclassed <em>only</em> + * within the SWT implementation. + * </p> + * + * @see #getMinimized + * @see #getMaximized + * @see Shell + * @see SWT + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> + */ + +public class Decorations : Canvas { + + alias Canvas.setBounds setBounds; + alias Canvas.setParent setParent; + alias Canvas.setSavedFocus setSavedFocus; + alias Canvas.sort sort; + alias Canvas.windowProc windowProc; + + Image image, smallImage, largeImage; + Image [] images; + Menu menuBar; + Menu [] menus; + Control savedFocus; + Button defaultButton, saveDefault; + int swFlags; + HACCEL hAccel; + int nAccel; + bool moved, resized, opened; + int oldX = OS.CW_USEDEFAULT, oldY = OS.CW_USEDEFAULT; + int oldWidth = OS.CW_USEDEFAULT, oldHeight = OS.CW_USEDEFAULT; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +this () { +} + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in + * class <code>SWT</code> which is applicable to instances of this + * class, or must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>SWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p> + * + * @param parent a composite control which will be the parent of the new instance (cannot be null) + * @param style the style of control to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> + * </ul> + * + * @see SWT#BORDER + * @see SWT#CLOSE + * @see SWT#MIN + * @see SWT#MAX + * @see SWT#RESIZE + * @see SWT#TITLE + * @see SWT#NO_TRIM + * @see SWT#SHELL_TRIM + * @see SWT#DIALOG_TRIM + * @see SWT#ON_TOP + * @see SWT#TOOL + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public this (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +void _setMaximized (bool maximized) { + swFlags = maximized ? OS.SW_SHOWMAXIMIZED : OS.SW_RESTORE; + static if (OS.IsWinCE) { + /* + * Note: WinCE does not support SW_SHOWMAXIMIZED and SW_RESTORE. The + * workaround is to resize the window to fit the parent client area. + */ + if (maximized) { + RECT rect; + OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, &rect, 0); + int width = rect.right - rect.left, height = rect.bottom - rect.top; + if (OS.IsPPC) { + /* Leave space for the menu bar */ + if (menuBar !is null) { + auto hwndCB = menuBar.hwndCB; + RECT rectCB; + OS.GetWindowRect (hwndCB, &rectCB); + height -= rectCB.bottom - rectCB.top; + } + } + int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE; + SetWindowPos (handle, null, rect.left, rect.top, width, height, flags); + } + } else { + if (!OS.IsWindowVisible (handle)) return; + if (maximized is OS.IsZoomed (handle)) return; + OS.ShowWindow (handle, swFlags); + OS.UpdateWindow (handle); + } +} + +void _setMinimized (bool minimized) { + static if (OS.IsWinCE) return; + swFlags = minimized ? OS.SW_SHOWMINNOACTIVE : OS.SW_RESTORE; + if (!OS.IsWindowVisible (handle)) return; + if (minimized is OS.IsIconic (handle)) return; + int flags = swFlags; + if (flags is OS.SW_SHOWMINNOACTIVE && handle is OS.GetActiveWindow ()) { + flags = OS.SW_MINIMIZE; + } + OS.ShowWindow (handle, flags); + OS.UpdateWindow (handle); +} + +void addMenu (Menu menu) { + if (menus is null) menus = new Menu [4]; + for (int i=0; i<menus.length; i++) { + if (menus [i] is null) { + menus [i] = menu; + return; + } + } + Menu [] newMenus = new Menu [menus.length + 4]; + newMenus [menus.length] = menu; + System.arraycopy (menus, 0, newMenus, 0, menus.length); + menus = newMenus; +} + +void bringToTop () { + /* + * This code is intentionally commented. On some platforms, + * the ON_TOP style creates a shell that will stay on top + * of every other shell on the desktop. Using SetWindowPos () + * with HWND_TOP caused problems on Windows 98 so this code is + * commented out until this functionality is specified and + * the problems are fixed. + */ +// if ((style & SWT.ON_TOP) !is 0) { +// int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE; +// OS.SetWindowPos (handle, OS.HWND_TOP, 0, 0, 0, 0, flags); +// } else { + OS.BringWindowToTop (handle); + // widget could be disposed at this point +// } +} + +static int checkStyle (int style) { + if ((style & SWT.NO_TRIM) !is 0) { + style &= ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER); + } + static if (OS.IsWinCE) { + /* + * Feature in WinCE PPC. WS_MINIMIZEBOX or WS_MAXIMIZEBOX + * are not supposed to be used. If they are, the result + * is a button which does not repaint correctly. The fix + * is to remove this style. + */ + if ((style & SWT.MIN) !is 0) style &= ~SWT.MIN; + if ((style & SWT.MAX) !is 0) style &= ~SWT.MAX; + return style; + } + if ((style & (SWT.MENU | SWT.MIN | SWT.MAX | SWT.CLOSE)) !is 0) { + style |= SWT.TITLE; + } + + /* + * If either WS_MINIMIZEBOX or WS_MAXIMIZEBOX are set, + * we must also set WS_SYSMENU or the buttons will not + * appear. + */ + if ((style & (SWT.MIN | SWT.MAX)) !is 0) style |= SWT.CLOSE; + + /* + * Both WS_SYSMENU and WS_CAPTION must be set in order + * to for the system menu to appear. + */ + if ((style & SWT.CLOSE) !is 0) style |= SWT.TITLE; + + /* + * Bug in Windows. The WS_CAPTION style must be + * set when the window is resizable or it does not + * draw properly. + */ + /* + * This code is intentionally commented. It seems + * that this problem originally in Windows 3.11, + * has been fixed in later versions. Because the + * exact nature of the drawing problem is unknown, + * keep the commented code around in case it comes + * back. + */ +// if ((style & SWT.RESIZE) !is 0) style |= SWT.TITLE; + + return style; +} + +override void checkBorder () { + /* Do nothing */ +} + +void checkComposited (Composite parent) { + /* Do nothing */ +} + +override void checkOpened () { + if (!opened) resized = false; +} + +override protected void checkSubclass () { + if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); +} + +override override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) { + if (handle is null) return 0; + return OS.DefMDIChildProc (hwnd, msg, wParam, lParam); +} + +void closeWidget () { + Event event = new Event (); + sendEvent (SWT.Close, event); + if (event.doit && !isDisposed ()) dispose (); +} + +int compare (ImageData data1, ImageData data2, int width, int height, int depth) { + int value1 = Math.abs (data1.width - width), value2 = Math.abs (data2.width - width); + if (value1 is value2) { + int transparent1 = data1.getTransparencyType (); + int transparent2 = data2.getTransparencyType (); + if (transparent1 is transparent2) { + if (data1.depth is data2.depth) return 0; + return data1.depth > data2.depth && data1.depth <= depth ? -1 : 1; + } + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (5, 1)) { + if (transparent1 is SWT.TRANSPARENCY_ALPHA) return -1; + if (transparent2 is SWT.TRANSPARENCY_ALPHA) return 1; + } + if (transparent1 is SWT.TRANSPARENCY_MASK) return -1; + if (transparent2 is SWT.TRANSPARENCY_MASK) return 1; + if (transparent1 is SWT.TRANSPARENCY_PIXEL) return -1; + if (transparent2 is SWT.TRANSPARENCY_PIXEL) return 1; + return 0; + } + return value1 < value2 ? -1 : 1; +} + +override Control computeTabGroup () { + return this; +} + +override Control computeTabRoot () { + return this; +} + +override public Rectangle computeTrim (int x, int y, int width, int height) { + checkWidget (); + + /* Get the size of the trimmings */ + RECT rect; + OS.SetRect (&rect, x, y, x + width, y + height); + int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE); + int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE); + bool hasMenu = OS.IsWinCE ? false : OS.GetMenu (handle) !is null; + OS.AdjustWindowRectEx (&rect, bits1, hasMenu, bits2); + + /* Get the size of the scroll bars */ + if (horizontalBar !is null) rect.bottom += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + if (verticalBar !is null) rect.right += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + + /* Compute the height of the menu bar */ + if (hasMenu) { + RECT testRect; + OS.SetRect (&testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, &testRect); + while ((testRect.bottom - testRect.top) < height) { + if (testRect.bottom - testRect.top is 0) break; + rect.top -= OS.GetSystemMetrics (OS.SM_CYMENU) - OS.GetSystemMetrics (OS.SM_CYBORDER); + OS.SetRect (&testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, &testRect); + } + } + return new Rectangle (rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); +} + +void createAccelerators () { + hAccel = null; + nAccel = 0; + int maxAccel = 0; + MenuItem [] items = display.items; + if (menuBar is null || items is null) { + if (!OS.IsPPC) return; + maxAccel = 1; + } else { + maxAccel = OS.IsPPC ? items.length + 1 : items.length; + } + ACCEL accel; + byte [] buffer1 = new byte [ACCEL.sizeof]; + byte [] buffer2 = new byte [maxAccel * ACCEL.sizeof]; + if (menuBar !is null && items !is null) { + for (int i=0; i<items.length; i++) { + MenuItem item = items [i]; + if (item !is null && item.accelerator !is 0) { + Menu menu = item.parent; + if (menu.parent is this) { + while (menu !is null && menu !is menuBar) { + menu = menu.getParentMenu (); + } + if (menu is menuBar && item.fillAccel (&accel)) { + *cast(ACCEL*)buffer1.ptr = accel; + //OS.MoveMemory (buffer1, accel, ACCEL.sizeof); + System.arraycopy (buffer1, 0, buffer2, nAccel * ACCEL.sizeof, ACCEL.sizeof); + nAccel++; + } + } + } + } + } + if (OS.IsPPC) { + /* + * Note on WinCE PPC. Close the shell when user taps CTRL-Q. + * IDOK represents the "Done Button" which also closes the shell. + */ + accel.fVirt = cast(byte) (OS.FVIRTKEY | OS.FCONTROL); + accel.key = cast(short) 'Q'; + accel.cmd = cast(short) OS.IDOK; + *cast(ACCEL*)buffer1.ptr = accel; + //OS.MoveMemory (buffer1, accel, ACCEL.sizeof); + System.arraycopy (buffer1, 0, buffer2, nAccel * ACCEL.sizeof, ACCEL.sizeof); + nAccel++; + } + if (nAccel !is 0) hAccel = OS.CreateAcceleratorTable ( cast(ACCEL*)buffer2.ptr, nAccel); +} + +override void createHandle () { + super.createHandle (); + if (parent !is null || ((style & SWT.TOOL) !is 0)) { + setParent (); + setSystemMenu (); + } +} + +override void createWidget () { + super.createWidget (); + swFlags = OS.IsWinCE ? OS.SW_SHOWMAXIMIZED : OS.SW_SHOWNOACTIVATE; + hAccel = cast(HACCEL)-1; +} + +void destroyAccelerators () { + if (hAccel !is null && hAccel !is cast(HACCEL)-1) OS.DestroyAcceleratorTable (hAccel); + hAccel = cast(HACCEL)-1; +} + +override public void dispose () { + if (isDisposed()) return; + if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); + if (!(cast(Shell)this)) { + if (!traverseDecorations (true)) { + Shell shell = getShell (); + shell.setFocus (); + } + setVisible (false); + } + super.dispose (); +} + +Menu findMenu (HMENU hMenu) { + if (menus is null) return null; + for (int i=0; i<menus.length; i++) { + Menu menu = menus [i]; + if (menu !is null && hMenu is menu.handle) return menu; + } + return null; +} + +void fixDecorations (Decorations newDecorations, Control control, Menu [] menus) { + if (this is newDecorations) return; + if (control is savedFocus) savedFocus = null; + if (control is defaultButton) defaultButton = null; + if (control is saveDefault) saveDefault = null; + if (menus is null) return; + Menu menu = control.menu; + if (menu !is null) { + int index = 0; + while (index <menus.length) { + if (menus [index] is menu) { + control.setMenu (null); + return; + } + index++; + } + menu.fixMenus (newDecorations); + destroyAccelerators (); + newDecorations.destroyAccelerators (); + } +} + +override public Rectangle getBounds () { + checkWidget (); + static if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl; + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, &lpwndpl); + int width = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left; + int height = lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top; + return new Rectangle (lpwndpl.rcNormalPosition.left, lpwndpl.rcNormalPosition.top, width, height); + } + } + return super.getBounds (); +} + +override public Rectangle getClientArea () { + checkWidget (); + /* + * Note: The CommandBar is part of the client area, + * not the trim. Applications don't expect this so + * subtract the height of the CommandBar. + */ + static if (OS.IsHPC) { + Rectangle rect = super.getClientArea (); + if (menuBar !is null) { + auto hwndCB = menuBar.hwndCB; + int height = OS.CommandBar_Height (hwndCB); + rect.y += height; + rect.height = Math.max (0, rect.height - height); + } + return rect; + } + static if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl; + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, &lpwndpl); + int width = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left; + int height = lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top; + /* + * Feature in Windows. For some reason WM_NCCALCSIZE does + * not compute the client area when the window is minimized. + * The fix is to compute it using AdjustWindowRectEx() and + * GetSystemMetrics(). + * + * NOTE: This code fails to compute the correct client area + * for a minimized window where the menu bar would wrap were + * the window restored. There is no fix for this problem at + * this time. + */ + if (horizontalBar !is null) width -= OS.GetSystemMetrics (OS.SM_CYHSCROLL); + if (verticalBar !is null) height -= OS.GetSystemMetrics (OS.SM_CXVSCROLL); + RECT rect; + int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE); + int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE); + bool hasMenu = OS.IsWinCE ? false : OS.GetMenu (handle) !is null; + OS.AdjustWindowRectEx (&rect, bits1, hasMenu, bits2); + width = Math.max (0, width - (rect.right - rect.left)); + height = Math.max (0, height - (rect.bottom - rect.top)); + return new Rectangle (0, 0, width, height); + } + } + return super.getClientArea (); +} + +/** + * Returns the receiver's default button if one had + * previously been set, otherwise returns null. + * + * @return the default button or null + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setDefaultButton(Button) + */ +public Button getDefaultButton () { + checkWidget (); + return defaultButton; +} + +/** + * Returns the receiver's image if it had previously been + * set using <code>setImage()</code>. The image is typically + * displayed by the window manager when the instance is + * marked as iconified, and may also be displayed somewhere + * in the trim when the instance is in normal or maximized + * states. + * <p> + * Note: This method will return null if called before + * <code>setImage()</code> is called. It does not provide + * access to a window manager provided, "default" image + * even if one exists. + * </p> + * + * @return the image + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public Image getImage () { + checkWidget (); + return image; +} + +/** + * Returns the receiver's images if they had previously been + * set using <code>setImages()</code>. Images are typically + * displayed by the window manager when the instance is + * marked as iconified, and may also be displayed somewhere + * in the trim when the instance is in normal or maximized + * states. Depending where the icon is displayed, the platform + * chooses the icon with the "best" attributes. It is expected + * that the array will contain the same icon rendered at different + * sizes, with different depth and transparency attributes. + * + * <p> + * Note: This method will return an empty array if called before + * <code>setImages()</code> is called. It does not provide + * access to a window manager provided, "default" image + * even if one exists. + * </p> + * + * @return the images + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ +public Image [] getImages () { + checkWidget (); + if (images is null) return new Image [0]; + Image [] result = new Image [images.length]; + System.arraycopy (images, 0, result, 0, images.length); + return result; +} + +override public Point getLocation () { + checkWidget (); + static if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl; + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, &lpwndpl); + return new Point (lpwndpl.rcNormalPosition.left, lpwndpl.rcNormalPosition.top); + } + } + return super.getLocation (); +} + +/** + * Returns <code>true</code> if the receiver is currently + * maximized, and false otherwise. + * <p> + * + * @return the maximized state + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setMaximized + */ +public bool getMaximized () { + checkWidget (); + static if (OS.IsWinCE) return swFlags is OS.SW_SHOWMAXIMIZED; + if (OS.IsWindowVisible (handle)) return cast(bool) OS.IsZoomed (handle); + return swFlags is OS.SW_SHOWMAXIMIZED; +} + +/** + * Returns the receiver's menu bar if one had previously + * been set, otherwise returns null. + * + * @return the menu bar or null + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public Menu getMenuBar () { + checkWidget (); + return menuBar; +} + +/** + * Returns <code>true</code> if the receiver is currently + * minimized, and false otherwise. + * <p> + * + * @return the minimized state + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setMinimized + */ +public bool getMinimized () { + checkWidget (); + static if (OS.IsWinCE) return false; + if (OS.IsWindowVisible (handle)) return cast(bool) OS.IsIconic (handle); + return swFlags is OS.SW_SHOWMINNOACTIVE; +} + +override String getNameText () { + return getText (); +} + +override public Point getSize () { + checkWidget (); + static if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl; + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, &lpwndpl); + int width = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left; + int height = lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top; + return new Point (width, height); + } + } + return super.getSize (); +} + +/** + * Returns the receiver's text, which is the string that the + * window manager will typically display as the receiver's + * <em>title</em>. If the text has not previously been set, + * returns an empty string. + * + * @return the text + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public String getText () { + checkWidget (); + int length = OS.GetWindowTextLength (handle); + if (length is 0) return ""; + /* Use the character encoding for the default locale */ + TCHAR[] buffer; + buffer.length = length + 1; + OS.GetWindowText (handle, buffer.ptr, length + 1); + return TCHARsToStr( buffer ); +} + +override public bool isReparentable () { + checkWidget (); + /* + * Feature in Windows. Calling SetParent() for a shell causes + * a kind of fake MDI to happen. It doesn't work well on Windows + * and is not supported on the other platforms. The fix is to + * disallow the SetParent(). + */ + return false; +} + +override bool isTabGroup () { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return true; +} + +override bool isTabItem () { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return false; +} + +override Decorations menuShell () { + return this; +} + +override void releaseChildren (bool destroy) { + if (menuBar !is null) { + menuBar.release (false); + menuBar = null; + } + super.releaseChildren (destroy); + if (menus !is null) { + for (int i=0; i<menus.length; i++) { + Menu menu = menus [i]; + if (menu !is null && !menu.isDisposed ()) { + menu.dispose (); + } + } + menus = null; + } +} + +override void releaseWidget () { + super.releaseWidget (); + if (smallImage !is null) smallImage.dispose (); + if (largeImage !is null) largeImage.dispose (); + smallImage = largeImage = image = null; + images = null; + savedFocus = null; + defaultButton = saveDefault = null; + if (hAccel !is null && hAccel !is cast(HACCEL)-1) OS.DestroyAcceleratorTable (hAccel); + hAccel = cast(HACCEL)-1; +} + +void removeMenu (Menu menu) { + if (menus is null) return; + for (int i=0; i<menus.length; i++) { + if (menus [i] is menu) { + menus [i] = null; + return; + } + } +} + +bool restoreFocus () { + if (display.ignoreRestoreFocus) return true; + if (savedFocus !is null && savedFocus.isDisposed ()) savedFocus = null; + if (savedFocus !is null && savedFocus.setSavedFocus ()) return true; + /* + * This code is intentionally commented. When no widget + * has been given focus, some platforms give focus to the + * default button. Windows doesn't do this. + */ +// if (defaultButton !is null && !defaultButton.isDisposed ()) { +// if (defaultButton.setFocus ()) return true; +// } + return false; +} + +void saveFocus () { + Control control = display._getFocusControl (); + if (control !is null && control !is this && this is control.menuShell ()) { + setSavedFocus (control); + } +} + +override void setBounds (int x, int y, int width, int height, int flags, bool defer) { + static if (OS.IsWinCE) { + swFlags = OS.SW_RESTORE; + } else { + if (OS.IsIconic (handle)) { + setPlacement (x, y, width, height, flags); + return; + } + } + forceResize (); + RECT rect; + OS.GetWindowRect (handle, &rect); + bool sameOrigin = true; + if ((OS.SWP_NOMOVE & flags) is 0) { + sameOrigin = rect.left is x && rect.top is y; + if (!sameOrigin) moved = true; + } + bool sameExtent = true; + if ((OS.SWP_NOSIZE & flags) is 0) { + sameExtent = rect.right - rect.left is width && rect.bottom - rect.top is height; + if (!sameExtent) resized = true; + } + static if (!OS.IsWinCE) { + if (OS.IsZoomed (handle)) { + if (sameOrigin && sameExtent) return; + setPlacement (x, y, width, height, flags); + _setMaximized (false); + return; + } + } + super.setBounds (x, y, width, height, flags, defer); +} + +/** + * If the argument is not null, sets the receiver's default + * button to the argument, and if the argument is null, sets + * the receiver's default button to the first button which + * was set as the receiver's default button (called the + * <em>saved default button</em>). If no default button had + * previously been set, or the saved default button was + * disposed, the receiver's default button will be set to + * null. + * <p> + * The default button is the button that is selected when + * the receiver is active and the user presses ENTER. + * </p> + * + * @param button the new default button + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the button has been disposed</li> + * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setDefaultButton (Button button) { + checkWidget (); + if (button !is null) { + if (button.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); + if (button.menuShell () !is this) error(SWT.ERROR_INVALID_PARENT); + } + setDefaultButton (button, true); +} + +void setDefaultButton (Button button, bool save) { + if (button is null) { + if (defaultButton is saveDefault) { + if (save) saveDefault = null; + return; + } + } else { + if ((button.style & SWT.PUSH) is 0) return; + if (button is defaultButton) return; + } + if (defaultButton !is null) { + if (!defaultButton.isDisposed ()) defaultButton.setDefault (false); + } + if ((defaultButton = button) is null) defaultButton = saveDefault; + if (defaultButton !is null) { + if (!defaultButton.isDisposed ()) defaultButton.setDefault (true); + } + if (save) saveDefault = defaultButton; + if (saveDefault !is null && saveDefault.isDisposed ()) saveDefault = null; +} + +/** + * Sets the receiver's image to the argument, which may + * be null. The image is typically displayed by the window + * manager when the instance is marked as iconified, and + * may also be displayed somewhere in the trim when the + * instance is in normal or maximized states. + * + * @param image the new image (or null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setImage (Image image) { + checkWidget (); + if (image !is null && image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); + this.image = image; + setImages (image, null); +} + +void setImages (Image image, Image [] images) { + /* + * Feature in WinCE. WM_SETICON and WM_GETICON set the icon + * for the window class, not the window instance. This means + * that it is possible to set an icon into a window and then + * later free the icon, thus freeing the icon for every window. + * The fix is to avoid the API. + * + * On WinCE PPC, icons in windows are not displayed. + */ + static if (OS.IsWinCE) return; + if (smallImage !is null) smallImage.dispose (); + if (largeImage !is null) largeImage.dispose (); + smallImage = largeImage = null; + HICON hSmallIcon, hLargeIcon; + Image smallIcon = null, largeIcon = null; + if (image !is null) { + smallIcon = largeIcon = image; + } else { + if (images !is null && images.length > 0) { + int depth = display.getIconDepth (); + ImageData [] datas = null; + if (images.length > 1) { + Image [] bestImages = new Image [images.length]; + System.arraycopy (images, 0, bestImages, 0, images.length); + datas = new ImageData [images.length]; + for (int i=0; i<datas.length; i++) { + datas [i] = images [i].getImageData (); + } + images = bestImages; + sort (images, datas, OS.GetSystemMetrics (OS.SM_CXSMICON), OS.GetSystemMetrics (OS.SM_CYSMICON), depth); + } + smallIcon = images [0]; + if (images.length > 1) { + sort (images, datas, OS.GetSystemMetrics (OS.SM_CXICON), OS.GetSystemMetrics (OS.SM_CYICON), depth); + } + largeIcon = images [0]; + } + } + if (smallIcon !is null) { + switch (smallIcon.type) { + case SWT.BITMAP: + smallImage = Display.createIcon (smallIcon); + hSmallIcon = smallImage.handle; + break; + case SWT.ICON: + hSmallIcon = smallIcon.handle; + break; + default: + } + } + OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_SMALL, hSmallIcon); + if (largeIcon !is null) { + switch (largeIcon.type) { + case SWT.BITMAP: + largeImage = Display.createIcon (largeIcon); + hLargeIcon = largeImage.handle; + break; + case SWT.ICON: + hLargeIcon = largeIcon.handle; + break; + default: + } + } + OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_BIG, hLargeIcon); + + /* + * Bug in Windows. When WM_SETICON is used to remove an + * icon from the window trimmings for a window with the + * extended style bits WS_EX_DLGMODALFRAME, the window + * trimmings do not redraw to hide the previous icon. + * The fix is to force a redraw. + */ + static if (!OS.IsWinCE) { + if (hSmallIcon is null && hLargeIcon is null && (style & SWT.BORDER) !is 0) { + int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE; + OS.RedrawWindow (handle, null, null, flags); + } + } +} + +/** + * Sets the receiver's images to the argument, which may + * be an empty array. Images are typically displayed by the + * window manager when the instance is marked as iconified, + * and may also be displayed somewhere in the trim when the + * instance is in normal or maximized states. Depending where + * the icon is displayed, the platform chooses the icon with + * the "best" attributes. It is expected that the array will + * contain the same icon rendered at different sizes, with + * different depth and transparency attributes. + * + * @param images the new image array + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if one of the images is null or has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.0 + */ +public void setImages (Image [] images) { + checkWidget (); + // SWT extension: allow null array + //if (images is null) error (SWT.ERROR_INVALID_ARGUMENT); + for (int i = 0; i < images.length; i++) { + if (images [i] is null || images [i].isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); + } + this.images = images; + setImages (null, images); +} + +/** + * Sets the maximized state of the receiver. + * If the argument is <code>true</code> causes the receiver + * to switch to the maximized state, and if the argument is + * <code>false</code> and the receiver was previously maximized, + * causes the receiver to switch back to either the minimized + * or normal states. + * <p> + * Note: The result of intermixing calls to <code>setMaximized(true)</code> + * and <code>setMinimized(true)</code> will vary by platform. Typically, + * the behavior will match the platform user's expectations, but not + * always. This should be avoided if possible. + * </p> + * + * @param maximized the new maximized state + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setMinimized + */ +public void setMaximized (bool maximized) { + checkWidget (); + Display.lpStartupInfo = null; + _setMaximized (maximized); +} + +/** + * Sets the receiver's menu bar to the argument, which + * may be null. + * + * @param menu the new menu bar + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li> + * <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setMenuBar (Menu menu) { + checkWidget (); + if (menuBar is menu) return; + if (menu !is null) { + if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); + if ((menu.style & SWT.BAR) is 0) error (SWT.ERROR_MENU_NOT_BAR); + if (menu.parent !is this) error (SWT.ERROR_INVALID_PARENT); + } + static if (OS.IsWinCE) { + if (OS.IsHPC) { + bool resize = menuBar !is menu; + if (menuBar !is null) OS.CommandBar_Show (menuBar.hwndCB, false); + menuBar = menu; + if (menuBar !is null) OS.CommandBar_Show (menuBar.hwndCB, true); + if (resize) { + sendEvent (SWT.Resize); + if (isDisposed ()) return; + if (layout !is null) { + markLayout (false, false); + updateLayout (true, false); + } + } + } else { + if (OS.IsPPC) { + /* + * Note in WinCE PPC. The menu bar is a separate popup window. + * If the shell is full screen, resize its window to leave + * space for the menu bar. + */ + bool resize = getMaximized () && menuBar !is menu; + if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE); + menuBar = menu; + if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW); + if (resize) _setMaximized (true); + } + if (OS.IsSP) { + if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE); + menuBar = menu; + if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW); + } + } + } else { + if (menu !is null) display.removeBar (menu); + menuBar = menu; + auto hMenu = menuBar !is null ? menuBar.handle: null; + OS.SetMenu (handle, hMenu); + } + destroyAccelerators (); +} + +/** + * Sets the minimized stated of the receiver. + * If the argument is <code>true</code> causes the receiver + * to switch to the minimized state, and if the argument is + * <code>false</code> and the receiver was previously minimized, + * causes the receiver to switch back to either the maximized + * or normal states. + * <p> + * Note: The result of intermixing calls to <code>setMaximized(true)</code> + * and <code>setMinimized(true)</code> will vary by platform. Typically, + * the behavior will match the platform user's expectations, but not + * always. This should be avoided if possible. + * </p> + * + * @param minimized the new maximized state + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setMaximized + */ +public void setMinimized (bool minimized) { + checkWidget (); + Display.lpStartupInfo = null; + _setMinimized (minimized); +} + +void setParent () { + /* + * In order for an MDI child window to support + * a menu bar, setParent () is needed to reset + * the parent. Otherwise, the MDI child window + * will appear as a separate shell. This is an + * undocumented and possibly dangerous Windows + * feature. + */ + auto hwndParent = parent.handle; + display.lockActiveWindow = true; + OS.SetParent (handle, hwndParent); + if (!OS.IsWindowVisible (hwndParent)) { + OS.ShowWindow (handle, OS.SW_SHOWNA); + } + int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); + bits &= ~OS.WS_CHILD; + OS.SetWindowLong (handle, OS.GWL_STYLE, bits | OS.WS_POPUP); + OS.SetWindowLongPtr (handle, OS.GWLP_ID, 0); + int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE; + SetWindowPos (handle, cast(HWND)OS.HWND_BOTTOM, 0, 0, 0, 0, flags); + display.lockActiveWindow = false; +} + +void setPlacement (int x, int y, int width, int height, int flags) { + WINDOWPLACEMENT lpwndpl; + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, &lpwndpl); + lpwndpl.showCmd = OS.SW_SHOWNA; + if (OS.IsIconic (handle)) { + lpwndpl.showCmd = OS.SW_SHOWMINNOACTIVE; + } else { + if (OS.IsZoomed (handle)) { + lpwndpl.showCmd = OS.SW_SHOWMAXIMIZED; + } + } + bool sameOrigin = true; + if ((flags & OS.SWP_NOMOVE) is 0) { + sameOrigin = lpwndpl.rcNormalPosition.left !is x || lpwndpl.rcNormalPosition.top !is y; + lpwndpl.rcNormalPosition.right = x + (lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left); + lpwndpl.rcNormalPosition.bottom = y + (lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top); + lpwndpl.rcNormalPosition.left = x; + lpwndpl.rcNormalPosition.top = y; + } + bool sameExtent = true; + if ((flags & OS.SWP_NOSIZE) is 0) { + sameExtent = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left !is width || lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top !is height; + lpwndpl.rcNormalPosition.right = lpwndpl.rcNormalPosition.left + width; + lpwndpl.rcNormalPosition.bottom = lpwndpl.rcNormalPosition.top + height; + } + OS.SetWindowPlacement (handle, &lpwndpl); + if (OS.IsIconic (handle)) { + if (sameOrigin) { + moved = true; + Point location = getLocation (); + oldX = location.x; + oldY = location.y; + sendEvent (SWT.Move); + if (isDisposed ()) return; + } + if (sameExtent) { + resized = true; + Rectangle rect = getClientArea (); + oldWidth = rect.width; + oldHeight = rect.height; + sendEvent (SWT.Resize); + if (isDisposed ()) return; + if (layout_ !is null) { + markLayout (false, false); + updateLayout (true, false); + } + } + } +} + +void setSavedFocus (Control control) { + savedFocus = control; +} + +void setSystemMenu () { + static if (OS.IsWinCE) return; + auto hMenu = OS.GetSystemMenu (handle, false); + if (hMenu is null) return; + int oldCount = OS.GetMenuItemCount (hMenu); + if ((style & SWT.RESIZE) is 0) { + OS.DeleteMenu (hMenu, OS.SC_SIZE, OS.MF_BYCOMMAND); + } + if ((style & SWT.MIN) is 0) { + OS.DeleteMenu (hMenu, OS.SC_MINIMIZE, OS.MF_BYCOMMAND); + } + if ((style & SWT.MAX) is 0) { + OS.DeleteMenu (hMenu, OS.SC_MAXIMIZE, OS.MF_BYCOMMAND); + } + if ((style & (SWT.MIN | SWT.MAX)) is 0) { + OS.DeleteMenu (hMenu, OS.SC_RESTORE, OS.MF_BYCOMMAND); + } + int newCount = OS.GetMenuItemCount (hMenu); + if ((style & SWT.CLOSE) is 0 || newCount !is oldCount) { + OS.DeleteMenu (hMenu, OS.SC_TASKLIST, OS.MF_BYCOMMAND); + MENUITEMINFO info; + info.cbSize = OS.MENUITEMINFO_sizeof; + info.fMask = OS.MIIM_ID; + int index = 0; + while (index < newCount) { + if (OS.GetMenuItemInfo (hMenu, index, true, &info)) { + if (info.wID is OS.SC_CLOSE) break; + } + index++; + } + if (index !is newCount) { + OS.DeleteMenu (hMenu, index - 1, OS.MF_BYPOSITION); + if ((style & SWT.CLOSE) is 0) { + OS.DeleteMenu (hMenu, OS.SC_CLOSE, OS.MF_BYCOMMAND); + } + } + } +} + +/** + * Sets the receiver's text, which is the string that the + * window manager will typically display as the receiver's + * <em>title</em>, to the argument, which must not be null. + * + * @param string the new text + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setText (String string) { + checkWidget (); + // SWT extension: allow null string + //if (string is null) error (SWT.ERROR_NULL_ARGUMENT); + /* Use the character encoding for the default locale */ + TCHAR[] buffer = StrToTCHARs (string, true); + /* Ensure that the title appears in the task bar.*/ + if ((state & FOREIGN_HANDLE) !is 0) { + auto hHeap = OS.GetProcessHeap (); + int byteCount = buffer.length * TCHAR.sizeof; + auto pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory (pszText, buffer.ptr, byteCount); + OS.DefWindowProc (handle, OS.WM_SETTEXT, 0, cast(int) pszText); + if (pszText !is null) OS.HeapFree (hHeap, 0, pszText); + } else { + OS.SetWindowText (handle, buffer.ptr); + } +} + +override 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; + } + if (visible) { + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in the show + * event. If this happens, just return. + */ + sendEvent (SWT.Show); + if (isDisposed ()) return; + static if (OS.IsHPC) { + if (menuBar !is null) { + auto hwndCB = menuBar.hwndCB; + OS.CommandBar_DrawMenuBar (hwndCB, 0); + } + } + if (drawCount !is 0) { + state &= ~HIDDEN; + } else { + static if (OS.IsWinCE) { + OS.ShowWindow (handle, OS.SW_SHOW); + } else { + if (menuBar !is null) { + display.removeBar (menuBar); + OS.DrawMenuBar (handle); + } + STARTUPINFO* lpStartUpInfo = Display.lpStartupInfo; + if (lpStartUpInfo !is null && (lpStartUpInfo.dwFlags & OS.STARTF_USESHOWWINDOW) !is 0) { + OS.ShowWindow (handle, lpStartUpInfo.wShowWindow); + } else { + OS.ShowWindow (handle, swFlags); + } + } + if (isDisposed ()) return; + opened = true; + if (!moved) { + moved = true; + Point location = getLocation (); + oldX = location.x; + oldY = location.y; + } + if (!resized) { + resized = true; + Rectangle rect = getClientArea (); + oldWidth = rect.width; + oldHeight = rect.height; + } + /* + * Bug in Windows. On Vista using the Classic theme, + * when the window is hung and UpdateWindow() is called, + * nothing is drawn, and outstanding WM_PAINTs are cleared. + * This causes pixel corruption. The fix is to avoid calling + * update on hung windows. + */ + bool update = true; + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0) && !OS.IsAppThemed ()) { + update = !OS.IsHungAppWindow (handle); + } + if (update) OS.UpdateWindow (handle); + } + } else { + static if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + swFlags = OS.SW_SHOWMINNOACTIVE; + } else { + if (OS.IsZoomed (handle)) { + swFlags = OS.SW_SHOWMAXIMIZED; + } else { + swFlags = OS.SW_SHOWNOACTIVATE; + } + } + } + if (drawCount !is 0) { + state |= HIDDEN; + } else { + OS.ShowWindow (handle, OS.SW_HIDE); + } + if (isDisposed ()) return; + sendEvent (SWT.Hide); + } +} + +void sort (Image [] images, ImageData [] datas, int width, int height, int depth) { + /* Shell Sort from K&R, pg 108 */ + int length = images.length; + if (length <= 1) return; + for (int gap=length/2; gap>0; gap/=2) { + for (int i=gap; i<length; i++) { + for (int j=i-gap; j>=0; j-=gap) { + if (compare (datas [j], datas [j + gap], width, height, depth) >= 0) { + Image swap = images [j]; + images [j] = images [j + gap]; + images [j + gap] = swap; + ImageData swapData = datas [j]; + datas [j] = datas [j + gap]; + datas [j + gap] = swapData; + } + } + } + } +} + +override bool translateAccelerator (MSG* msg) { + if (!isEnabled () || !isActive ()) return false; + if (menuBar !is null && !menuBar.isEnabled ()) return false; + if (translateMDIAccelerator (msg) || translateMenuAccelerator (msg)) return true; + Decorations decorations = parent.menuShell (); + return decorations.translateAccelerator (msg); +} + +bool translateMenuAccelerator (MSG* msg) { + if (hAccel is cast(HACCEL)-1) createAccelerators (); + return hAccel !is null && OS.TranslateAccelerator (handle, hAccel, msg) !is 0; +} + +bool translateMDIAccelerator (MSG* msg) { + if (!(cast(Shell)this)) { + Shell shell = getShell (); + auto hwndMDIClient = shell.hwndMDIClient_; + if (hwndMDIClient !is null && OS.TranslateMDISysAccel (hwndMDIClient, msg)) { + return true; + } + if (msg.message is OS.WM_KEYDOWN) { + if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return false; + switch ((msg.wParam)) { + case OS.VK_F4: + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); + return true; + case OS.VK_F6: + if (traverseDecorations (true)) return true; + default: + } + return false; + } + if (msg.message is OS.WM_SYSKEYDOWN) { + switch ((msg.wParam)) { + case OS.VK_F4: + OS.PostMessage (shell.handle, OS.WM_CLOSE, 0, 0); + return true; + default: + } + return false; + } + } + return false; +} + +bool traverseDecorations (bool next) { + Control [] children = parent._getChildren (); + int length = children.length; + int index = 0; + while (index < length) { + if (children [index] is this) break; + index++; + } + /* + * It is possible (but unlikely), that application + * code could have disposed the widget in focus in + * or out events. Ensure that a disposed widget is + * not accessed. + */ + int start = index, offset = (next) ? 1 : -1; + while ((index = (index + offset + length) % length) !is start) { + Control child = children [index]; + if (!child.isDisposed () && ( null !is cast(Decorations)child)) { + if (child.setFocus ()) return true; + } + } + return false; +} + +override bool traverseItem (bool next) { + return false; +} + +override bool traverseReturn () { + if (defaultButton is null || defaultButton.isDisposed ()) return false; + if (!defaultButton.isVisible () || !defaultButton.isEnabled ()) return false; + defaultButton.click (); + return true; +} + +override CREATESTRUCT* widgetCreateStruct () { + return new CREATESTRUCT (); +} + +override int widgetExtStyle () { + int bits = super.widgetExtStyle () | OS.WS_EX_MDICHILD; + bits &= ~OS.WS_EX_CLIENTEDGE; + if ((style & SWT.NO_TRIM) !is 0) return bits; + if (OS.IsPPC) { + if ((style & SWT.CLOSE) !is 0) bits |= OS.WS_EX_CAPTIONOKBTN; + } + if ((style & SWT.RESIZE) !is 0) return bits; + if ((style & SWT.BORDER) !is 0) bits |= OS.WS_EX_DLGMODALFRAME; + return bits; +} + +override HWND widgetParent () { + Shell shell = getShell (); + return shell.hwndMDIClient (); +} + +override int widgetStyle () { + /* + * Clear WS_VISIBLE and WS_TABSTOP. NOTE: In Windows, WS_TABSTOP + * has the same value as WS_MAXIMIZEBOX so these bits cannot be + * used to control tabbing. + */ + int bits = super.widgetStyle () & ~(OS.WS_TABSTOP | OS.WS_VISIBLE); + + /* Set the title bits and no-trim bits */ + bits &= ~OS.WS_BORDER; + if ((style & SWT.NO_TRIM) !is 0) return bits; + if ((style & SWT.TITLE) !is 0) bits |= OS.WS_CAPTION; + + /* Set the min and max button bits */ + if ((style & SWT.MIN) !is 0) bits |= OS.WS_MINIMIZEBOX; + if ((style & SWT.MAX) !is 0) bits |= OS.WS_MAXIMIZEBOX; + + /* Set the resize, dialog border or border bits */ + if ((style & SWT.RESIZE) !is 0) { + /* + * Note on WinCE PPC. SWT.RESIZE is used to resize + * the Shell according to the state of the IME. + * It does not set the WS_THICKFRAME style. + */ + if (!OS.IsPPC) bits |= OS.WS_THICKFRAME; + } else { + if ((style & SWT.BORDER) is 0) bits |= OS.WS_BORDER; + } + + /* Set the system menu and close box bits */ + if (!OS.IsPPC && !OS.IsSP) { + if ((style & SWT.CLOSE) !is 0) bits |= OS.WS_SYSMENU; + } + + return bits; +} + +override int windowProc (HWND hwnd, int msg, int wParam, int lParam) { + switch (msg) { + case Display.SWT_GETACCEL: + case Display.SWT_GETACCELCOUNT: + if (hAccel is cast(HACCEL)-1) createAccelerators (); + return msg is Display.SWT_GETACCELCOUNT ? nAccel : cast(int)hAccel; + default: + } + return super.windowProc (hwnd, msg, wParam, lParam); +} + +override LRESULT WM_ACTIVATE (int wParam, int lParam) { + LRESULT result = super.WM_ACTIVATE (wParam, lParam); + if (result !is null) return result; + /* + * Feature in AWT. When an AWT Window is activated, + * for some reason, it seems to forward the WM_ACTIVATE + * message to the parent. Normally, the parent is an + * AWT Frame. When AWT is embedded in SWT, the SWT + * shell gets the WM_ACTIVATE and assumes that it came + * from Windows. When an SWT shell is activated it + * restores focus to the last control that had focus. + * If this control is an embedded composite, it takes + * focus from the AWT Window. The fix is to ignore + * WM_ACTIVATE messages that come from AWT Windows. + */ + if (OS.GetParent ( cast(HWND)lParam) is handle) { + TCHAR[128] buffer = 0; + OS.GetClassName (cast(HWND)lParam, buffer.ptr, buffer.length ); + String className = TCHARzToStr( buffer.ptr ); + if (className == Display.AWT_WINDOW_CLASS) { + return LRESULT.ZERO; + } + } + if (OS.LOWORD (wParam) !is 0) { + /* + * When the high word of wParam is non-zero, the activation + * state of the window is being changed while the window is + * minimized. If this is the case, do not report activation + * events or restore the focus. + */ + if (OS.HIWORD (wParam) !is 0) return result; + Control control = display.findControl (cast(HWND)lParam); + if (control is null || (null !is cast(Shell)control)) { + if (cast(Shell)this) { + sendEvent (SWT.Activate); + if (isDisposed ()) return LRESULT.ZERO; + } + } + if (restoreFocus ()) return LRESULT.ZERO; + } else { + Display display = this.display; + bool lockWindow = display.isXMouseActive (); + if (lockWindow) display.lockActiveWindow = true; + Control control = display.findControl (cast(HWND)lParam); + if (control is null || (null !is cast(Shell)control)) { + if (cast(Shell)this) { + sendEvent (SWT.Deactivate); + if (!isDisposed ()) { + Shell shell = getShell (); + shell.setActiveControl (null); + // widget could be disposed at this point + } + } + } + if (lockWindow) display.lockActiveWindow = false; + if (isDisposed ()) return LRESULT.ZERO; + saveFocus (); + } + return result; +} + +override LRESULT WM_CLOSE (int wParam, int lParam) { + LRESULT result = super.WM_CLOSE (wParam, lParam); + if (result !is null) return result; + if (isEnabled () && isActive ()) closeWidget (); + return LRESULT.ZERO; +} + +override LRESULT WM_HOTKEY (int wParam, int lParam) { + LRESULT result = super.WM_HOTKEY (wParam, lParam); + if (result !is null) return result; + static if( OS.IsWinCE ){ + if (OS.IsSP) { + /* + * Feature on WinCE SP. The Back key is either used to close + * the foreground Dialog or used as a regular Back key in an EDIT + * control. The article 'Back Key' in MSDN for Smartphone + * describes how an application should handle it. The + * workaround is to override the Back key when creating + * the menubar and handle it based on the style of the Shell. + * If the Shell has the SWT.CLOSE style, close the Shell. + * Otherwise, send the Back key to the window with focus. + */ + if (OS.HIWORD (lParam) is OS.VK_ESCAPE) { + if ((style & SWT.CLOSE) !is 0) { + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); + } else { + OS.SHSendBackToFocusWindow (OS.WM_HOTKEY, wParam, lParam); + } + return LRESULT.ZERO; + } + } + } + return result; +} + +override LRESULT WM_KILLFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_KILLFOCUS (wParam, lParam); + saveFocus (); + return result; +} + +override LRESULT WM_MOVE (int wParam, int lParam) { + if (moved) { + Point location = getLocation (); + if (location.x is oldX && location.y is oldY) { + return null; + } + oldX = location.x; + oldY = location.y; + } + return super.WM_MOVE (wParam, lParam); +} + +override LRESULT WM_NCACTIVATE (int wParam, int lParam) { + LRESULT result = super.WM_NCACTIVATE (wParam, lParam); + if (result !is null) return result; + if (wParam is 0) { + if (display.lockActiveWindow) return LRESULT.ZERO; + Control control = display.findControl (cast(HANDLE)lParam); + if (control !is null) { + Shell shell = getShell (); + Decorations decorations = control.menuShell (); + if (decorations.getShell () is shell) { + if (cast(Shell)this) return LRESULT.ONE; + if (display.ignoreRestoreFocus) { + if (display.lastHittest !is OS.HTCLIENT) { + result = LRESULT.ONE; + } + } + } + } + } + if (!(cast(Shell)this)) { + auto hwndShell = getShell().handle; + OS.SendMessage (hwndShell, OS.WM_NCACTIVATE, wParam, lParam); + } + return result; +} + +override LRESULT WM_QUERYOPEN (int wParam, int lParam) { + LRESULT result = super.WM_QUERYOPEN (wParam, lParam); + if (result !is null) return result; + sendEvent (SWT.Deiconify); + // widget could be disposed at this point + return result; +} + +override LRESULT WM_SETFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + if (savedFocus !is this) restoreFocus (); + return result; +} + +override LRESULT WM_SIZE (int wParam, int lParam) { + LRESULT result = null; + bool changed = true; + if (resized) { + int newWidth = 0, newHeight = 0; + switch (wParam) { + case OS.SIZE_RESTORED: + case OS.SIZE_MAXIMIZED: + newWidth = OS.LOWORD (lParam); + newHeight = OS.HIWORD (lParam); + break; + case OS.SIZE_MINIMIZED: + Rectangle rect = getClientArea (); + newWidth = rect.width; + newHeight = rect.height; + break; + default: + } + changed = newWidth !is oldWidth || newHeight !is oldHeight; + if (changed) { + oldWidth = newWidth; + oldHeight = newHeight; + } + } + if (changed) { + result = super.WM_SIZE (wParam, lParam); + if (isDisposed ()) return result; + } + if (wParam is OS.SIZE_MINIMIZED) { + sendEvent (SWT.Iconify); + // widget could be disposed at this point + } + return result; +} + +override LRESULT WM_SYSCOMMAND (int wParam, int lParam) { + LRESULT result = super.WM_SYSCOMMAND (wParam, lParam); + if (result !is null) return result; + if (!(cast(Shell)this)) { + int cmd = wParam & 0xFFF0; + switch (cmd) { + case OS.SC_CLOSE: { + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); + return LRESULT.ZERO; + } + case OS.SC_NEXTWINDOW: { + traverseDecorations (true); + return LRESULT.ZERO; + } + default: + } + } + return result; +} + +override LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) { + LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam); + if (result !is null) return result; + if (display.lockActiveWindow) { + WINDOWPOS* lpwp = cast(WINDOWPOS*)lParam; + //OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof); + lpwp.flags |= OS.SWP_NOZORDER; + //OS.MoveMemory (lParam, &lpwp, WINDOWPOS.sizeof); + } + return result; +} + +}