Mercurial > projects > dwt-win
diff dwt/widgets/Decorations.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/Decorations.d Mon Jan 28 04:47:28 2008 +0100 @@ -0,0 +1,1824 @@ +/******************************************************************************* + * 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 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwt.widgets.Decorations; + +import dwt.widgets.Canvas; +class Decorations : Canvas { +} +/++ +import dwt.DWT; +import dwt.DWTException; +import dwt.graphics.Image; +import dwt.graphics.ImageData; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.internal.win32.ACCEL; +import dwt.internal.win32.CREATESTRUCT; +import dwt.internal.win32.LRESULT; +import dwt.internal.win32.MENUITEMINFO; +import dwt.internal.win32.MSG; +import dwt.internal.win32.OS; +import dwt.internal.win32.RECT; +import dwt.internal.win32.STARTUPINFO; +import dwt.internal.win32.TCHAR; +import dwt.internal.win32.WINDOWPLACEMENT; +import dwt.internal.win32.WINDOWPOS; + +/** + * 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>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> + * IMPORTANT: This class is intended to be subclassed <em>only</em> + * within the DWT implementation. + * </p> + * + * @see #getMinimized + * @see #getMaximized + * @see Shell + * @see DWT + */ + +public class Decorations extends Canvas { + Image image, smallImage, largeImage; + Image [] images; + Menu menuBar; + Menu [] menus; + Control savedFocus; + Button defaultButton, saveDefault; + int swFlags, hAccel, 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. + */ +Decorations () { +} + +/** + * 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> + * + * @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 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 Widget#checkSubclass + * @see Widget#getStyle + */ +public Decorations (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +void _setMaximized (bool maximized) { + swFlags = maximized ? OS.SW_SHOWMAXIMIZED : OS.SW_RESTORE; + 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 = new 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) { + int hwndCB = menuBar.hwndCB; + RECT rectCB = new RECT (); + OS.GetWindowRect (hwndCB, rectCB); + height -= rectCB.bottom - rectCB.top; + } + } + int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE; + SetWindowPos (handle, 0, 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) { + 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 & DWT.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 & DWT.NO_TRIM) !is 0) { + style &= ~(DWT.CLOSE | DWT.TITLE | DWT.MIN | DWT.MAX | DWT.RESIZE | DWT.BORDER); + } + 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 & DWT.MIN) !is 0) style &= ~DWT.MIN; + if ((style & DWT.MAX) !is 0) style &= ~DWT.MAX; + return style; + } + if ((style & (DWT.MENU | DWT.MIN | DWT.MAX | DWT.CLOSE)) !is 0) { + style |= DWT.TITLE; + } + + /* + * If either WS_MINIMIZEBOX or WS_MAXIMIZEBOX are set, + * we must also set WS_SYSMENU or the buttons will not + * appear. + */ + if ((style & (DWT.MIN | DWT.MAX)) !is 0) style |= DWT.CLOSE; + + /* + * Both WS_SYSMENU and WS_CAPTION must be set in order + * to for the system menu to appear. + */ + if ((style & DWT.CLOSE) !is 0) style |= DWT.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 & DWT.RESIZE) !is 0) style |= DWT.TITLE; + + return style; +} + +void checkBorder () { + /* Do nothing */ +} + +void checkOpened () { + if (!opened) resized = false; +} + +protected void checkSubclass () { + if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS); +} + +int callWindowProc (int hwnd, int msg, int wParam, int lParam) { + if (handle is 0) return 0; + return OS.DefMDIChildProc (hwnd, msg, wParam, lParam); +} + +void closeWidget () { + Event event = new Event (); + sendEvent (DWT.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 DWT.TRANSPARENCY_ALPHA) return -1; + if (transparent2 is DWT.TRANSPARENCY_ALPHA) return 1; + } + if (transparent1 is DWT.TRANSPARENCY_MASK) return -1; + if (transparent2 is DWT.TRANSPARENCY_MASK) return 1; + if (transparent1 is DWT.TRANSPARENCY_PIXEL) return -1; + if (transparent2 is DWT.TRANSPARENCY_PIXEL) return 1; + return 0; + } + return value1 < value2 ? -1 : 1; +} + +Control computeTabGroup () { + return this; +} + +Control computeTabRoot () { + return this; +} + +public Rectangle computeTrim (int x, int y, int width, int height) { + checkWidget (); + + /* Get the size of the trimmings */ + RECT rect = new 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 0; + 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 = new RECT (); + 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 = 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 = new 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); + 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 = (byte) (OS.FVIRTKEY | OS.FCONTROL); + accel.key = (short) 'Q'; + accel.cmd = (short) OS.IDOK; + OS.MoveMemory (buffer1, accel, ACCEL.sizeof); + System.arraycopy (buffer1, 0, buffer2, nAccel * ACCEL.sizeof, ACCEL.sizeof); + nAccel++; + } + if (nAccel !is 0) hAccel = OS.CreateAcceleratorTable (buffer2, nAccel); +} + +void createHandle () { + super.createHandle (); + if (parent !is null || ((style & DWT.TOOL) !is 0)) { + setParent (); + setSystemMenu (); + } + /* + * Set the default icon for the shell to IDI_APPLICATION. + * This is not necessary for native applications but later + * versions of Java set the icon in javaw.exe instead of + * leaving the default. + * + * NOTE: The icon is not leaked. It is shared within + * the process by all threads and is released when the + * process exits. + */ + if ((state & FOREIGN_HANDLE) is 0) { + if (!OS.IsWinCE) { + int hIcon = OS.LoadIcon (0, OS.IDI_APPLICATION); + OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_SMALL, hIcon); + } + } +} + +void createWidget () { + super.createWidget (); + swFlags = OS.IsWinCE ? OS.SW_SHOWMAXIMIZED : OS.SW_SHOWNOACTIVATE; + hAccel = -1; +} + +void destroyAccelerators () { + if (hAccel !is 0 && hAccel !is -1) OS.DestroyAcceleratorTable (hAccel); + hAccel = -1; +} + +public void dispose () { + if (isDisposed()) return; + if (!isValidThread ()) error (DWT.ERROR_THREAD_INVALID_ACCESS); + if (!(this instanceof Shell)) { + if (!traverseDecorations (true)) { + Shell shell = getShell (); + shell.setFocus (); + } + setVisible (false); + } + super.dispose (); +} + +Menu findMenu (int 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 (); + } +} + +public Rectangle getBounds () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + int width = lpwndpl.right - lpwndpl.left; + int height = lpwndpl.bottom - lpwndpl.top; + return new Rectangle (lpwndpl.left, lpwndpl.top, width, height); + } + } + return super.getBounds (); +} + +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. + */ + if (OS.IsHPC) { + Rectangle rect = super.getClientArea (); + if (menuBar !is null) { + int hwndCB = menuBar.hwndCB; + int height = OS.CommandBar_Height (hwndCB); + rect.y += height; + rect.height = Math.max (0, rect.height - height); + } + return rect; + } + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + int width = lpwndpl.right - lpwndpl.left; + int height = lpwndpl.bottom - lpwndpl.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 = new 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 0; + 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 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 #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 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 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 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 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; +} + +public Point getLocation () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + return new Point (lpwndpl.left, lpwndpl.top); + } + } + return super.getLocation (); +} + +/** + * Returns <code>true</code> if the receiver is currently + * maximized, and false otherwise. + * <p> + * + * @return the maximized state + * + * @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 #setMaximized + */ +public bool getMaximized () { + checkWidget (); + if (OS.IsWinCE) return swFlags is OS.SW_SHOWMAXIMIZED; + if (OS.IsWindowVisible (handle)) return 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 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 Menu getMenuBar () { + checkWidget (); + return menuBar; +} + +/** + * Returns <code>true</code> if the receiver is currently + * minimized, and false otherwise. + * <p> + * + * @return the minimized state + * + * @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 #setMinimized + */ +public bool getMinimized () { + checkWidget (); + if (OS.IsWinCE) return false; + if (OS.IsWindowVisible (handle)) return OS.IsIconic (handle); + return swFlags is OS.SW_SHOWMINNOACTIVE; +} + +String getNameText () { + return getText (); +} + +public Point getSize () { + checkWidget (); + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT (); + lpwndpl.length = WINDOWPLACEMENT.sizeof; + OS.GetWindowPlacement (handle, lpwndpl); + int width = lpwndpl.right - lpwndpl.left; + int height = lpwndpl.bottom - lpwndpl.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 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 String getText () { + checkWidget (); + int length = OS.GetWindowTextLength (handle); + if (length is 0) return ""; + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, length + 1); + OS.GetWindowText (handle, buffer, length + 1); + return buffer.toString (0, length); +} + +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; +} + +bool isTabGroup () { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return true; +} + +bool isTabItem () { + /* + * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX. + */ + return false; +} + +Decorations menuShell () { + return this; +} + +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; + } +} + +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 0 && hAccel !is -1) OS.DestroyAcceleratorTable (hAccel); + 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); + } +} + +void setBounds (int x, int y, int width, int height, int flags, bool defer) { + if (OS.IsWinCE) { + swFlags = OS.SW_RESTORE; + } else { + if (OS.IsIconic (handle)) { + setPlacement (x, y, width, height, flags); + return; + } + } + forceResize (); + RECT rect = new 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; + } + 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 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 void setDefaultButton (Button button) { + checkWidget (); + if (button !is null) { + if (button.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT); + if (button.menuShell () !is this) error(DWT.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 & DWT.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 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 void setImage (Image image) { + checkWidget (); + if (image !is null && image.isDisposed ()) error (DWT.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. + */ + if (OS.IsWinCE) return; + if (smallImage !is null) smallImage.dispose (); + if (largeImage !is null) largeImage.dispose (); + smallImage = largeImage = null; + int hSmallIcon = 0, hLargeIcon = 0; + 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 DWT.BITMAP: + smallImage = Display.createIcon (smallIcon); + hSmallIcon = smallImage.handle; + break; + case DWT.ICON: + hSmallIcon = smallIcon.handle; + break; + } + } else { + /* + * Set the default icon for the shell to IDI_APPLICATION. + * This is not necessary for native applications but later + * versions of Java set the icon in javaw.exe instead of + * leaving the default. + * + * NOTE: The icon is not leaked. It is shared within + * the process by all threads and is released when the + * process exits. + */ + if ((state & FOREIGN_HANDLE) is 0) { + hSmallIcon = OS.LoadIcon (0, OS.IDI_APPLICATION); + } + } + OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_SMALL, hSmallIcon); + if (largeIcon !is null) { + switch (largeIcon.type) { + case DWT.BITMAP: + largeImage = Display.createIcon (largeIcon); + hLargeIcon = largeImage.handle; + break; + case DWT.ICON: + hLargeIcon = largeIcon.handle; + break; + } + } + 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. + */ + if (!OS.IsWinCE) { + if (hSmallIcon is 0 && hLargeIcon is 0 && (style & DWT.BORDER) !is 0) { + int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE; + OS.RedrawWindow (handle, null, 0, 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_NULL_ARGUMENT - if the array of images is null</li> + * <li>ERROR_INVALID_ARGUMENT - if one of the images is null or 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 setImages (Image [] images) { + checkWidget (); + if (images is null) error (DWT.ERROR_INVALID_ARGUMENT); + for (int i = 0; i < images.length; i++) { + if (images [i] is null || images [i].isDisposed ()) error (DWT.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 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 #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 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 void setMenuBar (Menu menu) { + checkWidget (); + if (menuBar is menu) return; + if (menu !is null) { + if (menu.isDisposed()) error(DWT.ERROR_INVALID_ARGUMENT); + if ((menu.style & DWT.BAR) is 0) error (DWT.ERROR_MENU_NOT_BAR); + if (menu.parent !is this) error (DWT.ERROR_INVALID_PARENT); + } + 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 (DWT.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; + int hMenu = menuBar !is null ? menuBar.handle: 0; + 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 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 #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. + */ + int 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.SetWindowLong (handle, OS.GWL_ID, 0); + int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE; + SetWindowPos (handle, 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 = new WINDOWPLACEMENT (); + 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.left !is x || lpwndpl.top !is y; + lpwndpl.right = x + (lpwndpl.right - lpwndpl.left); + lpwndpl.bottom = y + (lpwndpl.bottom - lpwndpl.top); + lpwndpl.left = x; + lpwndpl.top = y; + } + bool sameExtent = true; + if ((flags & OS.SWP_NOSIZE) is 0) { + sameExtent = lpwndpl.right - lpwndpl.left !is width || lpwndpl.bottom - lpwndpl.top !is height; + lpwndpl.right = lpwndpl.left + width; + lpwndpl.bottom = lpwndpl.top + height; + } + OS.SetWindowPlacement (handle, lpwndpl); + if (OS.IsIconic (handle)) { + if (sameOrigin) { + moved = true; + Point location = getLocation (); + oldX = location.x; + oldY = location.y; + sendEvent (DWT.Move); + if (isDisposed ()) return; + } + if (sameExtent) { + resized = true; + Rectangle rect = getClientArea (); + oldWidth = rect.width; + oldHeight = rect.height; + sendEvent (DWT.Resize); + if (isDisposed ()) return; + if (layout !is null) { + markLayout (false, false); + updateLayout (true, false); + } + } + } +} + +void setSavedFocus (Control control) { + savedFocus = control; +} + +void setSystemMenu () { + if (OS.IsWinCE) return; + int hMenu = OS.GetSystemMenu (handle, false); + if (hMenu is 0) return; + int oldCount = OS.GetMenuItemCount (hMenu); + if ((style & DWT.RESIZE) is 0) { + OS.DeleteMenu (hMenu, OS.SC_SIZE, OS.MF_BYCOMMAND); + } + if ((style & DWT.MIN) is 0) { + OS.DeleteMenu (hMenu, OS.SC_MINIMIZE, OS.MF_BYCOMMAND); + } + if ((style & DWT.MAX) is 0) { + OS.DeleteMenu (hMenu, OS.SC_MAXIMIZE, OS.MF_BYCOMMAND); + } + if ((style & (DWT.MIN | DWT.MAX)) is 0) { + OS.DeleteMenu (hMenu, OS.SC_RESTORE, OS.MF_BYCOMMAND); + } + int newCount = OS.GetMenuItemCount (hMenu); + if ((style & DWT.CLOSE) is 0 || newCount !is oldCount) { + OS.DeleteMenu (hMenu, OS.SC_TASKLIST, OS.MF_BYCOMMAND); + MENUITEMINFO info = new MENUITEMINFO (); + info.cbSize = 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 & DWT.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 IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the text 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> + */ +public void setText (String string) { + checkWidget (); + if (string is null) error (DWT.ERROR_NULL_ARGUMENT); + /* Use the character encoding for the default locale */ + TCHAR buffer = new TCHAR (0, string, true); + OS.SetWindowText (handle, buffer); +} + +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 (DWT.Show); + if (isDisposed ()) return; + if (OS.IsHPC) { + if (menuBar !is null) { + int hwndCB = menuBar.hwndCB; + OS.CommandBar_DrawMenuBar (hwndCB, 0); + } + } + if (drawCount !is 0) { + state &= ~HIDDEN; + } else { + 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; + } + OS.UpdateWindow (handle); + } + } else { + if (!OS.IsWinCE) { + if (OS.IsIconic (handle)) { + swFlags = OS.SW_SHOWMINNOACTIVE; + } else { + if (OS.IsZoomed (handle)) { + swFlags = OS.SW_SHOWMAXIMIZED; + } else { + if (handle is OS.GetActiveWindow ()) { + swFlags = OS.SW_RESTORE; + } else { + swFlags = OS.SW_SHOWNOACTIVATE; + } + } + } + } + if (drawCount !is 0) { + state |= HIDDEN; + } else { + OS.ShowWindow (handle, OS.SW_HIDE); + } + if (isDisposed ()) return; + sendEvent (DWT.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; + } + } + } + } +} + +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 -1) createAccelerators (); + return hAccel !is 0 && OS.TranslateAccelerator (handle, hAccel, msg) !is 0; +} + +bool translateMDIAccelerator (MSG msg) { + if (!(this instanceof Shell)) { + Shell shell = getShell (); + int hwndMDIClient = shell.hwndMDIClient; + if (hwndMDIClient !is 0 && 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; + } + 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; + } + 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 () && child instanceof Decorations) { + if (child.setFocus ()) return true; + } + } + return false; +} + +bool traverseItem (bool next) { + return false; +} + +bool traverseReturn () { + if (defaultButton is null || defaultButton.isDisposed ()) return false; + if (!defaultButton.isVisible () || !defaultButton.isEnabled ()) return false; + defaultButton.click (); + return true; +} + +CREATESTRUCT widgetCreateStruct () { + return new CREATESTRUCT (); +} + +int widgetExtStyle () { + int bits = super.widgetExtStyle () | OS.WS_EX_MDICHILD; + bits &= ~OS.WS_EX_CLIENTEDGE; + if ((style & DWT.NO_TRIM) !is 0) return bits; + if (OS.IsPPC) { + if ((style & DWT.CLOSE) !is 0) bits |= OS.WS_EX_CAPTIONOKBTN; + } + if ((style & DWT.RESIZE) !is 0) return bits; + if ((style & DWT.BORDER) !is 0) bits |= OS.WS_EX_DLGMODALFRAME; + return bits; +} + +int widgetParent () { + Shell shell = getShell (); + return shell.hwndMDIClient (); +} + +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 & DWT.NO_TRIM) !is 0) return bits; + if ((style & DWT.TITLE) !is 0) bits |= OS.WS_CAPTION; + + /* Set the min and max button bits */ + if ((style & DWT.MIN) !is 0) bits |= OS.WS_MINIMIZEBOX; + if ((style & DWT.MAX) !is 0) bits |= OS.WS_MAXIMIZEBOX; + + /* Set the resize, dialog border or border bits */ + if ((style & DWT.RESIZE) !is 0) { + /* + * Note on WinCE PPC. DWT.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 & DWT.BORDER) is 0) bits |= OS.WS_BORDER; + } + + /* Set the system menu and close box bits */ + if (!OS.IsPPC && !OS.IsSP) { + if ((style & DWT.CLOSE) !is 0) bits |= OS.WS_SYSMENU; + } + + return bits; +} + +int windowProc (int hwnd, int msg, int wParam, int lParam) { + switch (msg) { + case Display.SWT_GETACCEL: + case Display.SWT_GETACCELCOUNT: + if (hAccel is -1) createAccelerators (); + return msg is Display.SWT_GETACCELCOUNT ? nAccel : hAccel; + } + return super.windowProc (hwnd, msg, wParam, lParam); +} + +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 DWT, the DWT + * shell gets the WM_ACTIVATE and assumes that it came + * from Windows. When an DWT 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 (lParam) is handle) { + TCHAR buffer = new TCHAR (0, 128); + OS.GetClassName (lParam, buffer, buffer.length ()); + String className = buffer.toString (0, buffer.strlen ()); + if (className.equals (Display.AWT_WINDOW_CLASS)) { + return LRESULT.ZERO; + } + } + if ((wParam & 0xFFFF) !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 ((wParam >> 16) !is 0) return result; + Control control = display.findControl (lParam); + if (control is null || control instanceof Shell) { + if (this instanceof Shell) { + sendEvent (DWT.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 (lParam); + if (control is null || control instanceof Shell) { + if (this instanceof Shell) { + sendEvent (DWT.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; +} + +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; +} + +LRESULT WM_HOTKEY (int wParam, int lParam) { + LRESULT result = super.WM_HOTKEY (wParam, lParam); + if (result !is null) return result; + 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 DWT.CLOSE style, close the Shell. + * Otherwise, send the Back key to the window with focus. + */ + if (((lParam >> 16) & 0xFFFF) is OS.VK_ESCAPE) { + if ((style & DWT.CLOSE) !is 0) { + OS.PostMessage (handle, OS.WM_CLOSE, 0, 0); + } else { + OS.SHSendBackToFocusWindow (OS.WM_HOTKEY, wParam, lParam); + } + return LRESULT.ZERO; + } + } + return result; +} + +LRESULT WM_KILLFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_KILLFOCUS (wParam, lParam); + saveFocus (); + return result; +} + +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); +} + +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 (lParam); + if (control !is null) { + Shell shell = getShell (); + Decorations decorations = control.menuShell (); + if (decorations.getShell () is shell) { + if (this instanceof Shell) return LRESULT.ONE; + if (display.ignoreRestoreFocus) { + if (display.lastHittest !is OS.HTCLIENT) { + result = LRESULT.ONE; + } + } + } + } + } + if (!(this instanceof Shell)) { + int hwndShell = getShell().handle; + OS.SendMessage (hwndShell, OS.WM_NCACTIVATE, wParam, lParam); + } + return result; +} + +LRESULT WM_QUERYOPEN (int wParam, int lParam) { + LRESULT result = super.WM_QUERYOPEN (wParam, lParam); + if (result !is null) return result; + sendEvent (DWT.Deiconify); + // widget could be disposed at this point + return result; +} + +LRESULT WM_SETFOCUS (int wParam, int lParam) { + LRESULT result = super.WM_SETFOCUS (wParam, lParam); + if (savedFocus !is this) restoreFocus (); + return result; +} + +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 = lParam & 0xFFFF; + newHeight = lParam >> 16; + break; + case OS.SIZE_MINIMIZED: + Rectangle rect = getClientArea (); + newWidth = rect.width; + newHeight = rect.height; + break; + } + 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 (DWT.Iconify); + // widget could be disposed at this point + } + return result; +} + +LRESULT WM_SYSCOMMAND (int wParam, int lParam) { + LRESULT result = super.WM_SYSCOMMAND (wParam, lParam); + if (result !is null) return result; + if (!(this instanceof Shell)) { + 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; + } + } + } + return result; +} + +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 = new WINDOWPOS (); + OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof); + lpwp.flags |= OS.SWP_NOZORDER; + OS.MoveMemory (lParam, lpwp, WINDOWPOS.sizeof); + } + return result; +} + +} +++/ \ No newline at end of file