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 import org.eclipse.swt.widgets.Control;
16 import org.eclipse.swt.widgets.Menu;
17 import org.eclipse.swt.widgets.Composite;
18 
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.internal.gtk.OS;
21 //import org.eclipse.swt.graphics.;
22 import org.eclipse.swt.widgets.Canvas;
23 import org.eclipse.swt.graphics.Image;
24 import org.eclipse.swt.graphics.ImageData;
25 import org.eclipse.swt.widgets.Control;
26 import org.eclipse.swt.widgets.Display;
27 import org.eclipse.swt.widgets.Widget;
28 import org.eclipse.swt.widgets.Button;
29 import java.lang.all;
30 
31 /**
32  * Instances of this class provide the appearance and
33  * behavior of <code>Shells</code>, but are not top
34  * level shells or dialogs. Class <code>Shell</code>
35  * shares a significant amount of code with this class,
36  * and is a subclass.
37  * <p>
38  * IMPORTANT: This class was intended to be abstract and
39  * should <em>never</em> be referenced or instantiated.
40  * Instead, the class <code>Shell</code> should be used.
41  * </p>
42  * <p>
43  * Instances are always displayed in one of the maximized,
44  * minimized or normal states:
45  * <ul>
46  * <li>
47  * When an instance is marked as <em>maximized</em>, the
48  * window manager will typically resize it to fill the
49  * entire visible area of the display, and the instance
50  * is usually put in a state where it can not be resized
51  * (even if it has style <code>RESIZE</code>) until it is
52  * no longer maximized.
53  * </li><li>
54  * When an instance is in the <em>normal</em> state (neither
55  * maximized or minimized), its appearance is controlled by
56  * the style constants which were specified when it was created
57  * and the restrictions of the window manager (see below).
58  * </li><li>
59  * When an instance has been marked as <em>minimized</em>,
60  * its contents (client area) will usually not be visible,
61  * and depending on the window manager, it may be
62  * "iconified" (that is, replaced on the desktop by a small
63  * simplified representation of itself), relocated to a
64  * distinguished area of the screen, or hidden. Combinations
65  * of these changes are also possible.
66  * </li>
67  * </ul>
68  * </p>
69  * Note: The styles supported by this class must be treated
70  * as <em>HINT</em>s, since the window manager for the
71  * desktop on which the instance is visible has ultimate
72  * control over the appearance and behavior of decorations.
73  * For example, some window managers only support resizable
74  * windows and will always assume the RESIZE style, even if
75  * it is not set.
76  * <dl>
77  * <dt><b>Styles:</b></dt>
78  * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd>
79  * <dt><b>Events:</b></dt>
80  * <dd>(none)</dd>
81  * </dl>
82  * Class <code>SWT</code> provides two "convenience constants"
83  * for the most commonly required style combinations:
84  * <dl>
85  * <dt><code>SHELL_TRIM</code></dt>
86  * <dd>
87  * the result of combining the constants which are required
88  * to produce a typical application top level shell: (that
89  * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
90  * </dd>
91  * <dt><code>DIALOG_TRIM</code></dt>
92  * <dd>
93  * the result of combining the constants which are required
94  * to produce a typical application dialog shell: (that
95  * is, <code>TITLE | CLOSE | BORDER</code>)
96  * </dd>
97  * </dl>
98  * <p>
99  * IMPORTANT: This class is intended to be subclassed <em>only</em>
100  * within the SWT implementation.
101  * </p>
102  *
103  * @see #getMinimized
104  * @see #getMaximized
105  * @see Shell
106  * @see SWT
107  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
108  */
109 public class Decorations : Canvas {
110 
111     alias Canvas.sort sort;
112 
113     String text;
114     Image image;
115     Image [] images;
116     bool minimized, maximized;
117     Menu menuBar;
118     Menu [] menus;
119     Control savedFocus;
120     Button defaultButton, saveDefault;
121     GtkAccelGroup* accelGroup;
122     GtkWidget* vboxHandle;
123 
124 this () {
125     /* Do nothing */
126 }
127 
128 /**
129  * Constructs a new instance of this class given its parent
130  * and a style value describing its behavior and appearance.
131  * <p>
132  * The style value is either one of the style constants defined in
133  * class <code>SWT</code> which is applicable to instances of this
134  * class, or must be built by <em>bitwise OR</em>'ing together
135  * (that is, using the <code>int</code> "|" operator) two or more
136  * of those <code>SWT</code> style constants. The class description
137  * lists the style constants that are applicable to the class.
138  * Style bits are also inherited from superclasses.
139  * </p>
140  *
141  * @param parent a composite control which will be the parent of the new instance (cannot be null)
142  * @param style the style of control to construct
143  *
144  * @exception IllegalArgumentException <ul>
145  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
146  * </ul>
147  * @exception SWTException <ul>
148  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
149  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
150  * </ul>
151  *
152  * @see SWT#BORDER
153  * @see SWT#CLOSE
154  * @see SWT#MIN
155  * @see SWT#MAX
156  * @see SWT#RESIZE
157  * @see SWT#TITLE
158  * @see SWT#NO_TRIM
159  * @see SWT#SHELL_TRIM
160  * @see SWT#DIALOG_TRIM
161  * @see SWT#ON_TOP
162  * @see SWT#TOOL
163  * @see Widget#checkSubclass
164  * @see Widget#getStyle
165  */
166 public this (Composite parent, int style) {
167     super (parent, checkStyle (style));
168 }
169 
170 static int checkStyle (int style) {
171     if ((style & SWT.NO_TRIM) !is 0) {
172         style &= ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER);
173     }
174     if ((style & (SWT.MENU | SWT.MIN | SWT.MAX | SWT.CLOSE)) !is 0) {
175         style |= SWT.TITLE;
176     }
177     return style;
178 }
179 
180 override protected void checkSubclass () {
181     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
182 }
183 
184 void _setImages (Image [] images) {
185     if (images !is null && images.length > 1) {
186         Image [] bestImages = new Image [images.length];
187         System.arraycopy (images, 0, bestImages, 0, images.length);
188         sort (bestImages);
189         images = bestImages;
190     }
191     GList* pixbufs;
192     if (images !is null) {
193         for (int i = 0; i < images.length; i++) {
194             Image image = images [i];
195             auto pixbuf = Display.createPixbuf (image);
196             pixbufs = OS.g_list_append (pixbufs, pixbuf);
197         }
198     }
199     OS.gtk_window_set_icon_list (cast(GtkWindow*)topHandle (), pixbufs);
200     GList* data;
201     auto temp = pixbufs;
202     while (temp !is null) {
203         data = *cast(GList**)temp;
204         OS.g_object_unref (data);
205         temp = cast(GList*)OS.g_list_next (temp);
206     }
207     if (pixbufs !is null) OS.g_list_free (pixbufs);
208 }
209 
210 void addMenu (Menu menu) {
211     if (menus is null) menus = new Menu [4];
212     for (int i=0; i<menus.length; i++) {
213         if (menus [i] is null) {
214             menus [i] = menu;
215             return;
216         }
217     }
218     Menu [] newMenus = new Menu [menus.length + 4];
219     newMenus [menus.length] = menu;
220     System.arraycopy (menus, 0, newMenus, 0, menus.length);
221     menus = newMenus;
222 }
223 
224 int compare (ImageData data1, ImageData data2) {
225     if (data1.width is data2.width && data1.height is data2.height) {
226         int transparent1 = data1.getTransparencyType ();
227         int transparent2 = data2.getTransparencyType ();
228         if (transparent1 is SWT.TRANSPARENCY_ALPHA) return -1;
229         if (transparent2 is SWT.TRANSPARENCY_ALPHA) return 1;
230         if (transparent1 is SWT.TRANSPARENCY_MASK) return -1;
231         if (transparent2 is SWT.TRANSPARENCY_MASK) return 1;
232         if (transparent1 is SWT.TRANSPARENCY_PIXEL) return -1;
233         if (transparent2 is SWT.TRANSPARENCY_PIXEL) return 1;
234         return 0;
235     }
236     return data1.width > data2.width || data1.height > data2.height ? -1 : 1;
237 }
238 
239 override Control computeTabGroup () {
240     return this;
241 }
242 
243 override Control computeTabRoot () {
244     return this;
245 }
246 
247 void createAccelGroup () {
248     if (accelGroup !is null) return;
249     accelGroup = OS.gtk_accel_group_new ();
250     if (accelGroup is null) SWT.error (SWT.ERROR_NO_HANDLES);
251     //FIXME - what should we do for Decorations
252     auto shellHandle = topHandle ();
253     OS.gtk_window_add_accel_group (cast(GtkWindow*)shellHandle, accelGroup);
254 }
255 
256 override void createWidget (int index) {
257     super.createWidget (index);
258     text = "";
259 }
260 
261 void destroyAccelGroup () {
262     if (accelGroup is null) return;
263     auto shellHandle = topHandle ();
264     OS.gtk_window_remove_accel_group (cast(GtkWindow*)shellHandle, accelGroup);
265     //TEMPORARY CODE
266 //  OS.g_object_unref (accelGroup);
267     accelGroup = null;
268 }
269 
270 void fixAccelGroup () {
271     if (menuBar is null) return;
272     destroyAccelGroup ();
273     createAccelGroup ();
274     menuBar.addAccelerators (accelGroup);
275 }
276 
277 void fixDecorations (Decorations newDecorations, Control control, Menu [] menus) {
278     if (this is newDecorations) return;
279     if (control is savedFocus) savedFocus = null;
280     if (control is defaultButton) defaultButton = null;
281     if (control is saveDefault) saveDefault = null;
282     if (menus is null) return;
283     Menu menu = control.menu;
284     if (menu !is null) {
285         int index = 0;
286         while (index <menus.length) {
287             if (menus [index] is menu) {
288                 control.setMenu (null);
289                 return;
290             }
291             index++;
292         }
293         menu.fixMenus (newDecorations);
294     }
295 }
296 
297 /**
298  * Returns the receiver's default button if one had
299  * previously been set, otherwise returns null.
300  *
301  * @return the default button or null
302  *
303  * @exception SWTException <ul>
304  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
305  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
306  * </ul>
307  *
308  * @see #setDefaultButton(Button)
309  */
310 public Button getDefaultButton () {
311     checkWidget();
312     return defaultButton !is null ? defaultButton : saveDefault;
313 }
314 
315 /**
316  * Returns the receiver's image if it had previously been
317  * set using <code>setImage()</code>. The image is typically
318  * displayed by the window manager when the instance is
319  * marked as iconified, and may also be displayed somewhere
320  * in the trim when the instance is in normal or maximized
321  * states.
322  * <p>
323  * Note: This method will return null if called before
324  * <code>setImage()</code> is called. It does not provide
325  * access to a window manager provided, "default" image
326  * even if one exists.
327  * </p>
328  *
329  * @return the image
330  *
331  * @exception SWTException <ul>
332  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
333  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
334  * </ul>
335  */
336 public Image getImage () {
337     checkWidget ();
338     return image;
339 }
340 
341 /**
342  * Returns the receiver's images if they had previously been
343  * set using <code>setImages()</code>. Images are typically
344  * displayed by the window manager when the instance is
345  * marked as iconified, and may also be displayed somewhere
346  * in the trim when the instance is in normal or maximized
347  * states. Depending where the icon is displayed, the platform
348  * chooses the icon with the "best" attributes.  It is expected
349  * that the array will contain the same icon rendered at different
350  * sizes, with different depth and transparency attributes.
351  *
352  * <p>
353  * Note: This method will return an empty array if called before
354  * <code>setImages()</code> is called. It does not provide
355  * access to a window manager provided, "default" image
356  * even if one exists.
357  * </p>
358  *
359  * @return the images
360  *
361  * @exception SWTException <ul>
362  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
363  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
364  * </ul>
365  *
366  * @since 3.0
367  */
368 public Image [] getImages () {
369     checkWidget ();
370     if (images is null) return new Image [0];
371     Image [] result = new Image [images.length];
372     System.arraycopy (images, 0, result, 0, images.length);
373     return result;
374 }
375 
376 /**
377  * Returns <code>true</code> if the receiver is currently
378  * maximized, and false otherwise.
379  * <p>
380  *
381  * @return the maximized state
382  *
383  * @exception SWTException <ul>
384  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
385  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
386  * </ul>
387  *
388  * @see #setMaximized
389  */
390 public bool getMaximized () {
391     checkWidget();
392     return maximized;
393 }
394 
395 /**
396  * Returns the receiver's menu bar if one had previously
397  * been set, otherwise returns null.
398  *
399  * @return the menu bar or null
400  *
401  * @exception SWTException <ul>
402  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
403  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
404  * </ul>
405  */
406 public Menu getMenuBar () {
407     checkWidget();
408     return menuBar;
409 }
410 
411 /**
412  * Returns <code>true</code> if the receiver is currently
413  * minimized, and false otherwise.
414  * <p>
415  *
416  * @return the minimized state
417  *
418  * @exception SWTException <ul>
419  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
420  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
421  * </ul>
422  *
423  * @see #setMinimized
424  */
425 public bool getMinimized () {
426     checkWidget();
427     return minimized;
428 }
429 
430 override String getNameText () {
431     return getText ();
432 }
433 
434 /**
435  * Returns the receiver's text, which is the string that the
436  * window manager will typically display as the receiver's
437  * <em>title</em>. If the text has not previously been set,
438  * returns an empty string.
439  *
440  * @return the text
441  *
442  * @exception SWTException <ul>
443  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
444  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
445  * </ul>
446  */
447 public String getText () {
448     checkWidget();
449     return text;
450 }
451 
452 override public bool isReparentable () {
453     checkWidget ();
454     return false;
455 }
456 
457 override bool isTabGroup () {
458     return true;
459 }
460 
461 override bool isTabItem () {
462     return false;
463 }
464 
465 override Decorations menuShell () {
466     return this;
467 }
468 
469 void removeMenu (Menu menu) {
470     if (menus is null) return;
471     for (int i=0; i<menus.length; i++) {
472         if (menus [i] is menu) {
473             menus [i] = null;
474             return;
475         }
476     }
477 }
478 
479 override void releaseChildren (bool destroy) {
480     if (menuBar !is null) {
481         menuBar.release (false);
482         menuBar = null;
483     }
484     super.releaseChildren (destroy);
485     if (menus !is null) {
486         for (int i=0; i<menus.length; i++) {
487             Menu menu = menus [i];
488             if (menu !is null && !menu.isDisposed ()) {
489                 menu.dispose ();
490             }
491         }
492         menus = null;
493     }
494 }
495 
496 override void releaseHandle () {
497     super.releaseHandle ();
498     vboxHandle = null;
499 }
500 
501 override void releaseWidget () {
502     super.releaseWidget ();
503     image = null;
504     images = null;
505     savedFocus = null;
506     defaultButton = saveDefault = null;
507 }
508 
509 bool restoreFocus () {
510     if (savedFocus !is null && savedFocus.isDisposed ()) savedFocus = null;
511     bool restored = savedFocus !is null && savedFocus.setFocus ();
512     savedFocus = null;
513     /*
514     * This code is intentionally commented.  When no widget
515     * has been given focus, some platforms give focus to the
516     * default button.  Motif doesn't do this.
517     */
518 //  if (restored) return true;
519 //  if (defaultButton !is null && !defaultButton.isDisposed ()) {
520 //      if (defaultButton.setFocus ()) return true;
521 //  }
522 //  return false;
523     return restored;
524 }
525 
526 /**
527  * If the argument is not null, sets the receiver's default
528  * button to the argument, and if the argument is null, sets
529  * the receiver's default button to the first button which
530  * was set as the receiver's default button (called the
531  * <em>saved default button</em>). If no default button had
532  * previously been set, or the saved default button was
533  * disposed, the receiver's default button will be set to
534  * null.
535  * <p>
536  * The default button is the button that is selected when
537  * the receiver is active and the user presses ENTER.
538  * </p>
539  *
540  * @param button the new default button
541  *
542  * @exception IllegalArgumentException <ul>
543  *    <li>ERROR_INVALID_ARGUMENT - if the button has been disposed</li>
544  *    <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
545  * </ul>
546  * @exception SWTException <ul>
547  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
548  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
549  * </ul>
550  */
551 public void setDefaultButton (Button button) {
552     checkWidget();
553     GtkWidget* buttonHandle;
554     if (button !is null) {
555         if (button.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
556         if (button.menuShell () !is this) error (SWT.ERROR_INVALID_PARENT);
557         buttonHandle = button.handle;
558     }
559     saveDefault = defaultButton = button;
560     OS.gtk_window_set_default (cast(GtkWindow*)topHandle (), buttonHandle);
561 }
562 
563 /**
564  * Sets the receiver's image to the argument, which may
565  * be null. The image is typically displayed by the window
566  * manager when the instance is marked as iconified, and
567  * may also be displayed somewhere in the trim when the
568  * instance is in normal or maximized states.
569  *
570  * @param image the new image (or null)
571  *
572  * @exception IllegalArgumentException <ul>
573  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
574  * </ul>
575  * @exception SWTException <ul>
576  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
577  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
578  * </ul>
579  */
580 public void setImage (Image image) {
581     checkWidget ();
582     this.image = image;
583     _setImages (image !is null ? [image] : null);
584 }
585 
586 /**
587  * Sets the receiver's images to the argument, which may
588  * be an empty array. Images are typically displayed by the
589  * window manager when the instance is marked as iconified,
590  * and may also be displayed somewhere in the trim when the
591  * instance is in normal or maximized states. Depending where
592  * the icon is displayed, the platform chooses the icon with
593  * the "best" attributes. It is expected that the array will
594  * contain the same icon rendered at different sizes, with
595  * different depth and transparency attributes.
596  *
597  * @param images the new image array
598  *
599  * @exception IllegalArgumentException <ul>
600  *    <li>ERROR_INVALID_ARGUMENT - if one of the images is null or has been disposed</li>
601  * </ul>
602  * @exception SWTException <ul>
603  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
604  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
605  * </ul>
606  *
607  * @since 3.0
608  */
609 public void setImages (Image [] images) {
610     checkWidget ();
611     // SWT extension: allow null for zero length string
612     //if (images is null) error (SWT.ERROR_INVALID_ARGUMENT);
613     for (int i = 0; i < images.length; i++) {
614         if (images [i] is null || images [i].isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
615     }
616     this.images = images;
617     _setImages (images);
618 }
619 
620 /**
621  * Sets the maximized state of the receiver.
622  * If the argument is <code>true</code> causes the receiver
623  * to switch to the maximized state, and if the argument is
624  * <code>false</code> and the receiver was previously maximized,
625  * causes the receiver to switch back to either the minimized
626  * or normal states.
627  * <p>
628  * Note: The result of intermixing calls to <code>setMaximized(true)</code>
629  * and <code>setMinimized(true)</code> will vary by platform. Typically,
630  * the behavior will match the platform user's expectations, but not
631  * always. This should be avoided if possible.
632  * </p>
633  *
634  * @param maximized the new maximized state
635  *
636  * @exception SWTException <ul>
637  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
638  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
639  * </ul>
640  *
641  * @see #setMinimized
642  */
643 public void setMaximized (bool maximized) {
644     checkWidget();
645     this.maximized = maximized;
646 }
647 
648 /**
649  * Sets the receiver's menu bar to the argument, which
650  * may be null.
651  *
652  * @param menu the new menu bar
653  *
654  * @exception IllegalArgumentException <ul>
655  *    <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
656  *    <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li>
657  * </ul>
658  * @exception SWTException <ul>
659  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
660  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
661  * </ul>
662  */
663 public void setMenuBar (Menu menu) {
664     checkWidget();
665     if (menuBar is menu) return;
666     if (menu !is null) {
667         if ((menu.style & SWT.BAR) is 0) error (SWT.ERROR_MENU_NOT_BAR);
668         if (menu.parent !is this) error (SWT.ERROR_INVALID_PARENT);
669     }
670     menuBar = menu;
671 }
672 
673 /**
674  * Sets the minimized stated of the receiver.
675  * If the argument is <code>true</code> causes the receiver
676  * to switch to the minimized state, and if the argument is
677  * <code>false</code> and the receiver was previously minimized,
678  * causes the receiver to switch back to either the maximized
679  * or normal states.
680  * <p>
681  * Note: The result of intermixing calls to <code>setMaximized(true)</code>
682  * and <code>setMinimized(true)</code> will vary by platform. Typically,
683  * the behavior will match the platform user's expectations, but not
684  * always. This should be avoided if possible.
685  * </p>
686  *
687  * @param minimized the new maximized state
688  *
689  * @exception SWTException <ul>
690  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
691  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
692  * </ul>
693  *
694  * @see #setMaximized
695  */
696 public void setMinimized (bool minimized) {
697     checkWidget();
698     this.minimized = minimized;
699 }
700 
701 void setSavedFocus (Control control) {
702     if (this is control) return;
703     savedFocus = control;
704 }
705 
706 /**
707  * Sets the receiver's text, which is the string that the
708  * window manager will typically display as the receiver's
709  * <em>title</em>, to the argument, which must not be null.
710  *
711  * @param string the new text
712  *
713  * @exception SWTException <ul>
714  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
715  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
716  * </ul>
717  */
718 public void setText (String string) {
719     checkWidget();
720     // SWT extension: allow null for zero length string
721     //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
722     text = string;
723 }
724 
725 void sort (Image [] images) {
726     /* Shell Sort from K&R, pg 108 */
727     ptrdiff_t length = images.length;
728     if (length <= 1) return;
729     ImageData [] datas = new ImageData [length];
730     for (int i = 0; i < length; i++) {
731         datas [i] = images [i].getImageData ();
732     }
733     for (ptrdiff_t gap=length/2; gap>0; gap/=2) {
734         for (ptrdiff_t i=gap; i<length; i++) {
735             for (ptrdiff_t j=i-gap; j>=0; j-=gap) {
736                 if (compare (datas [j], datas [j + gap]) >= 0) {
737                     Image swap = images [j];
738                     images [j] = images [j + gap];
739                     images [j + gap] = swap;
740                     ImageData swapData = datas [j];
741                     datas [j] = datas [j + gap];
742                     datas [j + gap] = swapData;
743                 }
744             }
745         }
746     }
747 }
748 
749 override bool traverseItem (bool next) {
750     return false;
751 }
752 
753 override bool traverseReturn () {
754     Button button = defaultButton !is null ? defaultButton: saveDefault;
755     if (button is null || button.isDisposed ()) return false;
756     /*
757     * Bug in GTK.  When a default button that is disabled is
758     * activated using the Enter key, GTK GP's.  The fix is to
759     * detect this case and stop GTK from processing the Enter
760     * key.
761     */
762     if (!button.isVisible () || !button.isEnabled ()) return true;
763     auto shellHandle = _getShell ().topHandle ();
764     return cast(bool)OS.gtk_window_activate_default (cast(GtkWindow*)shellHandle);
765 }
766 
767 }