comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:6dd524f61e62
1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module org.eclipse.swt.widgets.Decorations;
14
15
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.SWTException;
18 import org.eclipse.swt.graphics.Image;
19 import org.eclipse.swt.graphics.ImageData;
20 import org.eclipse.swt.graphics.Point;
21 import org.eclipse.swt.graphics.Rectangle;
22 import org.eclipse.swt.internal.win32.OS;
23
24 import org.eclipse.swt.widgets.Canvas;
25 import org.eclipse.swt.widgets.Menu;
26 import org.eclipse.swt.widgets.Control;
27 import org.eclipse.swt.widgets.Button;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Event;
30 import org.eclipse.swt.widgets.Shell;
31 import org.eclipse.swt.widgets.MenuItem;
32 import org.eclipse.swt.widgets.Display;
33
34 import java.lang.all;
35
36 /**
37 * Instances of this class provide the appearance and
38 * behavior of <code>Shells</code>, but are not top
39 * level shells or dialogs. Class <code>Shell</code>
40 * shares a significant amount of code with this class,
41 * and is a subclass.
42 * <p>
43 * IMPORTANT: This class was intended to be abstract and
44 * should <em>never</em> be referenced or instantiated.
45 * Instead, the class <code>Shell</code> should be used.
46 * </p>
47 * <p>
48 * Instances are always displayed in one of the maximized,
49 * minimized or normal states:
50 * <ul>
51 * <li>
52 * When an instance is marked as <em>maximized</em>, the
53 * window manager will typically resize it to fill the
54 * entire visible area of the display, and the instance
55 * is usually put in a state where it can not be resized
56 * (even if it has style <code>RESIZE</code>) until it is
57 * no longer maximized.
58 * </li><li>
59 * When an instance is in the <em>normal</em> state (neither
60 * maximized or minimized), its appearance is controlled by
61 * the style constants which were specified when it was created
62 * and the restrictions of the window manager (see below).
63 * </li><li>
64 * When an instance has been marked as <em>minimized</em>,
65 * its contents (client area) will usually not be visible,
66 * and depending on the window manager, it may be
67 * "iconified" (that is, replaced on the desktop by a small
68 * simplified representation of itself), relocated to a
69 * distinguished area of the screen, or hidden. Combinations
70 * of these changes are also possible.
71 * </li>
72 * </ul>
73 * </p>
74 * Note: The styles supported by this class must be treated
75 * as <em>HINT</em>s, since the window manager for the
76 * desktop on which the instance is visible has ultimate
77 * control over the appearance and behavior of decorations.
78 * For example, some window managers only support resizable
79 * windows and will always assume the RESIZE style, even if
80 * it is not set.
81 * <dl>
82 * <dt><b>Styles:</b></dt>
83 * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd>
84 * <dt><b>Events:</b></dt>
85 * <dd>(none)</dd>
86 * </dl>
87 * Class <code>SWT</code> provides two "convenience constants"
88 * for the most commonly required style combinations:
89 * <dl>
90 * <dt><code>SHELL_TRIM</code></dt>
91 * <dd>
92 * the result of combining the constants which are required
93 * to produce a typical application top level shell: (that
94 * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
95 * </dd>
96 * <dt><code>DIALOG_TRIM</code></dt>
97 * <dd>
98 * the result of combining the constants which are required
99 * to produce a typical application dialog shell: (that
100 * is, <code>TITLE | CLOSE | BORDER</code>)
101 * </dd>
102 * </dl>
103 * <p>
104 * IMPORTANT: This class is intended to be subclassed <em>only</em>
105 * within the SWT implementation.
106 * </p>
107 *
108 * @see #getMinimized
109 * @see #getMaximized
110 * @see Shell
111 * @see SWT
112 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
113 */
114
115 public class Decorations : Canvas {
116
117 alias Canvas.setBounds setBounds;
118 alias Canvas.setParent setParent;
119 alias Canvas.setSavedFocus setSavedFocus;
120 alias Canvas.sort sort;
121 alias Canvas.windowProc windowProc;
122
123 Image image, smallImage, largeImage;
124 Image [] images;
125 Menu menuBar;
126 Menu [] menus;
127 Control savedFocus;
128 Button defaultButton, saveDefault;
129 int swFlags;
130 HACCEL hAccel;
131 int nAccel;
132 bool moved, resized, opened;
133 int oldX = OS.CW_USEDEFAULT, oldY = OS.CW_USEDEFAULT;
134 int oldWidth = OS.CW_USEDEFAULT, oldHeight = OS.CW_USEDEFAULT;
135
136 /**
137 * Prevents uninitialized instances from being created outside the package.
138 */
139 this () {
140 }
141
142 /**
143 * Constructs a new instance of this class given its parent
144 * and a style value describing its behavior and appearance.
145 * <p>
146 * The style value is either one of the style constants defined in
147 * class <code>SWT</code> which is applicable to instances of this
148 * class, or must be built by <em>bitwise OR</em>'ing together
149 * (that is, using the <code>int</code> "|" operator) two or more
150 * of those <code>SWT</code> style constants. The class description
151 * lists the style constants that are applicable to the class.
152 * Style bits are also inherited from superclasses.
153 * </p>
154 *
155 * @param parent a composite control which will be the parent of the new instance (cannot be null)
156 * @param style the style of control to construct
157 *
158 * @exception IllegalArgumentException <ul>
159 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
160 * </ul>
161 * @exception SWTException <ul>
162 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
163 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
164 * </ul>
165 *
166 * @see SWT#BORDER
167 * @see SWT#CLOSE
168 * @see SWT#MIN
169 * @see SWT#MAX
170 * @see SWT#RESIZE
171 * @see SWT#TITLE
172 * @see SWT#NO_TRIM
173 * @see SWT#SHELL_TRIM
174 * @see SWT#DIALOG_TRIM
175 * @see SWT#ON_TOP
176 * @see SWT#TOOL
177 * @see Widget#checkSubclass
178 * @see Widget#getStyle
179 */
180 public this (Composite parent, int style) {
181 super (parent, checkStyle (style));
182 }
183
184 void _setMaximized (bool maximized) {
185 swFlags = maximized ? OS.SW_SHOWMAXIMIZED : OS.SW_RESTORE;
186 static if (OS.IsWinCE) {
187 /*
188 * Note: WinCE does not support SW_SHOWMAXIMIZED and SW_RESTORE. The
189 * workaround is to resize the window to fit the parent client area.
190 */
191 if (maximized) {
192 RECT rect;
193 OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, &rect, 0);
194 int width = rect.right - rect.left, height = rect.bottom - rect.top;
195 if (OS.IsPPC) {
196 /* Leave space for the menu bar */
197 if (menuBar !is null) {
198 auto hwndCB = menuBar.hwndCB;
199 RECT rectCB;
200 OS.GetWindowRect (hwndCB, &rectCB);
201 height -= rectCB.bottom - rectCB.top;
202 }
203 }
204 int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
205 SetWindowPos (handle, null, rect.left, rect.top, width, height, flags);
206 }
207 } else {
208 if (!OS.IsWindowVisible (handle)) return;
209 if (maximized is OS.IsZoomed (handle)) return;
210 OS.ShowWindow (handle, swFlags);
211 OS.UpdateWindow (handle);
212 }
213 }
214
215 void _setMinimized (bool minimized) {
216 static if (OS.IsWinCE) return;
217 swFlags = minimized ? OS.SW_SHOWMINNOACTIVE : OS.SW_RESTORE;
218 if (!OS.IsWindowVisible (handle)) return;
219 if (minimized is OS.IsIconic (handle)) return;
220 int flags = swFlags;
221 if (flags is OS.SW_SHOWMINNOACTIVE && handle is OS.GetActiveWindow ()) {
222 flags = OS.SW_MINIMIZE;
223 }
224 OS.ShowWindow (handle, flags);
225 OS.UpdateWindow (handle);
226 }
227
228 void addMenu (Menu menu) {
229 if (menus is null) menus = new Menu [4];
230 for (int i=0; i<menus.length; i++) {
231 if (menus [i] is null) {
232 menus [i] = menu;
233 return;
234 }
235 }
236 Menu [] newMenus = new Menu [menus.length + 4];
237 newMenus [menus.length] = menu;
238 System.arraycopy (menus, 0, newMenus, 0, menus.length);
239 menus = newMenus;
240 }
241
242 void bringToTop () {
243 /*
244 * This code is intentionally commented. On some platforms,
245 * the ON_TOP style creates a shell that will stay on top
246 * of every other shell on the desktop. Using SetWindowPos ()
247 * with HWND_TOP caused problems on Windows 98 so this code is
248 * commented out until this functionality is specified and
249 * the problems are fixed.
250 */
251 // if ((style & SWT.ON_TOP) !is 0) {
252 // int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
253 // OS.SetWindowPos (handle, OS.HWND_TOP, 0, 0, 0, 0, flags);
254 // } else {
255 OS.BringWindowToTop (handle);
256 // widget could be disposed at this point
257 // }
258 }
259
260 static int checkStyle (int style) {
261 if ((style & SWT.NO_TRIM) !is 0) {
262 style &= ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER);
263 }
264 static if (OS.IsWinCE) {
265 /*
266 * Feature in WinCE PPC. WS_MINIMIZEBOX or WS_MAXIMIZEBOX
267 * are not supposed to be used. If they are, the result
268 * is a button which does not repaint correctly. The fix
269 * is to remove this style.
270 */
271 if ((style & SWT.MIN) !is 0) style &= ~SWT.MIN;
272 if ((style & SWT.MAX) !is 0) style &= ~SWT.MAX;
273 return style;
274 }
275 if ((style & (SWT.MENU | SWT.MIN | SWT.MAX | SWT.CLOSE)) !is 0) {
276 style |= SWT.TITLE;
277 }
278
279 /*
280 * If either WS_MINIMIZEBOX or WS_MAXIMIZEBOX are set,
281 * we must also set WS_SYSMENU or the buttons will not
282 * appear.
283 */
284 if ((style & (SWT.MIN | SWT.MAX)) !is 0) style |= SWT.CLOSE;
285
286 /*
287 * Both WS_SYSMENU and WS_CAPTION must be set in order
288 * to for the system menu to appear.
289 */
290 if ((style & SWT.CLOSE) !is 0) style |= SWT.TITLE;
291
292 /*
293 * Bug in Windows. The WS_CAPTION style must be
294 * set when the window is resizable or it does not
295 * draw properly.
296 */
297 /*
298 * This code is intentionally commented. It seems
299 * that this problem originally in Windows 3.11,
300 * has been fixed in later versions. Because the
301 * exact nature of the drawing problem is unknown,
302 * keep the commented code around in case it comes
303 * back.
304 */
305 // if ((style & SWT.RESIZE) !is 0) style |= SWT.TITLE;
306
307 return style;
308 }
309
310 override void checkBorder () {
311 /* Do nothing */
312 }
313
314 void checkComposited (Composite parent) {
315 /* Do nothing */
316 }
317
318 override void checkOpened () {
319 if (!opened) resized = false;
320 }
321
322 override protected void checkSubclass () {
323 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
324 }
325
326 override override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) {
327 if (handle is null) return 0;
328 return OS.DefMDIChildProc (hwnd, msg, wParam, lParam);
329 }
330
331 void closeWidget () {
332 Event event = new Event ();
333 sendEvent (SWT.Close, event);
334 if (event.doit && !isDisposed ()) dispose ();
335 }
336
337 int compare (ImageData data1, ImageData data2, int width, int height, int depth) {
338 int value1 = Math.abs (data1.width - width), value2 = Math.abs (data2.width - width);
339 if (value1 is value2) {
340 int transparent1 = data1.getTransparencyType ();
341 int transparent2 = data2.getTransparencyType ();
342 if (transparent1 is transparent2) {
343 if (data1.depth is data2.depth) return 0;
344 return data1.depth > data2.depth && data1.depth <= depth ? -1 : 1;
345 }
346 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (5, 1)) {
347 if (transparent1 is SWT.TRANSPARENCY_ALPHA) return -1;
348 if (transparent2 is SWT.TRANSPARENCY_ALPHA) return 1;
349 }
350 if (transparent1 is SWT.TRANSPARENCY_MASK) return -1;
351 if (transparent2 is SWT.TRANSPARENCY_MASK) return 1;
352 if (transparent1 is SWT.TRANSPARENCY_PIXEL) return -1;
353 if (transparent2 is SWT.TRANSPARENCY_PIXEL) return 1;
354 return 0;
355 }
356 return value1 < value2 ? -1 : 1;
357 }
358
359 override Control computeTabGroup () {
360 return this;
361 }
362
363 override Control computeTabRoot () {
364 return this;
365 }
366
367 override public Rectangle computeTrim (int x, int y, int width, int height) {
368 checkWidget ();
369
370 /* Get the size of the trimmings */
371 RECT rect;
372 OS.SetRect (&rect, x, y, x + width, y + height);
373 int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
374 int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
375 bool hasMenu = OS.IsWinCE ? false : OS.GetMenu (handle) !is null;
376 OS.AdjustWindowRectEx (&rect, bits1, hasMenu, bits2);
377
378 /* Get the size of the scroll bars */
379 if (horizontalBar !is null) rect.bottom += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
380 if (verticalBar !is null) rect.right += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
381
382 /* Compute the height of the menu bar */
383 if (hasMenu) {
384 RECT testRect;
385 OS.SetRect (&testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
386 OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, &testRect);
387 while ((testRect.bottom - testRect.top) < height) {
388 if (testRect.bottom - testRect.top is 0) break;
389 rect.top -= OS.GetSystemMetrics (OS.SM_CYMENU) - OS.GetSystemMetrics (OS.SM_CYBORDER);
390 OS.SetRect (&testRect, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
391 OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, &testRect);
392 }
393 }
394 return new Rectangle (rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
395 }
396
397 void createAccelerators () {
398 hAccel = null;
399 nAccel = 0;
400 int maxAccel = 0;
401 MenuItem [] items = display.items;
402 if (menuBar is null || items is null) {
403 if (!OS.IsPPC) return;
404 maxAccel = 1;
405 } else {
406 maxAccel = OS.IsPPC ? items.length + 1 : items.length;
407 }
408 ACCEL accel;
409 byte [] buffer1 = new byte [ACCEL.sizeof];
410 byte [] buffer2 = new byte [maxAccel * ACCEL.sizeof];
411 if (menuBar !is null && items !is null) {
412 for (int i=0; i<items.length; i++) {
413 MenuItem item = items [i];
414 if (item !is null && item.accelerator !is 0) {
415 Menu menu = item.parent;
416 if (menu.parent is this) {
417 while (menu !is null && menu !is menuBar) {
418 menu = menu.getParentMenu ();
419 }
420 if (menu is menuBar && item.fillAccel (&accel)) {
421 *cast(ACCEL*)buffer1.ptr = accel;
422 //OS.MoveMemory (buffer1, accel, ACCEL.sizeof);
423 System.arraycopy (buffer1, 0, buffer2, nAccel * ACCEL.sizeof, ACCEL.sizeof);
424 nAccel++;
425 }
426 }
427 }
428 }
429 }
430 if (OS.IsPPC) {
431 /*
432 * Note on WinCE PPC. Close the shell when user taps CTRL-Q.
433 * IDOK represents the "Done Button" which also closes the shell.
434 */
435 accel.fVirt = cast(byte) (OS.FVIRTKEY | OS.FCONTROL);
436 accel.key = cast(short) 'Q';
437 accel.cmd = cast(short) OS.IDOK;
438 *cast(ACCEL*)buffer1.ptr = accel;
439 //OS.MoveMemory (buffer1, accel, ACCEL.sizeof);
440 System.arraycopy (buffer1, 0, buffer2, nAccel * ACCEL.sizeof, ACCEL.sizeof);
441 nAccel++;
442 }
443 if (nAccel !is 0) hAccel = OS.CreateAcceleratorTable ( cast(ACCEL*)buffer2.ptr, nAccel);
444 }
445
446 override void createHandle () {
447 super.createHandle ();
448 if (parent !is null || ((style & SWT.TOOL) !is 0)) {
449 setParent ();
450 setSystemMenu ();
451 }
452 }
453
454 override void createWidget () {
455 super.createWidget ();
456 swFlags = OS.IsWinCE ? OS.SW_SHOWMAXIMIZED : OS.SW_SHOWNOACTIVATE;
457 hAccel = cast(HACCEL)-1;
458 }
459
460 void destroyAccelerators () {
461 if (hAccel !is null && hAccel !is cast(HACCEL)-1) OS.DestroyAcceleratorTable (hAccel);
462 hAccel = cast(HACCEL)-1;
463 }
464
465 override public void dispose () {
466 if (isDisposed()) return;
467 if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
468 if (!(cast(Shell)this)) {
469 if (!traverseDecorations (true)) {
470 Shell shell = getShell ();
471 shell.setFocus ();
472 }
473 setVisible (false);
474 }
475 super.dispose ();
476 }
477
478 Menu findMenu (HMENU hMenu) {
479 if (menus is null) return null;
480 for (int i=0; i<menus.length; i++) {
481 Menu menu = menus [i];
482 if (menu !is null && hMenu is menu.handle) return menu;
483 }
484 return null;
485 }
486
487 void fixDecorations (Decorations newDecorations, Control control, Menu [] menus) {
488 if (this is newDecorations) return;
489 if (control is savedFocus) savedFocus = null;
490 if (control is defaultButton) defaultButton = null;
491 if (control is saveDefault) saveDefault = null;
492 if (menus is null) return;
493 Menu menu = control.menu;
494 if (menu !is null) {
495 int index = 0;
496 while (index <menus.length) {
497 if (menus [index] is menu) {
498 control.setMenu (null);
499 return;
500 }
501 index++;
502 }
503 menu.fixMenus (newDecorations);
504 destroyAccelerators ();
505 newDecorations.destroyAccelerators ();
506 }
507 }
508
509 override public Rectangle getBounds () {
510 checkWidget ();
511 static if (!OS.IsWinCE) {
512 if (OS.IsIconic (handle)) {
513 WINDOWPLACEMENT lpwndpl;
514 lpwndpl.length = WINDOWPLACEMENT.sizeof;
515 OS.GetWindowPlacement (handle, &lpwndpl);
516 int width = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left;
517 int height = lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top;
518 return new Rectangle (lpwndpl.rcNormalPosition.left, lpwndpl.rcNormalPosition.top, width, height);
519 }
520 }
521 return super.getBounds ();
522 }
523
524 override public Rectangle getClientArea () {
525 checkWidget ();
526 /*
527 * Note: The CommandBar is part of the client area,
528 * not the trim. Applications don't expect this so
529 * subtract the height of the CommandBar.
530 */
531 static if (OS.IsHPC) {
532 Rectangle rect = super.getClientArea ();
533 if (menuBar !is null) {
534 auto hwndCB = menuBar.hwndCB;
535 int height = OS.CommandBar_Height (hwndCB);
536 rect.y += height;
537 rect.height = Math.max (0, rect.height - height);
538 }
539 return rect;
540 }
541 static if (!OS.IsWinCE) {
542 if (OS.IsIconic (handle)) {
543 WINDOWPLACEMENT lpwndpl;
544 lpwndpl.length = WINDOWPLACEMENT.sizeof;
545 OS.GetWindowPlacement (handle, &lpwndpl);
546 int width = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left;
547 int height = lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top;
548 /*
549 * Feature in Windows. For some reason WM_NCCALCSIZE does
550 * not compute the client area when the window is minimized.
551 * The fix is to compute it using AdjustWindowRectEx() and
552 * GetSystemMetrics().
553 *
554 * NOTE: This code fails to compute the correct client area
555 * for a minimized window where the menu bar would wrap were
556 * the window restored. There is no fix for this problem at
557 * this time.
558 */
559 if (horizontalBar !is null) width -= OS.GetSystemMetrics (OS.SM_CYHSCROLL);
560 if (verticalBar !is null) height -= OS.GetSystemMetrics (OS.SM_CXVSCROLL);
561 RECT rect;
562 int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
563 int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
564 bool hasMenu = OS.IsWinCE ? false : OS.GetMenu (handle) !is null;
565 OS.AdjustWindowRectEx (&rect, bits1, hasMenu, bits2);
566 width = Math.max (0, width - (rect.right - rect.left));
567 height = Math.max (0, height - (rect.bottom - rect.top));
568 return new Rectangle (0, 0, width, height);
569 }
570 }
571 return super.getClientArea ();
572 }
573
574 /**
575 * Returns the receiver's default button if one had
576 * previously been set, otherwise returns null.
577 *
578 * @return the default button or null
579 *
580 * @exception SWTException <ul>
581 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
582 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
583 * </ul>
584 *
585 * @see #setDefaultButton(Button)
586 */
587 public Button getDefaultButton () {
588 checkWidget ();
589 return defaultButton;
590 }
591
592 /**
593 * Returns the receiver's image if it had previously been
594 * set using <code>setImage()</code>. The image is typically
595 * displayed by the window manager when the instance is
596 * marked as iconified, and may also be displayed somewhere
597 * in the trim when the instance is in normal or maximized
598 * states.
599 * <p>
600 * Note: This method will return null if called before
601 * <code>setImage()</code> is called. It does not provide
602 * access to a window manager provided, "default" image
603 * even if one exists.
604 * </p>
605 *
606 * @return the image
607 *
608 * @exception SWTException <ul>
609 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
610 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
611 * </ul>
612 */
613 public Image getImage () {
614 checkWidget ();
615 return image;
616 }
617
618 /**
619 * Returns the receiver's images if they had previously been
620 * set using <code>setImages()</code>. Images are typically
621 * displayed by the window manager when the instance is
622 * marked as iconified, and may also be displayed somewhere
623 * in the trim when the instance is in normal or maximized
624 * states. Depending where the icon is displayed, the platform
625 * chooses the icon with the "best" attributes. It is expected
626 * that the array will contain the same icon rendered at different
627 * sizes, with different depth and transparency attributes.
628 *
629 * <p>
630 * Note: This method will return an empty array if called before
631 * <code>setImages()</code> is called. It does not provide
632 * access to a window manager provided, "default" image
633 * even if one exists.
634 * </p>
635 *
636 * @return the images
637 *
638 * @exception SWTException <ul>
639 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
640 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
641 * </ul>
642 *
643 * @since 3.0
644 */
645 public Image [] getImages () {
646 checkWidget ();
647 if (images is null) return new Image [0];
648 Image [] result = new Image [images.length];
649 System.arraycopy (images, 0, result, 0, images.length);
650 return result;
651 }
652
653 override public Point getLocation () {
654 checkWidget ();
655 static if (!OS.IsWinCE) {
656 if (OS.IsIconic (handle)) {
657 WINDOWPLACEMENT lpwndpl;
658 lpwndpl.length = WINDOWPLACEMENT.sizeof;
659 OS.GetWindowPlacement (handle, &lpwndpl);
660 return new Point (lpwndpl.rcNormalPosition.left, lpwndpl.rcNormalPosition.top);
661 }
662 }
663 return super.getLocation ();
664 }
665
666 /**
667 * Returns <code>true</code> if the receiver is currently
668 * maximized, and false otherwise.
669 * <p>
670 *
671 * @return the maximized state
672 *
673 * @exception SWTException <ul>
674 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
675 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
676 * </ul>
677 *
678 * @see #setMaximized
679 */
680 public bool getMaximized () {
681 checkWidget ();
682 static if (OS.IsWinCE) return swFlags is OS.SW_SHOWMAXIMIZED;
683 if (OS.IsWindowVisible (handle)) return cast(bool) OS.IsZoomed (handle);
684 return swFlags is OS.SW_SHOWMAXIMIZED;
685 }
686
687 /**
688 * Returns the receiver's menu bar if one had previously
689 * been set, otherwise returns null.
690 *
691 * @return the menu bar or null
692 *
693 * @exception SWTException <ul>
694 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
695 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
696 * </ul>
697 */
698 public Menu getMenuBar () {
699 checkWidget ();
700 return menuBar;
701 }
702
703 /**
704 * Returns <code>true</code> if the receiver is currently
705 * minimized, and false otherwise.
706 * <p>
707 *
708 * @return the minimized state
709 *
710 * @exception SWTException <ul>
711 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
712 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
713 * </ul>
714 *
715 * @see #setMinimized
716 */
717 public bool getMinimized () {
718 checkWidget ();
719 static if (OS.IsWinCE) return false;
720 if (OS.IsWindowVisible (handle)) return cast(bool) OS.IsIconic (handle);
721 return swFlags is OS.SW_SHOWMINNOACTIVE;
722 }
723
724 override String getNameText () {
725 return getText ();
726 }
727
728 override public Point getSize () {
729 checkWidget ();
730 static if (!OS.IsWinCE) {
731 if (OS.IsIconic (handle)) {
732 WINDOWPLACEMENT lpwndpl;
733 lpwndpl.length = WINDOWPLACEMENT.sizeof;
734 OS.GetWindowPlacement (handle, &lpwndpl);
735 int width = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left;
736 int height = lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top;
737 return new Point (width, height);
738 }
739 }
740 return super.getSize ();
741 }
742
743 /**
744 * Returns the receiver's text, which is the string that the
745 * window manager will typically display as the receiver's
746 * <em>title</em>. If the text has not previously been set,
747 * returns an empty string.
748 *
749 * @return the text
750 *
751 * @exception SWTException <ul>
752 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
753 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
754 * </ul>
755 */
756 public String getText () {
757 checkWidget ();
758 int length = OS.GetWindowTextLength (handle);
759 if (length is 0) return "";
760 /* Use the character encoding for the default locale */
761 TCHAR[] buffer;
762 buffer.length = length + 1;
763 OS.GetWindowText (handle, buffer.ptr, length + 1);
764 return TCHARsToStr( buffer );
765 }
766
767 override public bool isReparentable () {
768 checkWidget ();
769 /*
770 * Feature in Windows. Calling SetParent() for a shell causes
771 * a kind of fake MDI to happen. It doesn't work well on Windows
772 * and is not supported on the other platforms. The fix is to
773 * disallow the SetParent().
774 */
775 return false;
776 }
777
778 override bool isTabGroup () {
779 /*
780 * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX.
781 */
782 return true;
783 }
784
785 override bool isTabItem () {
786 /*
787 * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX.
788 */
789 return false;
790 }
791
792 override Decorations menuShell () {
793 return this;
794 }
795
796 override void releaseChildren (bool destroy) {
797 if (menuBar !is null) {
798 menuBar.release (false);
799 menuBar = null;
800 }
801 super.releaseChildren (destroy);
802 if (menus !is null) {
803 for (int i=0; i<menus.length; i++) {
804 Menu menu = menus [i];
805 if (menu !is null && !menu.isDisposed ()) {
806 menu.dispose ();
807 }
808 }
809 menus = null;
810 }
811 }
812
813 override void releaseWidget () {
814 super.releaseWidget ();
815 if (smallImage !is null) smallImage.dispose ();
816 if (largeImage !is null) largeImage.dispose ();
817 smallImage = largeImage = image = null;
818 images = null;
819 savedFocus = null;
820 defaultButton = saveDefault = null;
821 if (hAccel !is null && hAccel !is cast(HACCEL)-1) OS.DestroyAcceleratorTable (hAccel);
822 hAccel = cast(HACCEL)-1;
823 }
824
825 void removeMenu (Menu menu) {
826 if (menus is null) return;
827 for (int i=0; i<menus.length; i++) {
828 if (menus [i] is menu) {
829 menus [i] = null;
830 return;
831 }
832 }
833 }
834
835 bool restoreFocus () {
836 if (display.ignoreRestoreFocus) return true;
837 if (savedFocus !is null && savedFocus.isDisposed ()) savedFocus = null;
838 if (savedFocus !is null && savedFocus.setSavedFocus ()) return true;
839 /*
840 * This code is intentionally commented. When no widget
841 * has been given focus, some platforms give focus to the
842 * default button. Windows doesn't do this.
843 */
844 // if (defaultButton !is null && !defaultButton.isDisposed ()) {
845 // if (defaultButton.setFocus ()) return true;
846 // }
847 return false;
848 }
849
850 void saveFocus () {
851 Control control = display._getFocusControl ();
852 if (control !is null && control !is this && this is control.menuShell ()) {
853 setSavedFocus (control);
854 }
855 }
856
857 override void setBounds (int x, int y, int width, int height, int flags, bool defer) {
858 static if (OS.IsWinCE) {
859 swFlags = OS.SW_RESTORE;
860 } else {
861 if (OS.IsIconic (handle)) {
862 setPlacement (x, y, width, height, flags);
863 return;
864 }
865 }
866 forceResize ();
867 RECT rect;
868 OS.GetWindowRect (handle, &rect);
869 bool sameOrigin = true;
870 if ((OS.SWP_NOMOVE & flags) is 0) {
871 sameOrigin = rect.left is x && rect.top is y;
872 if (!sameOrigin) moved = true;
873 }
874 bool sameExtent = true;
875 if ((OS.SWP_NOSIZE & flags) is 0) {
876 sameExtent = rect.right - rect.left is width && rect.bottom - rect.top is height;
877 if (!sameExtent) resized = true;
878 }
879 static if (!OS.IsWinCE) {
880 if (OS.IsZoomed (handle)) {
881 if (sameOrigin && sameExtent) return;
882 setPlacement (x, y, width, height, flags);
883 _setMaximized (false);
884 return;
885 }
886 }
887 super.setBounds (x, y, width, height, flags, defer);
888 }
889
890 /**
891 * If the argument is not null, sets the receiver's default
892 * button to the argument, and if the argument is null, sets
893 * the receiver's default button to the first button which
894 * was set as the receiver's default button (called the
895 * <em>saved default button</em>). If no default button had
896 * previously been set, or the saved default button was
897 * disposed, the receiver's default button will be set to
898 * null.
899 * <p>
900 * The default button is the button that is selected when
901 * the receiver is active and the user presses ENTER.
902 * </p>
903 *
904 * @param button the new default button
905 *
906 * @exception IllegalArgumentException <ul>
907 * <li>ERROR_INVALID_ARGUMENT - if the button has been disposed</li>
908 * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
909 * </ul>
910 * @exception SWTException <ul>
911 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
912 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
913 * </ul>
914 */
915 public void setDefaultButton (Button button) {
916 checkWidget ();
917 if (button !is null) {
918 if (button.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
919 if (button.menuShell () !is this) error(SWT.ERROR_INVALID_PARENT);
920 }
921 setDefaultButton (button, true);
922 }
923
924 void setDefaultButton (Button button, bool save) {
925 if (button is null) {
926 if (defaultButton is saveDefault) {
927 if (save) saveDefault = null;
928 return;
929 }
930 } else {
931 if ((button.style & SWT.PUSH) is 0) return;
932 if (button is defaultButton) return;
933 }
934 if (defaultButton !is null) {
935 if (!defaultButton.isDisposed ()) defaultButton.setDefault (false);
936 }
937 if ((defaultButton = button) is null) defaultButton = saveDefault;
938 if (defaultButton !is null) {
939 if (!defaultButton.isDisposed ()) defaultButton.setDefault (true);
940 }
941 if (save) saveDefault = defaultButton;
942 if (saveDefault !is null && saveDefault.isDisposed ()) saveDefault = null;
943 }
944
945 /**
946 * Sets the receiver's image to the argument, which may
947 * be null. The image is typically displayed by the window
948 * manager when the instance is marked as iconified, and
949 * may also be displayed somewhere in the trim when the
950 * instance is in normal or maximized states.
951 *
952 * @param image the new image (or null)
953 *
954 * @exception IllegalArgumentException <ul>
955 * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
956 * </ul>
957 * @exception SWTException <ul>
958 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
959 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
960 * </ul>
961 */
962 public void setImage (Image image) {
963 checkWidget ();
964 if (image !is null && image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
965 this.image = image;
966 setImages (image, null);
967 }
968
969 void setImages (Image image, Image [] images) {
970 /*
971 * Feature in WinCE. WM_SETICON and WM_GETICON set the icon
972 * for the window class, not the window instance. This means
973 * that it is possible to set an icon into a window and then
974 * later free the icon, thus freeing the icon for every window.
975 * The fix is to avoid the API.
976 *
977 * On WinCE PPC, icons in windows are not displayed.
978 */
979 static if (OS.IsWinCE) return;
980 if (smallImage !is null) smallImage.dispose ();
981 if (largeImage !is null) largeImage.dispose ();
982 smallImage = largeImage = null;
983 HICON hSmallIcon, hLargeIcon;
984 Image smallIcon = null, largeIcon = null;
985 if (image !is null) {
986 smallIcon = largeIcon = image;
987 } else {
988 if (images !is null && images.length > 0) {
989 int depth = display.getIconDepth ();
990 ImageData [] datas = null;
991 if (images.length > 1) {
992 Image [] bestImages = new Image [images.length];
993 System.arraycopy (images, 0, bestImages, 0, images.length);
994 datas = new ImageData [images.length];
995 for (int i=0; i<datas.length; i++) {
996 datas [i] = images [i].getImageData ();
997 }
998 images = bestImages;
999 sort (images, datas, OS.GetSystemMetrics (OS.SM_CXSMICON), OS.GetSystemMetrics (OS.SM_CYSMICON), depth);
1000 }
1001 smallIcon = images [0];
1002 if (images.length > 1) {
1003 sort (images, datas, OS.GetSystemMetrics (OS.SM_CXICON), OS.GetSystemMetrics (OS.SM_CYICON), depth);
1004 }
1005 largeIcon = images [0];
1006 }
1007 }
1008 if (smallIcon !is null) {
1009 switch (smallIcon.type) {
1010 case SWT.BITMAP:
1011 smallImage = Display.createIcon (smallIcon);
1012 hSmallIcon = smallImage.handle;
1013 break;
1014 case SWT.ICON:
1015 hSmallIcon = smallIcon.handle;
1016 break;
1017 default:
1018 }
1019 }
1020 OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_SMALL, hSmallIcon);
1021 if (largeIcon !is null) {
1022 switch (largeIcon.type) {
1023 case SWT.BITMAP:
1024 largeImage = Display.createIcon (largeIcon);
1025 hLargeIcon = largeImage.handle;
1026 break;
1027 case SWT.ICON:
1028 hLargeIcon = largeIcon.handle;
1029 break;
1030 default:
1031 }
1032 }
1033 OS.SendMessage (handle, OS.WM_SETICON, OS.ICON_BIG, hLargeIcon);
1034
1035 /*
1036 * Bug in Windows. When WM_SETICON is used to remove an
1037 * icon from the window trimmings for a window with the
1038 * extended style bits WS_EX_DLGMODALFRAME, the window
1039 * trimmings do not redraw to hide the previous icon.
1040 * The fix is to force a redraw.
1041 */
1042 static if (!OS.IsWinCE) {
1043 if (hSmallIcon is null && hLargeIcon is null && (style & SWT.BORDER) !is 0) {
1044 int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE;
1045 OS.RedrawWindow (handle, null, null, flags);
1046 }
1047 }
1048 }
1049
1050 /**
1051 * Sets the receiver's images to the argument, which may
1052 * be an empty array. Images are typically displayed by the
1053 * window manager when the instance is marked as iconified,
1054 * and may also be displayed somewhere in the trim when the
1055 * instance is in normal or maximized states. Depending where
1056 * the icon is displayed, the platform chooses the icon with
1057 * the "best" attributes. It is expected that the array will
1058 * contain the same icon rendered at different sizes, with
1059 * different depth and transparency attributes.
1060 *
1061 * @param images the new image array
1062 *
1063 * @exception IllegalArgumentException <ul>
1064 * <li>ERROR_INVALID_ARGUMENT - if one of the images is null or has been disposed</li>
1065 * </ul>
1066 * @exception SWTException <ul>
1067 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1068 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1069 * </ul>
1070 *
1071 * @since 3.0
1072 */
1073 public void setImages (Image [] images) {
1074 checkWidget ();
1075 // SWT extension: allow null array
1076 //if (images is null) error (SWT.ERROR_INVALID_ARGUMENT);
1077 for (int i = 0; i < images.length; i++) {
1078 if (images [i] is null || images [i].isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
1079 }
1080 this.images = images;
1081 setImages (null, images);
1082 }
1083
1084 /**
1085 * Sets the maximized state of the receiver.
1086 * If the argument is <code>true</code> causes the receiver
1087 * to switch to the maximized state, and if the argument is
1088 * <code>false</code> and the receiver was previously maximized,
1089 * causes the receiver to switch back to either the minimized
1090 * or normal states.
1091 * <p>
1092 * Note: The result of intermixing calls to <code>setMaximized(true)</code>
1093 * and <code>setMinimized(true)</code> will vary by platform. Typically,
1094 * the behavior will match the platform user's expectations, but not
1095 * always. This should be avoided if possible.
1096 * </p>
1097 *
1098 * @param maximized the new maximized state
1099 *
1100 * @exception SWTException <ul>
1101 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1102 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1103 * </ul>
1104 *
1105 * @see #setMinimized
1106 */
1107 public void setMaximized (bool maximized) {
1108 checkWidget ();
1109 Display.lpStartupInfo = null;
1110 _setMaximized (maximized);
1111 }
1112
1113 /**
1114 * Sets the receiver's menu bar to the argument, which
1115 * may be null.
1116 *
1117 * @param menu the new menu bar
1118 *
1119 * @exception IllegalArgumentException <ul>
1120 * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
1121 * <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li>
1122 * </ul>
1123 * @exception SWTException <ul>
1124 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1125 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1126 * </ul>
1127 */
1128 public void setMenuBar (Menu menu) {
1129 checkWidget ();
1130 if (menuBar is menu) return;
1131 if (menu !is null) {
1132 if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
1133 if ((menu.style & SWT.BAR) is 0) error (SWT.ERROR_MENU_NOT_BAR);
1134 if (menu.parent !is this) error (SWT.ERROR_INVALID_PARENT);
1135 }
1136 static if (OS.IsWinCE) {
1137 if (OS.IsHPC) {
1138 bool resize = menuBar !is menu;
1139 if (menuBar !is null) OS.CommandBar_Show (menuBar.hwndCB, false);
1140 menuBar = menu;
1141 if (menuBar !is null) OS.CommandBar_Show (menuBar.hwndCB, true);
1142 if (resize) {
1143 sendEvent (SWT.Resize);
1144 if (isDisposed ()) return;
1145 if (layout !is null) {
1146 markLayout (false, false);
1147 updateLayout (true, false);
1148 }
1149 }
1150 } else {
1151 if (OS.IsPPC) {
1152 /*
1153 * Note in WinCE PPC. The menu bar is a separate popup window.
1154 * If the shell is full screen, resize its window to leave
1155 * space for the menu bar.
1156 */
1157 bool resize = getMaximized () && menuBar !is menu;
1158 if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE);
1159 menuBar = menu;
1160 if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW);
1161 if (resize) _setMaximized (true);
1162 }
1163 if (OS.IsSP) {
1164 if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_HIDE);
1165 menuBar = menu;
1166 if (menuBar !is null) OS.ShowWindow (menuBar.hwndCB, OS.SW_SHOW);
1167 }
1168 }
1169 } else {
1170 if (menu !is null) display.removeBar (menu);
1171 menuBar = menu;
1172 auto hMenu = menuBar !is null ? menuBar.handle: null;
1173 OS.SetMenu (handle, hMenu);
1174 }
1175 destroyAccelerators ();
1176 }
1177
1178 /**
1179 * Sets the minimized stated of the receiver.
1180 * If the argument is <code>true</code> causes the receiver
1181 * to switch to the minimized state, and if the argument is
1182 * <code>false</code> and the receiver was previously minimized,
1183 * causes the receiver to switch back to either the maximized
1184 * or normal states.
1185 * <p>
1186 * Note: The result of intermixing calls to <code>setMaximized(true)</code>
1187 * and <code>setMinimized(true)</code> will vary by platform. Typically,
1188 * the behavior will match the platform user's expectations, but not
1189 * always. This should be avoided if possible.
1190 * </p>
1191 *
1192 * @param minimized the new maximized state
1193 *
1194 * @exception SWTException <ul>
1195 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1196 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1197 * </ul>
1198 *
1199 * @see #setMaximized
1200 */
1201 public void setMinimized (bool minimized) {
1202 checkWidget ();
1203 Display.lpStartupInfo = null;
1204 _setMinimized (minimized);
1205 }
1206
1207 void setParent () {
1208 /*
1209 * In order for an MDI child window to support
1210 * a menu bar, setParent () is needed to reset
1211 * the parent. Otherwise, the MDI child window
1212 * will appear as a separate shell. This is an
1213 * undocumented and possibly dangerous Windows
1214 * feature.
1215 */
1216 auto hwndParent = parent.handle;
1217 display.lockActiveWindow = true;
1218 OS.SetParent (handle, hwndParent);
1219 if (!OS.IsWindowVisible (hwndParent)) {
1220 OS.ShowWindow (handle, OS.SW_SHOWNA);
1221 }
1222 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1223 bits &= ~OS.WS_CHILD;
1224 OS.SetWindowLong (handle, OS.GWL_STYLE, bits | OS.WS_POPUP);
1225 OS.SetWindowLongPtr (handle, OS.GWLP_ID, 0);
1226 int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
1227 SetWindowPos (handle, cast(HWND)OS.HWND_BOTTOM, 0, 0, 0, 0, flags);
1228 display.lockActiveWindow = false;
1229 }
1230
1231 void setPlacement (int x, int y, int width, int height, int flags) {
1232 WINDOWPLACEMENT lpwndpl;
1233 lpwndpl.length = WINDOWPLACEMENT.sizeof;
1234 OS.GetWindowPlacement (handle, &lpwndpl);
1235 lpwndpl.showCmd = OS.SW_SHOWNA;
1236 if (OS.IsIconic (handle)) {
1237 lpwndpl.showCmd = OS.SW_SHOWMINNOACTIVE;
1238 } else {
1239 if (OS.IsZoomed (handle)) {
1240 lpwndpl.showCmd = OS.SW_SHOWMAXIMIZED;
1241 }
1242 }
1243 bool sameOrigin = true;
1244 if ((flags & OS.SWP_NOMOVE) is 0) {
1245 sameOrigin = lpwndpl.rcNormalPosition.left !is x || lpwndpl.rcNormalPosition.top !is y;
1246 lpwndpl.rcNormalPosition.right = x + (lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left);
1247 lpwndpl.rcNormalPosition.bottom = y + (lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top);
1248 lpwndpl.rcNormalPosition.left = x;
1249 lpwndpl.rcNormalPosition.top = y;
1250 }
1251 bool sameExtent = true;
1252 if ((flags & OS.SWP_NOSIZE) is 0) {
1253 sameExtent = lpwndpl.rcNormalPosition.right - lpwndpl.rcNormalPosition.left !is width || lpwndpl.rcNormalPosition.bottom - lpwndpl.rcNormalPosition.top !is height;
1254 lpwndpl.rcNormalPosition.right = lpwndpl.rcNormalPosition.left + width;
1255 lpwndpl.rcNormalPosition.bottom = lpwndpl.rcNormalPosition.top + height;
1256 }
1257 OS.SetWindowPlacement (handle, &lpwndpl);
1258 if (OS.IsIconic (handle)) {
1259 if (sameOrigin) {
1260 moved = true;
1261 Point location = getLocation ();
1262 oldX = location.x;
1263 oldY = location.y;
1264 sendEvent (SWT.Move);
1265 if (isDisposed ()) return;
1266 }
1267 if (sameExtent) {
1268 resized = true;
1269 Rectangle rect = getClientArea ();
1270 oldWidth = rect.width;
1271 oldHeight = rect.height;
1272 sendEvent (SWT.Resize);
1273 if (isDisposed ()) return;
1274 if (layout_ !is null) {
1275 markLayout (false, false);
1276 updateLayout (true, false);
1277 }
1278 }
1279 }
1280 }
1281
1282 void setSavedFocus (Control control) {
1283 savedFocus = control;
1284 }
1285
1286 void setSystemMenu () {
1287 static if (OS.IsWinCE) return;
1288 auto hMenu = OS.GetSystemMenu (handle, false);
1289 if (hMenu is null) return;
1290 int oldCount = OS.GetMenuItemCount (hMenu);
1291 if ((style & SWT.RESIZE) is 0) {
1292 OS.DeleteMenu (hMenu, OS.SC_SIZE, OS.MF_BYCOMMAND);
1293 }
1294 if ((style & SWT.MIN) is 0) {
1295 OS.DeleteMenu (hMenu, OS.SC_MINIMIZE, OS.MF_BYCOMMAND);
1296 }
1297 if ((style & SWT.MAX) is 0) {
1298 OS.DeleteMenu (hMenu, OS.SC_MAXIMIZE, OS.MF_BYCOMMAND);
1299 }
1300 if ((style & (SWT.MIN | SWT.MAX)) is 0) {
1301 OS.DeleteMenu (hMenu, OS.SC_RESTORE, OS.MF_BYCOMMAND);
1302 }
1303 int newCount = OS.GetMenuItemCount (hMenu);
1304 if ((style & SWT.CLOSE) is 0 || newCount !is oldCount) {
1305 OS.DeleteMenu (hMenu, OS.SC_TASKLIST, OS.MF_BYCOMMAND);
1306 MENUITEMINFO info;
1307 info.cbSize = OS.MENUITEMINFO_sizeof;
1308 info.fMask = OS.MIIM_ID;
1309 int index = 0;
1310 while (index < newCount) {
1311 if (OS.GetMenuItemInfo (hMenu, index, true, &info)) {
1312 if (info.wID is OS.SC_CLOSE) break;
1313 }
1314 index++;
1315 }
1316 if (index !is newCount) {
1317 OS.DeleteMenu (hMenu, index - 1, OS.MF_BYPOSITION);
1318 if ((style & SWT.CLOSE) is 0) {
1319 OS.DeleteMenu (hMenu, OS.SC_CLOSE, OS.MF_BYCOMMAND);
1320 }
1321 }
1322 }
1323 }
1324
1325 /**
1326 * Sets the receiver's text, which is the string that the
1327 * window manager will typically display as the receiver's
1328 * <em>title</em>, to the argument, which must not be null.
1329 *
1330 * @param string the new text
1331 *
1332 * @exception SWTException <ul>
1333 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1334 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1335 * </ul>
1336 */
1337 public void setText (String string) {
1338 checkWidget ();
1339 // SWT extension: allow null string
1340 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
1341 /* Use the character encoding for the default locale */
1342 TCHAR[] buffer = StrToTCHARs (string, true);
1343 /* Ensure that the title appears in the task bar.*/
1344 if ((state & FOREIGN_HANDLE) !is 0) {
1345 auto hHeap = OS.GetProcessHeap ();
1346 int byteCount = buffer.length * TCHAR.sizeof;
1347 auto pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
1348 OS.MoveMemory (pszText, buffer.ptr, byteCount);
1349 OS.DefWindowProc (handle, OS.WM_SETTEXT, 0, cast(int) pszText);
1350 if (pszText !is null) OS.HeapFree (hHeap, 0, pszText);
1351 } else {
1352 OS.SetWindowText (handle, buffer.ptr);
1353 }
1354 }
1355
1356 override public void setVisible (bool visible) {
1357 checkWidget ();
1358 if (drawCount !is 0) {
1359 if (((state & HIDDEN) is 0) is visible) return;
1360 } else {
1361 if (visible is OS.IsWindowVisible (handle)) return;
1362 }
1363 if (visible) {
1364 /*
1365 * It is possible (but unlikely), that application
1366 * code could have disposed the widget in the show
1367 * event. If this happens, just return.
1368 */
1369 sendEvent (SWT.Show);
1370 if (isDisposed ()) return;
1371 static if (OS.IsHPC) {
1372 if (menuBar !is null) {
1373 auto hwndCB = menuBar.hwndCB;
1374 OS.CommandBar_DrawMenuBar (hwndCB, 0);
1375 }
1376 }
1377 if (drawCount !is 0) {
1378 state &= ~HIDDEN;
1379 } else {
1380 static if (OS.IsWinCE) {
1381 OS.ShowWindow (handle, OS.SW_SHOW);
1382 } else {
1383 if (menuBar !is null) {
1384 display.removeBar (menuBar);
1385 OS.DrawMenuBar (handle);
1386 }
1387 STARTUPINFO* lpStartUpInfo = Display.lpStartupInfo;
1388 if (lpStartUpInfo !is null && (lpStartUpInfo.dwFlags & OS.STARTF_USESHOWWINDOW) !is 0) {
1389 OS.ShowWindow (handle, lpStartUpInfo.wShowWindow);
1390 } else {
1391 OS.ShowWindow (handle, swFlags);
1392 }
1393 }
1394 if (isDisposed ()) return;
1395 opened = true;
1396 if (!moved) {
1397 moved = true;
1398 Point location = getLocation ();
1399 oldX = location.x;
1400 oldY = location.y;
1401 }
1402 if (!resized) {
1403 resized = true;
1404 Rectangle rect = getClientArea ();
1405 oldWidth = rect.width;
1406 oldHeight = rect.height;
1407 }
1408 /*
1409 * Bug in Windows. On Vista using the Classic theme,
1410 * when the window is hung and UpdateWindow() is called,
1411 * nothing is drawn, and outstanding WM_PAINTs are cleared.
1412 * This causes pixel corruption. The fix is to avoid calling
1413 * update on hung windows.
1414 */
1415 bool update = true;
1416 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0) && !OS.IsAppThemed ()) {
1417 update = !OS.IsHungAppWindow (handle);
1418 }
1419 if (update) OS.UpdateWindow (handle);
1420 }
1421 } else {
1422 static if (!OS.IsWinCE) {
1423 if (OS.IsIconic (handle)) {
1424 swFlags = OS.SW_SHOWMINNOACTIVE;
1425 } else {
1426 if (OS.IsZoomed (handle)) {
1427 swFlags = OS.SW_SHOWMAXIMIZED;
1428 } else {
1429 swFlags = OS.SW_SHOWNOACTIVATE;
1430 }
1431 }
1432 }
1433 if (drawCount !is 0) {
1434 state |= HIDDEN;
1435 } else {
1436 OS.ShowWindow (handle, OS.SW_HIDE);
1437 }
1438 if (isDisposed ()) return;
1439 sendEvent (SWT.Hide);
1440 }
1441 }
1442
1443 void sort (Image [] images, ImageData [] datas, int width, int height, int depth) {
1444 /* Shell Sort from K&R, pg 108 */
1445 int length = images.length;
1446 if (length <= 1) return;
1447 for (int gap=length/2; gap>0; gap/=2) {
1448 for (int i=gap; i<length; i++) {
1449 for (int j=i-gap; j>=0; j-=gap) {
1450 if (compare (datas [j], datas [j + gap], width, height, depth) >= 0) {
1451 Image swap = images [j];
1452 images [j] = images [j + gap];
1453 images [j + gap] = swap;
1454 ImageData swapData = datas [j];
1455 datas [j] = datas [j + gap];
1456 datas [j + gap] = swapData;
1457 }
1458 }
1459 }
1460 }
1461 }
1462
1463 override bool translateAccelerator (MSG* msg) {
1464 if (!isEnabled () || !isActive ()) return false;
1465 if (menuBar !is null && !menuBar.isEnabled ()) return false;
1466 if (translateMDIAccelerator (msg) || translateMenuAccelerator (msg)) return true;
1467 Decorations decorations = parent.menuShell ();
1468 return decorations.translateAccelerator (msg);
1469 }
1470
1471 bool translateMenuAccelerator (MSG* msg) {
1472 if (hAccel is cast(HACCEL)-1) createAccelerators ();
1473 return hAccel !is null && OS.TranslateAccelerator (handle, hAccel, msg) !is 0;
1474 }
1475
1476 bool translateMDIAccelerator (MSG* msg) {
1477 if (!(cast(Shell)this)) {
1478 Shell shell = getShell ();
1479 auto hwndMDIClient = shell.hwndMDIClient_;
1480 if (hwndMDIClient !is null && OS.TranslateMDISysAccel (hwndMDIClient, msg)) {
1481 return true;
1482 }
1483 if (msg.message is OS.WM_KEYDOWN) {
1484 if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return false;
1485 switch ((msg.wParam)) {
1486 case OS.VK_F4:
1487 OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
1488 return true;
1489 case OS.VK_F6:
1490 if (traverseDecorations (true)) return true;
1491 default:
1492 }
1493 return false;
1494 }
1495 if (msg.message is OS.WM_SYSKEYDOWN) {
1496 switch ((msg.wParam)) {
1497 case OS.VK_F4:
1498 OS.PostMessage (shell.handle, OS.WM_CLOSE, 0, 0);
1499 return true;
1500 default:
1501 }
1502 return false;
1503 }
1504 }
1505 return false;
1506 }
1507
1508 bool traverseDecorations (bool next) {
1509 Control [] children = parent._getChildren ();
1510 int length = children.length;
1511 int index = 0;
1512 while (index < length) {
1513 if (children [index] is this) break;
1514 index++;
1515 }
1516 /*
1517 * It is possible (but unlikely), that application
1518 * code could have disposed the widget in focus in
1519 * or out events. Ensure that a disposed widget is
1520 * not accessed.
1521 */
1522 int start = index, offset = (next) ? 1 : -1;
1523 while ((index = (index + offset + length) % length) !is start) {
1524 Control child = children [index];
1525 if (!child.isDisposed () && ( null !is cast(Decorations)child)) {
1526 if (child.setFocus ()) return true;
1527 }
1528 }
1529 return false;
1530 }
1531
1532 override bool traverseItem (bool next) {
1533 return false;
1534 }
1535
1536 override bool traverseReturn () {
1537 if (defaultButton is null || defaultButton.isDisposed ()) return false;
1538 if (!defaultButton.isVisible () || !defaultButton.isEnabled ()) return false;
1539 defaultButton.click ();
1540 return true;
1541 }
1542
1543 override CREATESTRUCT* widgetCreateStruct () {
1544 return new CREATESTRUCT ();
1545 }
1546
1547 override int widgetExtStyle () {
1548 int bits = super.widgetExtStyle () | OS.WS_EX_MDICHILD;
1549 bits &= ~OS.WS_EX_CLIENTEDGE;
1550 if ((style & SWT.NO_TRIM) !is 0) return bits;
1551 if (OS.IsPPC) {
1552 if ((style & SWT.CLOSE) !is 0) bits |= OS.WS_EX_CAPTIONOKBTN;
1553 }
1554 if ((style & SWT.RESIZE) !is 0) return bits;
1555 if ((style & SWT.BORDER) !is 0) bits |= OS.WS_EX_DLGMODALFRAME;
1556 return bits;
1557 }
1558
1559 override HWND widgetParent () {
1560 Shell shell = getShell ();
1561 return shell.hwndMDIClient ();
1562 }
1563
1564 override int widgetStyle () {
1565 /*
1566 * Clear WS_VISIBLE and WS_TABSTOP. NOTE: In Windows, WS_TABSTOP
1567 * has the same value as WS_MAXIMIZEBOX so these bits cannot be
1568 * used to control tabbing.
1569 */
1570 int bits = super.widgetStyle () & ~(OS.WS_TABSTOP | OS.WS_VISIBLE);
1571
1572 /* Set the title bits and no-trim bits */
1573 bits &= ~OS.WS_BORDER;
1574 if ((style & SWT.NO_TRIM) !is 0) return bits;
1575 if ((style & SWT.TITLE) !is 0) bits |= OS.WS_CAPTION;
1576
1577 /* Set the min and max button bits */
1578 if ((style & SWT.MIN) !is 0) bits |= OS.WS_MINIMIZEBOX;
1579 if ((style & SWT.MAX) !is 0) bits |= OS.WS_MAXIMIZEBOX;
1580
1581 /* Set the resize, dialog border or border bits */
1582 if ((style & SWT.RESIZE) !is 0) {
1583 /*
1584 * Note on WinCE PPC. SWT.RESIZE is used to resize
1585 * the Shell according to the state of the IME.
1586 * It does not set the WS_THICKFRAME style.
1587 */
1588 if (!OS.IsPPC) bits |= OS.WS_THICKFRAME;
1589 } else {
1590 if ((style & SWT.BORDER) is 0) bits |= OS.WS_BORDER;
1591 }
1592
1593 /* Set the system menu and close box bits */
1594 if (!OS.IsPPC && !OS.IsSP) {
1595 if ((style & SWT.CLOSE) !is 0) bits |= OS.WS_SYSMENU;
1596 }
1597
1598 return bits;
1599 }
1600
1601 override int windowProc (HWND hwnd, int msg, int wParam, int lParam) {
1602 switch (msg) {
1603 case Display.SWT_GETACCEL:
1604 case Display.SWT_GETACCELCOUNT:
1605 if (hAccel is cast(HACCEL)-1) createAccelerators ();
1606 return msg is Display.SWT_GETACCELCOUNT ? nAccel : cast(int)hAccel;
1607 default:
1608 }
1609 return super.windowProc (hwnd, msg, wParam, lParam);
1610 }
1611
1612 override LRESULT WM_ACTIVATE (int wParam, int lParam) {
1613 LRESULT result = super.WM_ACTIVATE (wParam, lParam);
1614 if (result !is null) return result;
1615 /*
1616 * Feature in AWT. When an AWT Window is activated,
1617 * for some reason, it seems to forward the WM_ACTIVATE
1618 * message to the parent. Normally, the parent is an
1619 * AWT Frame. When AWT is embedded in SWT, the SWT
1620 * shell gets the WM_ACTIVATE and assumes that it came
1621 * from Windows. When an SWT shell is activated it
1622 * restores focus to the last control that had focus.
1623 * If this control is an embedded composite, it takes
1624 * focus from the AWT Window. The fix is to ignore
1625 * WM_ACTIVATE messages that come from AWT Windows.
1626 */
1627 if (OS.GetParent ( cast(HWND)lParam) is handle) {
1628 TCHAR[128] buffer = 0;
1629 OS.GetClassName (cast(HWND)lParam, buffer.ptr, buffer.length );
1630 String className = TCHARzToStr( buffer.ptr );
1631 if (className == Display.AWT_WINDOW_CLASS) {
1632 return LRESULT.ZERO;
1633 }
1634 }
1635 if (OS.LOWORD (wParam) !is 0) {
1636 /*
1637 * When the high word of wParam is non-zero, the activation
1638 * state of the window is being changed while the window is
1639 * minimized. If this is the case, do not report activation
1640 * events or restore the focus.
1641 */
1642 if (OS.HIWORD (wParam) !is 0) return result;
1643 Control control = display.findControl (cast(HWND)lParam);
1644 if (control is null || (null !is cast(Shell)control)) {
1645 if (cast(Shell)this) {
1646 sendEvent (SWT.Activate);
1647 if (isDisposed ()) return LRESULT.ZERO;
1648 }
1649 }
1650 if (restoreFocus ()) return LRESULT.ZERO;
1651 } else {
1652 Display display = this.display;
1653 bool lockWindow = display.isXMouseActive ();
1654 if (lockWindow) display.lockActiveWindow = true;
1655 Control control = display.findControl (cast(HWND)lParam);
1656 if (control is null || (null !is cast(Shell)control)) {
1657 if (cast(Shell)this) {
1658 sendEvent (SWT.Deactivate);
1659 if (!isDisposed ()) {
1660 Shell shell = getShell ();
1661 shell.setActiveControl (null);
1662 // widget could be disposed at this point
1663 }
1664 }
1665 }
1666 if (lockWindow) display.lockActiveWindow = false;
1667 if (isDisposed ()) return LRESULT.ZERO;
1668 saveFocus ();
1669 }
1670 return result;
1671 }
1672
1673 override LRESULT WM_CLOSE (int wParam, int lParam) {
1674 LRESULT result = super.WM_CLOSE (wParam, lParam);
1675 if (result !is null) return result;
1676 if (isEnabled () && isActive ()) closeWidget ();
1677 return LRESULT.ZERO;
1678 }
1679
1680 override LRESULT WM_HOTKEY (int wParam, int lParam) {
1681 LRESULT result = super.WM_HOTKEY (wParam, lParam);
1682 if (result !is null) return result;
1683 static if( OS.IsWinCE ){
1684 if (OS.IsSP) {
1685 /*
1686 * Feature on WinCE SP. The Back key is either used to close
1687 * the foreground Dialog or used as a regular Back key in an EDIT
1688 * control. The article 'Back Key' in MSDN for Smartphone
1689 * describes how an application should handle it. The
1690 * workaround is to override the Back key when creating
1691 * the menubar and handle it based on the style of the Shell.
1692 * If the Shell has the SWT.CLOSE style, close the Shell.
1693 * Otherwise, send the Back key to the window with focus.
1694 */
1695 if (OS.HIWORD (lParam) is OS.VK_ESCAPE) {
1696 if ((style & SWT.CLOSE) !is 0) {
1697 OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
1698 } else {
1699 OS.SHSendBackToFocusWindow (OS.WM_HOTKEY, wParam, lParam);
1700 }
1701 return LRESULT.ZERO;
1702 }
1703 }
1704 }
1705 return result;
1706 }
1707
1708 override LRESULT WM_KILLFOCUS (int wParam, int lParam) {
1709 LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
1710 saveFocus ();
1711 return result;
1712 }
1713
1714 override LRESULT WM_MOVE (int wParam, int lParam) {
1715 if (moved) {
1716 Point location = getLocation ();
1717 if (location.x is oldX && location.y is oldY) {
1718 return null;
1719 }
1720 oldX = location.x;
1721 oldY = location.y;
1722 }
1723 return super.WM_MOVE (wParam, lParam);
1724 }
1725
1726 override LRESULT WM_NCACTIVATE (int wParam, int lParam) {
1727 LRESULT result = super.WM_NCACTIVATE (wParam, lParam);
1728 if (result !is null) return result;
1729 if (wParam is 0) {
1730 if (display.lockActiveWindow) return LRESULT.ZERO;
1731 Control control = display.findControl (cast(HANDLE)lParam);
1732 if (control !is null) {
1733 Shell shell = getShell ();
1734 Decorations decorations = control.menuShell ();
1735 if (decorations.getShell () is shell) {
1736 if (cast(Shell)this) return LRESULT.ONE;
1737 if (display.ignoreRestoreFocus) {
1738 if (display.lastHittest !is OS.HTCLIENT) {
1739 result = LRESULT.ONE;
1740 }
1741 }
1742 }
1743 }
1744 }
1745 if (!(cast(Shell)this)) {
1746 auto hwndShell = getShell().handle;
1747 OS.SendMessage (hwndShell, OS.WM_NCACTIVATE, wParam, lParam);
1748 }
1749 return result;
1750 }
1751
1752 override LRESULT WM_QUERYOPEN (int wParam, int lParam) {
1753 LRESULT result = super.WM_QUERYOPEN (wParam, lParam);
1754 if (result !is null) return result;
1755 sendEvent (SWT.Deiconify);
1756 // widget could be disposed at this point
1757 return result;
1758 }
1759
1760 override LRESULT WM_SETFOCUS (int wParam, int lParam) {
1761 LRESULT result = super.WM_SETFOCUS (wParam, lParam);
1762 if (savedFocus !is this) restoreFocus ();
1763 return result;
1764 }
1765
1766 override LRESULT WM_SIZE (int wParam, int lParam) {
1767 LRESULT result = null;
1768 bool changed = true;
1769 if (resized) {
1770 int newWidth = 0, newHeight = 0;
1771 switch (wParam) {
1772 case OS.SIZE_RESTORED:
1773 case OS.SIZE_MAXIMIZED:
1774 newWidth = OS.LOWORD (lParam);
1775 newHeight = OS.HIWORD (lParam);
1776 break;
1777 case OS.SIZE_MINIMIZED:
1778 Rectangle rect = getClientArea ();
1779 newWidth = rect.width;
1780 newHeight = rect.height;
1781 break;
1782 default:
1783 }
1784 changed = newWidth !is oldWidth || newHeight !is oldHeight;
1785 if (changed) {
1786 oldWidth = newWidth;
1787 oldHeight = newHeight;
1788 }
1789 }
1790 if (changed) {
1791 result = super.WM_SIZE (wParam, lParam);
1792 if (isDisposed ()) return result;
1793 }
1794 if (wParam is OS.SIZE_MINIMIZED) {
1795 sendEvent (SWT.Iconify);
1796 // widget could be disposed at this point
1797 }
1798 return result;
1799 }
1800
1801 override LRESULT WM_SYSCOMMAND (int wParam, int lParam) {
1802 LRESULT result = super.WM_SYSCOMMAND (wParam, lParam);
1803 if (result !is null) return result;
1804 if (!(cast(Shell)this)) {
1805 int cmd = wParam & 0xFFF0;
1806 switch (cmd) {
1807 case OS.SC_CLOSE: {
1808 OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
1809 return LRESULT.ZERO;
1810 }
1811 case OS.SC_NEXTWINDOW: {
1812 traverseDecorations (true);
1813 return LRESULT.ZERO;
1814 }
1815 default:
1816 }
1817 }
1818 return result;
1819 }
1820
1821 override LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
1822 LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
1823 if (result !is null) return result;
1824 if (display.lockActiveWindow) {
1825 WINDOWPOS* lpwp = cast(WINDOWPOS*)lParam;
1826 //OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
1827 lpwp.flags |= OS.SWP_NOZORDER;
1828 //OS.MoveMemory (lParam, &lpwp, WINDOWPOS.sizeof);
1829 }
1830 return result;
1831 }
1832
1833 }