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.Shell;
14 
15 import java.lang.all;
16 
17 import org.eclipse.swt.widgets.Composite;
18 import org.eclipse.swt.widgets.Control;
19 //import org.eclipse.swt.internal.c.gtk;
20 
21 import org.eclipse.swt.SWT;
22 import org.eclipse.swt.internal.gtk.OS;
23 import org.eclipse.swt.events.ShellListener;
24 import org.eclipse.swt.graphics.Cursor;
25 import org.eclipse.swt.graphics.GC;
26 import org.eclipse.swt.graphics.Image;
27 import org.eclipse.swt.graphics.Point;
28 import org.eclipse.swt.graphics.Rectangle;
29 import org.eclipse.swt.graphics.Region;
30 import org.eclipse.swt.internal.Converter;
31 import org.eclipse.swt.internal.SWTEventListener;
32 import org.eclipse.swt.widgets.Composite;
33 import org.eclipse.swt.widgets.Control;
34 import org.eclipse.swt.widgets.Decorations;
35 import org.eclipse.swt.widgets.Display;
36 import org.eclipse.swt.widgets.Event;
37 import org.eclipse.swt.widgets.EventTable;
38 import org.eclipse.swt.widgets.Layout;
39 import org.eclipse.swt.widgets.Listener;
40 import org.eclipse.swt.widgets.Menu;
41 import org.eclipse.swt.widgets.Monitor;
42 import org.eclipse.swt.widgets.TypedListener;
43 import org.eclipse.swt.widgets.Widget;
44 
45 version(Tango){
46 import Unicode = tango.text.Unicode;
47 } else { // Phobos
48 }
49 
50 /**
51  * Instances of this class represent the "windows"
52  * which the desktop or "window manager" is managing.
53  * Instances that do not have a parent (that is, they
54  * are built using the constructor, which takes a
55  * <code>Display</code> as the argument) are described
56  * as <em>top level</em> shells. Instances that do have
57  * a parent are described as <em>secondary</em> or
58  * <em>dialog</em> shells.
59  * <p>
60  * Instances are always displayed in one of the maximized,
61  * minimized or normal states:
62  * <ul>
63  * <li>
64  * When an instance is marked as <em>maximized</em>, the
65  * window manager will typically resize it to fill the
66  * entire visible area of the display, and the instance
67  * is usually put in a state where it can not be resized
68  * (even if it has style <code>RESIZE</code>) until it is
69  * no longer maximized.
70  * </li><li>
71  * When an instance is in the <em>normal</em> state (neither
72  * maximized or minimized), its appearance is controlled by
73  * the style constants which were specified when it was created
74  * and the restrictions of the window manager (see below).
75  * </li><li>
76  * When an instance has been marked as <em>minimized</em>,
77  * its contents (client area) will usually not be visible,
78  * and depending on the window manager, it may be
79  * "iconified" (that is, replaced on the desktop by a small
80  * simplified representation of itself), relocated to a
81  * distinguished area of the screen, or hidden. Combinations
82  * of these changes are also possible.
83  * </li>
84  * </ul>
85  * </p><p>
86  * The <em>modality</em> of an instance may be specified using
87  * style bits. The modality style bits are used to determine
88  * whether input is blocked for other shells on the display.
89  * The <code>PRIMARY_MODAL</code> style allows an instance to block
90  * input to its parent. The <code>APPLICATION_MODAL</code> style
91  * allows an instance to block input to every other shell in the
92  * display. The <code>SYSTEM_MODAL</code> style allows an instance
93  * to block input to all shells, including shells belonging to
94  * different applications.
95  * </p><p>
96  * Note: The styles supported by this class are treated
97  * as <em>HINT</em>s, since the window manager for the
98  * desktop on which the instance is visible has ultimate
99  * control over the appearance and behavior of decorations
100  * and modality. For example, some window managers only
101  * support resizable windows and will always assume the
102  * RESIZE style, even if it is not set. In addition, if a
103  * modality style is not supported, it is "upgraded" to a
104  * more restrictive modality style that is supported. For
105  * example, if <code>PRIMARY_MODAL</code> is not supported,
106  * it would be upgraded to <code>APPLICATION_MODAL</code>.
107  * A modality style may also be "downgraded" to a less
108  * restrictive style. For example, most operating systems
109  * no longer support <code>SYSTEM_MODAL</code> because
110  * it can freeze up the desktop, so this is typically
111  * downgraded to <code>APPLICATION_MODAL</code>.
112  * <dl>
113  * <dt><b>Styles:</b></dt>
114  * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL</dd>
115  * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd>
116  * <dt><b>Events:</b></dt>
117  * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd>
118  * </dl>
119  * Class <code>SWT</code> provides two "convenience constants"
120  * for the most commonly required style combinations:
121  * <dl>
122  * <dt><code>SHELL_TRIM</code></dt>
123  * <dd>
124  * the result of combining the constants which are required
125  * to produce a typical application top level shell: (that
126  * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
127  * </dd>
128  * <dt><code>DIALOG_TRIM</code></dt>
129  * <dd>
130  * the result of combining the constants which are required
131  * to produce a typical application dialog shell: (that
132  * is, <code>TITLE | CLOSE | BORDER</code>)
133  * </dd>
134  * </dl>
135  * </p>
136  * <p>
137  * Note: Only one of the styles APPLICATION_MODAL, MODELESS,
138  * PRIMARY_MODAL and SYSTEM_MODAL may be specified.
139  * </p><p>
140  * IMPORTANT: This class is not intended to be subclassed.
141  * </p>
142  *
143  * @see Decorations
144  * @see SWT
145  * @see <a href="http://www.eclipse.org/swt/snippets/#shell">Shell snippets</a>
146  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
147  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
148  */
149 public class Shell : Decorations {
150 
151     alias Decorations.createHandle createHandle;
152     alias Decorations.fixStyle fixStyle;
153     alias Decorations.setBounds setBounds;
154     alias Decorations.setCursor setCursor;
155     alias Decorations.setToolTipText setToolTipText;
156     alias Decorations.setZOrder setZOrder;
157 
158     GtkWidget* shellHandle, tooltipsHandle, tooltipWindow, group, modalGroup;
159     bool mapped, moved, resized, opened, fullScreen, showWithParent;
160 
161     int oldX, oldY, oldWidth, oldHeight;
162     int minWidth, minHeight;
163     Control lastActive;
164     CallbackData filterProcCallbackData;
165     CallbackData sizeAllocateProcCallbackData;
166     CallbackData sizeRequestProcCallbackData;
167 
168     static const int MAXIMUM_TRIM = 128;
169 
170 /**
171  * Constructs a new instance of this class. This is equivalent
172  * to calling <code>Shell((Display) null)</code>.
173  *
174  * @exception SWTException <ul>
175  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
176  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
177  * </ul>
178  */
179 public this () {
180     this (cast(Display) null);
181 }
182 /**
183  * Constructs a new instance of this class given only the style
184  * value describing its behavior and appearance. This is equivalent
185  * to calling <code>Shell((Display) null, style)</code>.
186  * <p>
187  * The style value is either one of the style constants defined in
188  * class <code>SWT</code> which is applicable to instances of this
189  * class, or must be built by <em>bitwise OR</em>'ing together
190  * (that is, using the <code>int</code> "|" operator) two or more
191  * of those <code>SWT</code> style constants. The class description
192  * lists the style constants that are applicable to the class.
193  * Style bits are also inherited from superclasses.
194  * </p>
195  *
196  * @param style the style of control to construct
197  *
198  * @exception SWTException <ul>
199  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
200  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
201  * </ul>
202  *
203  * @see SWT#BORDER
204  * @see SWT#CLOSE
205  * @see SWT#MIN
206  * @see SWT#MAX
207  * @see SWT#RESIZE
208  * @see SWT#TITLE
209  * @see SWT#NO_TRIM
210  * @see SWT#SHELL_TRIM
211  * @see SWT#DIALOG_TRIM
212  * @see SWT#MODELESS
213  * @see SWT#PRIMARY_MODAL
214  * @see SWT#APPLICATION_MODAL
215  * @see SWT#SYSTEM_MODAL
216  */
217 public this (int style) {
218     this (cast(Display) null, style);
219 }
220 
221 /**
222  * Constructs a new instance of this class given only the display
223  * to create it on. It is created with style <code>SWT.SHELL_TRIM</code>.
224  * <p>
225  * Note: Currently, null can be passed in for the display argument.
226  * This has the effect of creating the shell on the currently active
227  * display if there is one. If there is no current display, the
228  * shell is created on a "default" display. <b>Passing in null as
229  * the display argument is not considered to be good coding style,
230  * and may not be supported in a future release of SWT.</b>
231  * </p>
232  *
233  * @param display the display to create the shell on
234  *
235  * @exception SWTException <ul>
236  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
237  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
238  * </ul>
239  */
240 public this (Display display) {
241     this (display, SWT.SHELL_TRIM);
242 }
243 /**
244  * Constructs a new instance of this class given the display
245  * to create it on and a style value describing its behavior
246  * and appearance.
247  * <p>
248  * The style value is either one of the style constants defined in
249  * class <code>SWT</code> which is applicable to instances of this
250  * class, or must be built by <em>bitwise OR</em>'ing together
251  * (that is, using the <code>int</code> "|" operator) two or more
252  * of those <code>SWT</code> style constants. The class description
253  * lists the style constants that are applicable to the class.
254  * Style bits are also inherited from superclasses.
255  * </p><p>
256  * Note: Currently, null can be passed in for the display argument.
257  * This has the effect of creating the shell on the currently active
258  * display if there is one. If there is no current display, the
259  * shell is created on a "default" display. <b>Passing in null as
260  * the display argument is not considered to be good coding style,
261  * and may not be supported in a future release of SWT.</b>
262  * </p>
263  *
264  * @param display the display to create the shell on
265  * @param style the style of control to construct
266  *
267  * @exception SWTException <ul>
268  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
269  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
270  * </ul>
271  *
272  * @see SWT#BORDER
273  * @see SWT#CLOSE
274  * @see SWT#MIN
275  * @see SWT#MAX
276  * @see SWT#RESIZE
277  * @see SWT#TITLE
278  * @see SWT#NO_TRIM
279  * @see SWT#SHELL_TRIM
280  * @see SWT#DIALOG_TRIM
281  * @see SWT#MODELESS
282  * @see SWT#PRIMARY_MODAL
283  * @see SWT#APPLICATION_MODAL
284  * @see SWT#SYSTEM_MODAL
285  */
286 public this (Display display, int style) {
287     this (display, null, style, null, false);
288 }
289 
290 this (Display display, Shell parent, int style, GtkWidget* handle, bool embedded) {
291     super ();
292     checkSubclass ();
293     if (display is null) display = Display.getCurrent ();
294     if (display is null) display = Display.getDefault ();
295     if (!display.isValidThread ()) {
296         error (SWT.ERROR_THREAD_INVALID_ACCESS);
297     }
298     if (parent !is null && parent.isDisposed ()) {
299         error (SWT.ERROR_INVALID_ARGUMENT);
300     }
301     this.style = checkStyle (style);
302     this.parent = parent;
303     this.display = display;
304     if (handle !is null) {
305         if (embedded) {
306             this.handle = handle;
307         } else {
308             shellHandle = handle;
309             state |= FOREIGN_HANDLE;
310         }
311     }
312     createWidget (0);
313 }
314 
315 /**
316  * Constructs a new instance of this class given only its
317  * parent. It is created with style <code>SWT.DIALOG_TRIM</code>.
318  * <p>
319  * Note: Currently, null can be passed in for the parent.
320  * This has the effect of creating the shell on the currently active
321  * display if there is one. If there is no current display, the
322  * shell is created on a "default" display. <b>Passing in null as
323  * the parent is not considered to be good coding style,
324  * and may not be supported in a future release of SWT.</b>
325  * </p>
326  *
327  * @param parent a shell which will be the parent of the new instance
328  *
329  * @exception IllegalArgumentException <ul>
330  *    <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
331  * </ul>
332  * @exception SWTException <ul>
333  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
334  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
335  * </ul>
336  */
337 public this (Shell parent) {
338     this (parent, SWT.DIALOG_TRIM);
339 }
340 
341 /**
342  * Constructs a new instance of this class given its parent
343  * and a style value describing its behavior and appearance.
344  * <p>
345  * The style value is either one of the style constants defined in
346  * class <code>SWT</code> which is applicable to instances of this
347  * class, or must be built by <em>bitwise OR</em>'ing together
348  * (that is, using the <code>int</code> "|" operator) two or more
349  * of those <code>SWT</code> style constants. The class description
350  * lists the style constants that are applicable to the class.
351  * Style bits are also inherited from superclasses.
352  * </p><p>
353  * Note: Currently, null can be passed in for the parent.
354  * This has the effect of creating the shell on the currently active
355  * display if there is one. If there is no current display, the
356  * shell is created on a "default" display. <b>Passing in null as
357  * the parent is not considered to be good coding style,
358  * and may not be supported in a future release of SWT.</b>
359  * </p>
360  *
361  * @param parent a shell which will be the parent of the new instance
362  * @param style the style of control to construct
363  *
364  * @exception IllegalArgumentException <ul>
365  *    <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
366  * </ul>
367  * @exception SWTException <ul>
368  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
369  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
370  * </ul>
371  *
372  * @see SWT#BORDER
373  * @see SWT#CLOSE
374  * @see SWT#MIN
375  * @see SWT#MAX
376  * @see SWT#RESIZE
377  * @see SWT#TITLE
378  * @see SWT#NO_TRIM
379  * @see SWT#SHELL_TRIM
380  * @see SWT#DIALOG_TRIM
381  * @see SWT#ON_TOP
382  * @see SWT#TOOL
383  * @see SWT#MODELESS
384  * @see SWT#PRIMARY_MODAL
385  * @see SWT#APPLICATION_MODAL
386  * @see SWT#SYSTEM_MODAL
387  */
388 public this (Shell parent, int style) {
389     this (parent !is null ? parent.display : null, parent, style, null, false);
390 }
391 
392 public static Shell gtk_new (Display display, GtkWidget* handle) {
393     return new Shell (display, null, SWT.NO_TRIM, handle, true);
394 }
395 
396 /**  
397  * Invokes platform specific functionality to allocate a new shell
398  * that is not embedded.
399  * <p>
400  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
401  * API for <code>Shell</code>. It is marked public only so that it
402  * can be shared within the packages provided by SWT. It is not
403  * available on all platforms, and should never be called from
404  * application code.
405  * </p>
406  *
407  * @param display the display for the shell
408  * @param handle the handle for the shell
409  * @return a new shell object containing the specified display and handle
410  * 
411  * @since 3.3
412  */
413 public static Shell internal_new (Display display, GtkWidget* handle) {
414     return new Shell (display, null, SWT.NO_TRIM, handle, false);
415 }
416 
417 static int checkStyle (int style) {
418     style = Decorations.checkStyle (style);
419     style &= ~SWT.TRANSPARENT;
420     if ((style & SWT.ON_TOP) !is 0) style &= ~SWT.SHELL_TRIM;
421     int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL;
422     int bits = style & ~mask;
423     if ((style & SWT.SYSTEM_MODAL) !is 0) return bits | SWT.SYSTEM_MODAL;
424     if ((style & SWT.APPLICATION_MODAL) !is 0) return bits | SWT.APPLICATION_MODAL;
425     if ((style & SWT.PRIMARY_MODAL) !is 0) return bits | SWT.PRIMARY_MODAL;
426     return bits;
427 }
428 
429 /**
430  * Adds the listener to the collection of listeners who will
431  * be notified when operations are performed on the receiver,
432  * by sending the listener one of the messages defined in the
433  * <code>ShellListener</code> interface.
434  *
435  * @param listener the listener which should be notified
436  *
437  * @exception IllegalArgumentException <ul>
438  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
439  * </ul>
440  * @exception SWTException <ul>
441  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
442  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
443  * </ul>
444  *
445  * @see ShellListener
446  * @see #removeShellListener
447  */
448 public void addShellListener (ShellListener listener) {
449     checkWidget();
450     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
451     TypedListener typedListener = new TypedListener (listener);
452     addListener (SWT.Close,typedListener);
453     addListener (SWT.Iconify,typedListener);
454     addListener (SWT.Deiconify,typedListener);
455     addListener (SWT.Activate, typedListener);
456     addListener (SWT.Deactivate, typedListener);
457 }
458 
459 void adjustTrim () {
460     if (display.ignoreTrim) return;
461     int width = OS.GTK_WIDGET_WIDTH (shellHandle);
462     int height = OS.GTK_WIDGET_HEIGHT (shellHandle);
463     auto window = OS.GTK_WIDGET_WINDOW (shellHandle);
464     GdkRectangle* rect = new GdkRectangle ();
465     OS.gdk_window_get_frame_extents (window, rect);
466     int trimWidth = Math.max (0, rect.width - width);
467     int trimHeight = Math.max (0, rect.height - height);
468     /*
469     * Bug in GTK.  gdk_window_get_frame_extents() fails for various window
470     * managers, causing a large incorrect value to be returned as the trim.
471     * The fix is to ignore the returned trim values if they are too large.
472     */
473     if (trimWidth > MAXIMUM_TRIM || trimHeight > MAXIMUM_TRIM) {
474         display.ignoreTrim = true;
475         return;
476     }
477     bool hasTitle = false, hasResize = false, hasBorder = false;
478     if ((style & SWT.NO_TRIM) is 0) {
479         hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) !is 0;
480         hasResize = (style & SWT.RESIZE) !is 0;
481         hasBorder = (style & SWT.BORDER) !is 0;
482     }
483     if (hasTitle) {
484         if (hasResize)  {
485             display.titleResizeTrimWidth = trimWidth;
486             display.titleResizeTrimHeight = trimHeight;
487             return;
488         }
489         if (hasBorder) {
490             display.titleBorderTrimWidth = trimWidth;
491             display.titleBorderTrimHeight = trimHeight;
492             return;
493         }
494         display.titleTrimWidth = trimWidth;
495         display.titleTrimHeight = trimHeight;
496         return;
497     }
498     if (hasResize) {
499         display.resizeTrimWidth = trimWidth;
500         display.resizeTrimHeight = trimHeight;
501         return;
502     }
503     if (hasBorder) {
504         display.borderTrimWidth = trimWidth;
505         display.borderTrimHeight = trimHeight;
506         return;
507     }
508 }
509 
510 void bringToTop (bool force) {
511     if (!OS.GTK_WIDGET_VISIBLE (shellHandle)) return;
512     Display display = this.display;
513     Shell activeShell = display.activeShell;
514     if (activeShell is this) return;
515     if (!force) {
516         if (activeShell is null) return;
517         if (!display.activePending) {
518             auto focusHandle = OS.gtk_window_get_focus (cast(GtkWindow*)activeShell.shellHandle);
519             if (focusHandle !is null && !OS.GTK_WIDGET_HAS_FOCUS (focusHandle)) return;
520         }
521     }
522     /*
523     * Bug in GTK.  When a shell that is not managed by the window
524     * manage is given focus, GTK gets stuck in "focus follows pointer"
525     * mode when the pointer is within the shell and its parent when
526     * the shell is hidden or disposed. The fix is to use XSetInputFocus()
527     * to assign focus when ever the active shell has not managed by
528     * the window manager.
529     *
530     * NOTE: This bug is fixed in GTK+ 2.6.8 and above.
531     */
532     bool xFocus = false;
533     if (activeShell !is null) {
534         if (OS.GTK_VERSION < OS.buildVERSION (2, 6, 8)) {
535             xFocus = activeShell.isUndecorated ();
536         }
537         display.activeShell = null;
538         display.activePending = true;
539     }
540     /*
541     * Feature in GTK.  When the shell is an override redirect
542     * window, gdk_window_focus() does not give focus to the
543     * window.  The fix is to use XSetInputFocus() to force
544     * the focus.
545     */
546     auto window = OS.GTK_WIDGET_WINDOW (shellHandle);
547     if ((xFocus || (style & SWT.ON_TOP) !is 0) && OS.GDK_WINDOWING_X11 ()) {
548         auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (window);
549         auto xWindow = OS.gdk_x11_drawable_get_xid (window);
550         OS.gdk_error_trap_push ();
551         /* Use CurrentTime instead of the last event time to ensure that the shell becomes active */
552         OS.XSetInputFocus (xDisplay, xWindow, OS.RevertToParent, OS.CurrentTime);
553         OS.gdk_error_trap_pop ();
554     } else {
555         /*
556         * Bug in metacity.  Calling gdk_window_focus() with a timestamp more
557         * recent than the last user interaction time can cause windows not
558         * to come forward in versions > 2.10.0.  The fix is to use the last
559         * user event time.
560         */
561         if ( display.windowManager.toLowerCase() ==/*eq*/ "metacity") {
562             OS.gdk_window_focus (window, display.lastUserEventTime);
563         } else {
564             OS.gdk_window_focus (window, OS.GDK_CURRENT_TIME);
565         }
566     }
567     display.activeShell = this;
568     display.activePending = true;
569 }
570 
571 override void checkBorder () {
572     /* Do nothing */
573 }
574 
575 override void checkOpen () {
576     if (!opened) resized = false;
577 }
578 
579 override GtkStyle* childStyle () {
580     return null;
581 }
582 
583 /**
584  * Requests that the window manager close the receiver in
585  * the same way it would be closed when the user clicks on
586  * the "close box" or performs some other platform specific
587  * key or mouse combination that indicates the window
588  * should be removed.
589  *
590  * @exception SWTException <ul>
591  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
592  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
593  * </ul>
594  *
595  * @see SWT#Close
596  * @see #dispose
597  */
598 public void close () {
599     checkWidget ();
600     closeWidget ();
601 }
602 
603 void closeWidget () {
604     Event event = new Event ();
605     sendEvent (SWT.Close, event);
606     if (event.doit && !isDisposed ()) dispose ();
607 }
608 
609 override public Rectangle computeTrim (int x, int y, int width, int height) {
610     checkWidget();
611     Rectangle trim = super.computeTrim (x, y, width, height);
612     int border = 0;
613     if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) {
614         border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle);
615     }
616     int trimWidth = trimWidth (), trimHeight = trimHeight ();
617     trim.x -= (trimWidth / 2) + border;
618     trim.y -= trimHeight - (trimWidth / 2) + border;
619     trim.width += trimWidth + border * 2;
620     trim.height += trimHeight + border * 2;
621     if (menuBar !is null) {
622         forceResize ();
623         int menuBarHeight = OS.GTK_WIDGET_HEIGHT (menuBar.handle);
624         trim.y -= menuBarHeight;
625         trim.height += menuBarHeight;
626     }
627     return trim;
628 }
629 
630 override void createHandle (int index) {
631     state |= HANDLE | CANVAS;
632     if (shellHandle is null) {
633         if (handle is null) {
634             int type = OS.GTK_WINDOW_TOPLEVEL;
635             if ((style & SWT.ON_TOP) !is 0) type = OS.GTK_WINDOW_POPUP;
636             shellHandle = cast(GtkWidget*)OS.gtk_window_new (type);
637         } else {
638             shellHandle = cast(GtkWidget*) OS.gtk_plug_new (handle);
639         }
640         if (shellHandle is null) error (SWT.ERROR_NO_HANDLES);
641         if (parent !is null) {
642             OS.gtk_window_set_transient_for (cast(GtkWindow*)shellHandle, cast(GtkWindow*)parent.topHandle ());
643             OS.gtk_window_set_destroy_with_parent (cast(GtkWindow*)shellHandle, true);
644             if (!isUndecorated ()) {
645                 OS.gtk_window_set_type_hint (cast(GtkWindow*)shellHandle, OS.GDK_WINDOW_TYPE_HINT_DIALOG);
646             } else {
647                 if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 0)) {
648                     OS.gtk_window_set_skip_taskbar_hint (cast(GtkWindow*)shellHandle, true);
649                 }
650             }
651         }
652         /*
653         * Feature in GTK.  The window size must be set when the window
654         * is created or it will not be allowed to be resized smaller that the
655         * initial size by the user.  The fix is to set the size to zero.
656         */
657         if ((style & SWT.RESIZE) !is 0) {
658             OS.gtk_widget_set_size_request (shellHandle, 0, 0);
659             OS.gtk_window_set_resizable (cast(GtkWindow*)shellHandle, true);
660         } else {
661             OS.gtk_window_set_resizable (cast(GtkWindow*)shellHandle, false);
662         }
663         vboxHandle = OS.gtk_vbox_new (false, 0);
664         if (vboxHandle is null) error (SWT.ERROR_NO_HANDLES);
665         createHandle (index, false, true);
666         OS.gtk_container_add (cast(GtkContainer*)vboxHandle, scrolledHandle);
667         OS.gtk_box_set_child_packing (cast(GtkBox*)vboxHandle, scrolledHandle, true, true, 0, OS.GTK_PACK_END);
668         String dummy = "a";
669         OS.gtk_window_set_title (cast(GtkWindow*)shellHandle, dummy.ptr );
670         if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) {
671             OS.gtk_container_set_border_width (cast(GtkContainer*)shellHandle, 1);
672             GdkColor* color = new GdkColor ();
673             OS.gtk_style_get_black (OS.gtk_widget_get_style (shellHandle), color);
674             OS.gtk_widget_modify_bg (shellHandle,  OS.GTK_STATE_NORMAL, color);
675         }
676     } else {
677         vboxHandle = OS.gtk_bin_get_child (cast(GtkBin*)shellHandle);
678         if (vboxHandle is null) error (SWT.ERROR_NO_HANDLES);
679         auto children = OS.gtk_container_get_children (cast(GtkContainer*)vboxHandle);
680         if (OS.g_list_length (children) > 0) {
681             scrolledHandle = cast(GtkWidget*)OS.g_list_data (children);
682         }
683         OS.g_list_free (children);
684         if (scrolledHandle is null) error (SWT.ERROR_NO_HANDLES);
685         handle = OS.gtk_bin_get_child (cast(GtkBin*)scrolledHandle);
686         if (handle is null) error (SWT.ERROR_NO_HANDLES);
687     }
688     group = cast(GtkWidget*) OS.gtk_window_group_new ();
689     if (group is null) error (SWT.ERROR_NO_HANDLES);
690     /*
691     * Feature in GTK.  Realizing the shell triggers a size allocate event,
692     * which may be confused for a resize event from the window manager if
693     * received too late.  The fix is to realize the window during creation
694     * to avoid confusion.
695     */
696     OS.gtk_widget_realize (shellHandle);
697 }
698 
699 override int filterProc ( XEvent* xEvent, GdkEvent* gdkEvent, void* data2) {
700     int eventType = OS.X_EVENT_TYPE (xEvent);
701     if (eventType !is OS.FocusOut && eventType !is OS.FocusIn) return 0;
702     XFocusChangeEvent* xFocusEvent = cast(XFocusChangeEvent*)xEvent;
703     switch (eventType) {
704         case OS.FocusIn:
705             if (xFocusEvent.mode is OS.NotifyNormal || xFocusEvent.mode is OS.NotifyWhileGrabbed) {
706                 switch (xFocusEvent.detail) {
707                     case OS.NotifyNonlinear:
708                     case OS.NotifyNonlinearVirtual:
709                     case OS.NotifyAncestor:
710                         if (tooltipsHandle !is null) OS.gtk_tooltips_enable (cast(GtkTooltips*)tooltipsHandle);
711                         display.activeShell = this;
712                         display.activePending = false;
713                         sendEvent (SWT.Activate);
714                         break;
715                     default:
716                 }
717             }
718             break;
719         case OS.FocusOut:
720             if (xFocusEvent.mode is OS.NotifyNormal || xFocusEvent.mode is OS.NotifyWhileGrabbed) {
721                 switch (xFocusEvent.detail) {
722                     case OS.NotifyNonlinear:
723                     case OS.NotifyNonlinearVirtual:
724                     case OS.NotifyVirtual:
725                         if (tooltipsHandle !is null) OS.gtk_tooltips_disable (cast(GtkTooltips*)tooltipsHandle);
726                         Display display = this.display;
727                         sendEvent (SWT.Deactivate);
728                         setActiveControl (null);
729                         if (display.activeShell is this) {
730                             display.activeShell = null;
731                             display.activePending = false;
732                         }
733                         break;
734                     default:
735                 }
736             }
737             break;
738         default:
739     }
740     return 0;
741 }
742 
743 override Control findBackgroundControl () {
744     return (state & BACKGROUND) !is 0 || backgroundImage !is null ? this : null;
745 }
746 
747 override Composite findDeferredControl () {
748     return layoutCount > 0 ? this : null;
749 }
750 
751 override bool hasBorder () {
752     return false;
753 }
754 
755 override void hookEvents () {
756     super.hookEvents ();
757     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [KEY_PRESS_EVENT], 0, display.closures [KEY_PRESS_EVENT], false);
758     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [WINDOW_STATE_EVENT], 0, display.closures [WINDOW_STATE_EVENT], false);
759     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [SIZE_ALLOCATE], 0, display.closures [SIZE_ALLOCATE], false);
760     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [CONFIGURE_EVENT], 0, display.closures [CONFIGURE_EVENT], false);
761     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [DELETE_EVENT], 0, display.closures [DELETE_EVENT], false);
762     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [MAP_EVENT], 0, display.shellMapProcClosure, false);
763     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [ENTER_NOTIFY_EVENT], 0, display.closures [ENTER_NOTIFY_EVENT], false);
764     OS.g_signal_connect_closure (shellHandle, OS.move_focus.ptr, display.closures [MOVE_FOCUS], false);
765     auto window = OS.GTK_WIDGET_WINDOW (shellHandle);
766     display.doWindowAddFilter( &filterProcCallbackData, window, shellHandle );
767     //OS.gdk_window_add_filter  (window, display.filterProc, shellHandle);
768 }
769 
770 override public bool isEnabled () {
771     checkWidget ();
772     return getEnabled ();
773 }
774 
775 bool isUndecorated () {
776     return
777         (style & (SWT.SHELL_TRIM | SWT.BORDER)) is SWT.NONE ||
778         (style & (SWT.NO_TRIM | SWT.ON_TOP)) !is 0;
779 }
780 
781 override public bool isVisible () {
782     checkWidget();
783     return getVisible ();
784 }
785 
786 override void register () {
787     super.register ();
788     display.addWidget (shellHandle, this);
789 }
790 
791 override void releaseParent () {
792     /* Do nothing */
793 }
794 
795 override GtkWidget* topHandle () {
796     return shellHandle;
797 }
798 
799 void fixActiveShell () {
800     if (display.activeShell is this) {
801         Shell shell = null;
802         if (parent !is null && parent.isVisible ()) shell = parent.getShell ();
803         if (shell is null && isUndecorated ()) {
804             Shell [] shells = display.getShells ();
805             for (int i = 0; i < shells.length; i++) {
806                 if (shells [i] !is null && shells [i].isVisible ()) {
807                     shell = shells [i];
808                     break;
809                 }
810             }
811         }
812         if (shell !is null) shell.bringToTop (false);
813     }
814 }
815 
816 void fixShell (Shell newShell, Control control) {
817     if (this is newShell) return;
818     if (control is lastActive) setActiveControl (null);
819     String toolTipText = control.toolTipText;
820     if (toolTipText !is null) {
821         control.setToolTipText (this, null);
822         control.setToolTipText (newShell, toolTipText);
823     }
824 }
825 
826 override void fixedSizeAllocateProc(GtkWidget* widget, GtkAllocation* allocationPtr) {
827     int clientWidth = 0;
828     if ((style & SWT.MIRRORED) !is 0) clientWidth = getClientWidth ();
829     super.fixedSizeAllocateProc (widget, allocationPtr);
830     if ((style & SWT.MIRRORED) !is 0) moveChildren (clientWidth);
831 }
832 
833 override void fixStyle (GtkWidget* handle) {
834 }
835 
836 override void forceResize () {
837     forceResize (OS.GTK_WIDGET_WIDTH (vboxHandle), OS.GTK_WIDGET_HEIGHT (vboxHandle));
838 }
839 
840 void forceResize (int width, int height) {
841     GtkRequisition requisition;
842     OS.gtk_widget_size_request (vboxHandle, &requisition);
843     GtkAllocation allocation;
844     int border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle);
845     allocation.x = border;
846     allocation.y = border;
847     allocation.width = width;
848     allocation.height = height;
849     OS.gtk_widget_size_allocate (cast(GtkWidget*)vboxHandle, &allocation);
850 }
851 
852 /**
853  * Returns the receiver's alpha value. The alpha value
854  * is between 0 (transparent) and 255 (opaque).
855  *
856  * @return the alpha value
857  *
858  * @exception SWTException <ul>
859  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
860  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
861  * </ul>
862  * 
863  * @since 3.4
864  */
865 public int getAlpha () {
866     checkWidget ();
867     if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
868         if (OS.gtk_widget_is_composited (shellHandle)) {
869             return cast(int) (OS.gtk_window_get_opacity (shellHandle) * 255);
870         }
871     }
872     return 255;
873 }
874 
875 /**
876  * Returns <code>true</code> if the receiver is currently
877  * in fullscreen state, and false otherwise. 
878  * <p>
879  *
880  * @return the fullscreen state
881  *
882  * @exception SWTException <ul>
883  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
884  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
885  * </ul>
886  *
887  * @since 3.4
888  */
889 public bool getFullScreen () {
890     checkWidget();
891     return fullScreen;
892 }
893 
894 override public Point getLocation () {
895     checkWidget ();
896     int x, y;
897     OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x,&y);
898     return new Point (x, y);
899 }
900 
901 override
902 public bool getMaximized () {
903     checkWidget();
904     return !fullScreen && super.getMaximized ();
905 }
906 
907 /**
908  * Returns a point describing the minimum receiver's size. The
909  * x coordinate of the result is the minimum width of the receiver.
910  * The y coordinate of the result is the minimum height of the
911  * receiver.
912  *
913  * @return the receiver's size
914  *
915  * @exception SWTException <ul>
916  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
917  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
918  * </ul>
919  *
920  * @since 3.1
921  */
922 public Point getMinimumSize () {
923     checkWidget ();
924     int width = Math.max (1, minWidth + trimWidth ());
925     int height = Math.max (1, minHeight + trimHeight ());
926     return new Point (width, height);
927 }
928 
929 Shell getModalShell () {
930     Shell shell = null;
931     Shell [] modalShells = display.modalShells;
932     if (modalShells !is null) {
933         int bits = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
934         ptrdiff_t index = modalShells.length;
935         while (--index >= 0) {
936             Shell modal = modalShells [index];
937             if (modal !is null) {
938                 if ((modal.style & bits) !is 0) {
939                     Control control = this;
940                     while (control !is null) {
941                         if (control is modal) break;
942                         control = control.parent;
943                     }
944                     if (control !is modal) return modal;
945                     break;
946                 }
947                 if ((modal.style & SWT.PRIMARY_MODAL) !is 0) {
948                     if (shell is null) shell = getShell ();
949                     if (modal.parent is shell) return modal;
950                 }
951             }
952         }
953     }
954     return null;
955 }
956 
957 override public Point getSize () {
958     checkWidget ();
959     int width = OS.GTK_WIDGET_WIDTH (vboxHandle);
960     int height = OS.GTK_WIDGET_HEIGHT (vboxHandle);
961     int border = 0;
962     if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) {
963         border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle);
964     }
965     return new Point (width + trimWidth () + 2*border, height + trimHeight () + 2*border);
966 }
967 
968 override public bool getVisible () {
969     checkWidget();
970     return OS.GTK_WIDGET_VISIBLE (shellHandle);
971 }
972 
973 /**
974  * Returns the region that defines the shape of the shell,
975  * or null if the shell has the default shape.
976  *
977  * @return the region that defines the shape of the shell (or null)
978  *
979  * @exception SWTException <ul>
980  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
981  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
982  * </ul>
983  *
984  * @since 3.0
985  *
986  */
987 override
988 public Region getRegion () {
989     /* This method is needed for @since 3.0 Javadoc */
990     checkWidget ();
991     return region;
992 }
993 
994 /**
995  * Returns the receiver's input method editor mode. This
996  * will be the result of bitwise OR'ing together one or
997  * more of the following constants defined in class
998  * <code>SWT</code>:
999  * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>,
1000  * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
1001  *
1002  * @return the IME mode
1003  *
1004  * @exception SWTException <ul>
1005  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1006  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1007  * </ul>
1008  *
1009  * @see SWT
1010  */
1011 public int getImeInputMode () {
1012     checkWidget();
1013     return SWT.NONE;
1014 }
1015 
1016 override Shell _getShell () {
1017     return this;
1018 }
1019 /**
1020  * Returns an array containing all shells which are
1021  * descendants of the receiver.
1022  * <p>
1023  * @return the dialog shells
1024  *
1025  * @exception SWTException <ul>
1026  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1027  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1028  * </ul>
1029  */
1030 public Shell [] getShells () {
1031     checkWidget();
1032     int count = 0;
1033     Shell [] shells = display.getShells ();
1034     for (int i=0; i<shells.length; i++) {
1035         Control shell = shells [i];
1036         do {
1037             shell = shell.getParent ();
1038         } while (shell !is null && shell !is this);
1039         if (shell is this) count++;
1040     }
1041     int index = 0;
1042     Shell [] result = new Shell [count];
1043     for (int i=0; i<shells.length; i++) {
1044         Control shell = shells [i];
1045         do {
1046             shell = shell.getParent ();
1047         } while (shell !is null && shell !is this);
1048         if (shell is this) {
1049             result [index++] = shells [i];
1050         }
1051     }
1052     return result;
1053 }
1054 
1055 override int gtk_configure_event (GtkWidget* widget, ptrdiff_t event) {
1056     int x, y;
1057     OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x, &y);
1058     if (!moved || oldX !is x || oldY !is y) {
1059         moved = true;
1060         oldX = x;
1061         oldY = y;
1062         sendEvent (SWT.Move);
1063         // widget could be disposed at this point
1064     }
1065     return 0;
1066 }
1067 
1068 override int gtk_delete_event (GtkWidget* widget, ptrdiff_t event) {
1069     if (isEnabled()) closeWidget ();
1070     return 1;
1071 }
1072 
1073 override int gtk_enter_notify_event (GtkWidget* widget, GdkEventCrossing* event) {
1074     if (widget !is shellHandle) {
1075         return super.gtk_enter_notify_event (widget, event);
1076     }
1077     return 0;
1078 }
1079 
1080 override int gtk_focus (GtkWidget* widget, ptrdiff_t directionType) {
1081     switch (directionType) {
1082         case OS.GTK_DIR_TAB_FORWARD:
1083         case OS.GTK_DIR_TAB_BACKWARD:
1084             Control control = display.getFocusControl ();
1085             if (control !is null) {
1086                 if ((control.state & CANVAS) !is 0 && (control.style & SWT.EMBEDDED) !is 0) {
1087                     int traversal = directionType is OS.GTK_DIR_TAB_FORWARD ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS;
1088                     control.traverse (traversal);
1089                     return 1;
1090                 }
1091             }
1092             break;
1093         default:
1094     }
1095     return super.gtk_focus (widget, directionType);
1096 }
1097 
1098 override int gtk_move_focus (GtkWidget* widget, ptrdiff_t directionType) {
1099     Control control = display.getFocusControl ();
1100     if (control !is null) {
1101         auto focusHandle = control.focusHandle ();
1102         OS.gtk_widget_child_focus (focusHandle, cast(int)/*64bit*/directionType);
1103     }
1104     OS.g_signal_stop_emission_by_name (shellHandle, OS.move_focus.ptr );
1105     return 1;
1106 }
1107 
1108 override int gtk_key_press_event (GtkWidget* widget, GdkEventKey* event) {
1109     /* Stop menu mnemonics when the shell is disabled */
1110     if (widget is shellHandle) {
1111         return (state & DISABLED) !is 0 ? 1 : 0;
1112     }
1113     return super.gtk_key_press_event (widget, event);
1114 }
1115 
1116 override int gtk_size_allocate (GtkWidget* widget, ptrdiff_t allocation) {
1117     int width = OS.GTK_WIDGET_WIDTH (shellHandle);
1118     int height = OS.GTK_WIDGET_HEIGHT (shellHandle);
1119     if (!resized || oldWidth !is width || oldHeight !is height) {
1120         oldWidth = width;
1121         oldHeight = height;
1122         resizeBounds (width, height, true);
1123     }
1124     return 0;
1125 }
1126 
1127 override int gtk_realize (GtkWidget* widget) {
1128     auto result = super.gtk_realize (widget);
1129     auto window = OS.GTK_WIDGET_WINDOW (shellHandle);
1130     if ((style & SWT.SHELL_TRIM) !is SWT.SHELL_TRIM) {
1131         int decorations = 0;
1132         if ((style & SWT.NO_TRIM) is 0) {
1133             if ((style & SWT.MIN) !is 0) decorations |= OS.GDK_DECOR_MINIMIZE;
1134             if ((style & SWT.MAX) !is 0) decorations |= OS.GDK_DECOR_MAXIMIZE;
1135             if ((style & SWT.RESIZE) !is 0) decorations |= OS.GDK_DECOR_RESIZEH;
1136             if ((style & SWT.BORDER) !is 0) decorations |= OS.GDK_DECOR_BORDER;
1137             if ((style & SWT.MENU) !is 0) decorations |= OS.GDK_DECOR_MENU;
1138             if ((style & SWT.TITLE) !is 0) decorations |= OS.GDK_DECOR_TITLE;
1139             /*
1140             * Feature in GTK.  Under some Window Managers (Sawmill), in order
1141             * to get any border at all from the window manager it is necessary to
1142             * set GDK_DECOR_BORDER.  The fix is to force these bits when any
1143             * kind of border is requested.
1144             */
1145             if ((style & SWT.RESIZE) !is 0) decorations |= OS.GDK_DECOR_BORDER;
1146         }
1147         OS.gdk_window_set_decorations (window, decorations);
1148     }
1149     if ((style & SWT.ON_TOP) !is 0) {
1150         OS.gdk_window_set_override_redirect (window, true);
1151     }
1152     return result;
1153 }
1154 
1155 override int gtk_window_state_event (GtkWidget* widget, GdkEventWindowState* event) {
1156     minimized = (event.new_window_state & OS.GDK_WINDOW_STATE_ICONIFIED) !is 0;
1157     maximized = (event.new_window_state & OS.GDK_WINDOW_STATE_MAXIMIZED) !is 0;
1158     fullScreen = (event.new_window_state & OS.GDK_WINDOW_STATE_FULLSCREEN) !is 0;
1159     if ((event.changed_mask & OS.GDK_WINDOW_STATE_ICONIFIED) !is 0) {
1160         if (minimized) {
1161             sendEvent (SWT.Iconify);
1162         } else {
1163             sendEvent (SWT.Deiconify);
1164         }
1165         updateMinimized (minimized);
1166     }
1167     return 0;
1168 }
1169 
1170 /**
1171  * Moves the receiver to the top of the drawing order for
1172  * the display on which it was created (so that all other
1173  * shells on that display, which are not the receiver's
1174  * children will be drawn behind it), marks it visible,
1175  * sets the focus and asks the window manager to make the
1176  * shell active.
1177  *
1178  * @exception SWTException <ul>
1179  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1180  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1181  * </ul>
1182  *
1183  * @see Control#moveAbove
1184  * @see Control#setFocus
1185  * @see Control#setVisible
1186  * @see Display#getActiveShell
1187  * @see Decorations#setDefaultButton(Button)
1188  * @see Shell#setActive
1189  * @see Shell#forceActive
1190  */
1191 public void open () {
1192     checkWidget ();
1193     bringToTop (false);
1194     setVisible (true);
1195     if (isDisposed ()) return;
1196     if (!restoreFocus () && !traverseGroup (true)) setFocus ();
1197 }
1198 
1199 override
1200 public bool print (GC gc) {
1201     checkWidget ();
1202     if (gc is null) error (SWT.ERROR_NULL_ARGUMENT);
1203     if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
1204     return false;
1205 }
1206 
1207 /**
1208  * Removes the listener from the collection of listeners who will
1209  * be notified when operations are performed on the receiver.
1210  *
1211  * @param listener the listener which should no longer be notified
1212  *
1213  * @exception IllegalArgumentException <ul>
1214  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1215  * </ul>
1216  * @exception SWTException <ul>
1217  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1218  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1219  * </ul>
1220  *
1221  * @see ShellListener
1222  * @see #addShellListener
1223  */
1224 public void removeShellListener (ShellListener listener) {
1225     checkWidget();
1226     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
1227     if (eventTable is null) return;
1228     eventTable.unhook (SWT.Close, listener);
1229     eventTable.unhook (SWT.Iconify,listener);
1230     eventTable.unhook (SWT.Deiconify,listener);
1231     eventTable.unhook (SWT.Activate, listener);
1232     eventTable.unhook (SWT.Deactivate, listener);
1233 }
1234 
1235 /**
1236  * If the receiver is visible, moves it to the top of the
1237  * drawing order for the display on which it was created
1238  * (so that all other shells on that display, which are not
1239  * the receiver's children will be drawn behind it) and asks
1240  * the window manager to make the shell active
1241  *
1242  * @exception SWTException <ul>
1243  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1244  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1245  * </ul>
1246  *
1247  * @since 2.0
1248  * @see Control#moveAbove
1249  * @see Control#setFocus
1250  * @see Control#setVisible
1251  * @see Display#getActiveShell
1252  * @see Decorations#setDefaultButton(Button)
1253  * @see Shell#open
1254  * @see Shell#setActive
1255  */
1256 public void setActive () {
1257     checkWidget ();
1258     bringToTop (false);
1259 }
1260 
1261 void setActiveControl (Control control) {
1262     if (control !is null && control.isDisposed ()) control = null;
1263     if (lastActive !is null && lastActive.isDisposed ()) lastActive = null;
1264     if (lastActive is control) return;
1265 
1266     /*
1267     * Compute the list of controls to be activated and
1268     * deactivated by finding the first common parent
1269     * control.
1270     */
1271     Control [] activate = (control is null) ? new Control[0] : control.getPath ();
1272     Control [] deactivate = (lastActive is null) ? new Control[0] : lastActive.getPath ();
1273     lastActive = control;
1274     ptrdiff_t index = 0, length = Math.min (activate.length, deactivate.length);
1275     while (index < length) {
1276         if (activate [index] !is deactivate [index]) break;
1277         index++;
1278     }
1279 
1280     /*
1281     * It is possible (but unlikely), that application
1282     * code could have destroyed some of the widgets. If
1283     * this happens, keep processing those widgets that
1284     * are not disposed.
1285     */
1286     for (ptrdiff_t i=deactivate.length-1; i>=index; --i) {
1287         if (!deactivate [i].isDisposed ()) {
1288             deactivate [i].sendEvent (SWT.Deactivate);
1289         }
1290     }
1291     for (ptrdiff_t i=activate.length-1; i>=index; --i) {
1292         if (!activate [i].isDisposed ()) {
1293             activate [i].sendEvent (SWT.Activate);
1294         }
1295     }
1296 }
1297 
1298 /**
1299  * Sets the receiver's alpha value which must be
1300  * between 0 (transparent) and 255 (opaque).
1301  * <p>
1302  * This operation requires the operating system's advanced
1303  * widgets subsystem which may not be available on some
1304  * platforms.
1305  * </p>
1306  * @param alpha the alpha value
1307  *
1308  * @exception SWTException <ul>
1309  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1310  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1311  * </ul>
1312  * 
1313  * @since 3.4
1314  */
1315 public void setAlpha (int alpha) {
1316     checkWidget ();
1317     if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
1318         if (OS.gtk_widget_is_composited (shellHandle)) {
1319             alpha &= 0xFF;
1320             OS.gtk_window_set_opacity (shellHandle, alpha / 255f);
1321         }
1322     }
1323 }
1324 
1325 void resizeBounds (int width, int height, bool notify) {
1326     if (redrawWindow !is null) {
1327         OS.gdk_window_resize (redrawWindow, width, height);
1328     }
1329     if (enableWindow !is null) {
1330         OS.gdk_window_resize (enableWindow, width, height);
1331     }
1332     int border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle);
1333     int boxWidth = width - 2*border;
1334     int boxHeight = height - 2*border;
1335     OS.gtk_widget_set_size_request (vboxHandle, boxWidth, boxHeight);
1336     forceResize (boxWidth, boxHeight);
1337     if (notify) {
1338         resized = true;
1339         sendEvent (SWT.Resize);
1340         if (isDisposed ()) return;
1341         if (layout_ !is null) {
1342             markLayout (false, false);
1343             updateLayout (false);
1344         }
1345     }
1346 }
1347 
1348 override int setBounds (int x, int y, int width, int height, bool move, bool resize) {
1349     if (fullScreen) setFullScreen (false);
1350     /*
1351     * Bug in GTK.  When either of the location or size of
1352     * a shell is changed while the shell is maximized, the
1353     * shell is moved to (0, 0).  The fix is to explicitly
1354     * unmaximize the shell before setting the bounds to
1355     * anything different from the current bounds.
1356     */
1357     if (getMaximized ()) {
1358         Rectangle rect = getBounds ();
1359         bool sameOrigin = !move || (rect.x is x && rect.y is y);
1360         bool sameExtent = !resize || (rect.width is width && rect.height is height);
1361         if (sameOrigin && sameExtent) return 0;
1362         setMaximized (false);
1363     }
1364     int result = 0;
1365     if (move) {
1366         int x_pos, y_pos;
1367         OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x_pos, &y_pos);
1368         OS.gtk_window_move (cast(GtkWindow*)shellHandle, x, y);
1369         if (x_pos !is x || y_pos !is y) {
1370             moved = true;
1371             oldX = x;
1372             oldY = y;
1373             sendEvent (SWT.Move);
1374             if (isDisposed ()) return 0;
1375             result |= MOVED;
1376         }
1377     }
1378     if (resize) {
1379         width = Math.max (1, Math.max (minWidth, width - trimWidth ()));
1380         height = Math.max (1, Math.max (minHeight, height - trimHeight ()));
1381         if ((style & SWT.RESIZE) !is 0) OS.gtk_window_resize (cast(GtkWindow*)shellHandle, width, height);
1382         bool changed = width !is oldWidth || height !is oldHeight;
1383         if (changed) {
1384             oldWidth = width;
1385             oldHeight = height;
1386             result |= RESIZED;
1387         }
1388         resizeBounds (width, height, changed);
1389     }
1390     return result;
1391 }
1392 
1393 override void gtk_setCursor (GdkCursor* cursor) {
1394     if (enableWindow !is null) {
1395         OS.gdk_window_set_cursor (cast(GdkDrawable*)enableWindow, cursor);
1396         if (!OS.GDK_WINDOWING_X11 ()) {
1397             OS.gdk_flush ();
1398         } else {
1399             auto xDisplay = OS.GDK_DISPLAY ();
1400             OS.XFlush (xDisplay);
1401         }
1402     }
1403     super.gtk_setCursor (cursor);
1404 }
1405 
1406 public override void setEnabled (bool enabled) {
1407     checkWidget();
1408     if (((state & DISABLED) is 0) is enabled) return;
1409     Display display = this.display;
1410     Control control = null;
1411     bool fixFocus_ = false;
1412     if (!enabled) {
1413         if (display.focusEvent !is SWT.FocusOut) {
1414             control = display.getFocusControl ();
1415             fixFocus_ = isFocusAncestor (control);
1416         }
1417     }
1418     if (enabled) {
1419         state &= ~DISABLED;
1420     } else {
1421         state |= DISABLED;
1422     }
1423     enableWidget (enabled);
1424     if (isDisposed ()) return;
1425     if (enabled) {
1426         if (enableWindow !is null) {
1427             OS.gdk_window_set_user_data (enableWindow, null);
1428             OS.gdk_window_destroy (enableWindow);
1429             enableWindow = null;
1430         }
1431     } else {
1432         auto parentHandle = shellHandle;
1433         OS.gtk_widget_realize (parentHandle);
1434         auto window = OS.GTK_WIDGET_WINDOW (parentHandle);
1435         Rectangle rect = getBounds ();
1436         GdkWindowAttr* attributes = new GdkWindowAttr ();
1437         attributes.width = rect.width;
1438         attributes.height = rect.height;
1439         attributes.event_mask = (0xFFFFFFFF & ~OS.ExposureMask);
1440         attributes.wclass = OS.GDK_INPUT_ONLY;
1441         attributes.window_type = OS.GDK_WINDOW_CHILD;
1442         enableWindow = OS.gdk_window_new (window, attributes, 0);
1443         if (enableWindow !is null) {
1444             if (cursor !is null) {
1445                 OS.gdk_window_set_cursor (enableWindow, cursor.handle);
1446                 if (!OS.GDK_WINDOWING_X11 ()) {
1447                     OS.gdk_flush ();
1448                 } else {
1449                     auto xDisplay = OS.GDK_DISPLAY ();
1450                     OS.XFlush (xDisplay);
1451                 }
1452             }
1453             OS.gdk_window_set_user_data (enableWindow, parentHandle);
1454             OS.gdk_window_show (enableWindow);
1455         }
1456     }
1457     if (fixFocus_) fixFocus (control);
1458     if (enabled && display.activeShell is this) {
1459         if (!restoreFocus ()) traverseGroup (false);
1460     }
1461 }
1462 
1463 /**
1464  * Sets the full screen state of the receiver.
1465  * If the argument is <code>true</code> causes the receiver
1466  * to switch to the full screen state, and if the argument is
1467  * <code>false</code> and the receiver was previously switched
1468  * into full screen state, causes the receiver to switch back
1469  * to either the maximmized or normal states.
1470  * <p>
1471  * Note: The result of intermixing calls to <code>setFullScreen(true)</code>, 
1472  * <code>setMaximized(true)</code> and <code>setMinimized(true)</code> will 
1473  * vary by platform. Typically, the behavior will match the platform user's 
1474  * expectations, but not always. This should be avoided if possible.
1475  * </p>
1476  * 
1477  * @param fullScreen the new fullscreen state
1478  *
1479  * @exception SWTException <ul>
1480  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1481  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1482  * </ul>
1483  *
1484  * @since 3.4
1485  */
1486 public void setFullScreen (bool fullScreen) {
1487     checkWidget();
1488     if (fullScreen) {
1489         OS.gtk_window_fullscreen (shellHandle);
1490     } else {
1491         OS.gtk_window_unfullscreen (shellHandle);
1492         if (maximized) {
1493             setMaximized (true);
1494         }
1495     }
1496     this.fullScreen = fullScreen;
1497 }
1498 
1499 /**
1500  * Sets the input method editor mode to the argument which
1501  * should be the result of bitwise OR'ing together one or more
1502  * of the following constants defined in class <code>SWT</code>:
1503  * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>,
1504  * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
1505  *
1506  * @param mode the new IME mode
1507  *
1508  * @exception SWTException <ul>
1509  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1510  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1511  * </ul>
1512  *
1513  * @see SWT
1514  */
1515 public void setImeInputMode (int mode) {
1516     checkWidget();
1517 }
1518 
1519 override void setInitialBounds () {
1520     if ((state & FOREIGN_HANDLE) !is 0) return;
1521     org.eclipse.swt.widgets.Monitor.Monitor monitor = getMonitor ();
1522     Rectangle rect = monitor.getClientArea ();
1523     int width = rect.width * 5 / 8;
1524     int height = rect.height * 5 / 8;
1525     if ((style & SWT.RESIZE) !is 0) {
1526         OS.gtk_window_resize (cast(GtkWindow*)shellHandle, width, height);
1527     }
1528     resizeBounds (width, height, false);
1529 }
1530 
1531 public override void setMaximized (bool maximized) {
1532     checkWidget();
1533     super.setMaximized (maximized);
1534     if (maximized) {
1535         OS.gtk_window_maximize (cast(GtkWindow*)shellHandle);
1536     } else {
1537         OS.gtk_window_unmaximize (cast(GtkWindow*)shellHandle);
1538     }
1539 }
1540 
1541 public override void setMenuBar (Menu menu) {
1542     checkWidget();
1543     if (menuBar is menu) return;
1544     bool both = menu !is null && menuBar !is null;
1545     if (menu !is null) {
1546         if ((menu.style & SWT.BAR) is 0) error (SWT.ERROR_MENU_NOT_BAR);
1547         if (menu.parent !is this) error (SWT.ERROR_INVALID_PARENT);
1548     }
1549     if (menuBar !is null) {
1550         auto menuHandle = menuBar.handle;
1551         OS.gtk_widget_hide (menuHandle);
1552         destroyAccelGroup ();
1553     }
1554     menuBar = menu;
1555     if (menuBar !is null) {
1556         auto menuHandle = menu.handle;
1557         OS.gtk_widget_show (menuHandle);
1558         createAccelGroup ();
1559         menuBar.addAccelerators (accelGroup);
1560     }
1561     int width = OS.GTK_WIDGET_WIDTH (vboxHandle);
1562     int height = OS.GTK_WIDGET_HEIGHT (vboxHandle);
1563     resizeBounds (width, height, !both);
1564 }
1565 
1566 public override void setMinimized (bool minimized) {
1567     checkWidget();
1568     if (this.minimized is minimized) return;
1569     super.setMinimized (minimized);
1570     if (minimized) {
1571         OS.gtk_window_iconify (cast(GtkWindow*)shellHandle);
1572     } else {
1573         OS.gtk_window_deiconify (cast(GtkWindow*)shellHandle);
1574         bringToTop (false);
1575     }
1576 }
1577 
1578 /**
1579  * Sets the receiver's minimum size to the size specified by the arguments.
1580  * If the new minimum size is larger than the current size of the receiver,
1581  * the receiver is resized to the new minimum size.
1582  *
1583  * @param width the new minimum width for the receiver
1584  * @param height the new minimum height for the receiver
1585  *
1586  * @exception SWTException <ul>
1587  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1588  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1589  * </ul>
1590  *
1591  * @since 3.1
1592  */
1593 public void setMinimumSize (int width, int height) {
1594     checkWidget ();
1595     GdkGeometry* geometry = new GdkGeometry ();
1596     minWidth = geometry.min_width = Math.max (width, trimWidth ()) - trimWidth ();
1597     minHeight = geometry.min_height = Math.max (height, trimHeight ()) - trimHeight ();
1598     OS.gtk_window_set_geometry_hints (cast(GtkWindow*)shellHandle, null, geometry, OS.GDK_HINT_MIN_SIZE);
1599 }
1600 
1601 /**
1602  * Sets the receiver's minimum size to the size specified by the argument.
1603  * If the new minimum size is larger than the current size of the receiver,
1604  * the receiver is resized to the new minimum size.
1605  *
1606  * @param size the new minimum size for the receiver
1607  *
1608  * @exception IllegalArgumentException <ul>
1609  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
1610  * </ul>
1611  * @exception SWTException <ul>
1612  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1613  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1614  * </ul>
1615  *
1616  * @since 3.1
1617  */
1618 public void setMinimumSize (Point size) {
1619     checkWidget ();
1620     if (size is null) error (SWT.ERROR_NULL_ARGUMENT);
1621     setMinimumSize (size.x, size.y);
1622 }
1623 
1624 /**
1625  * Sets the shape of the shell to the region specified
1626  * by the argument.  When the argument is null, the
1627  * default shape of the shell is restored.  The shell
1628  * must be created with the style SWT.NO_TRIM in order
1629  * to specify a region.
1630  *
1631  * @param region the region that defines the shape of the shell (or null)
1632  *
1633  * @exception IllegalArgumentException <ul>
1634  *    <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
1635  * </ul>
1636  * @exception SWTException <ul>
1637  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1638  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1639  * </ul>
1640  *
1641  * @since 3.0
1642  *
1643  */
1644 override
1645 public void setRegion (Region region) {
1646     checkWidget ();
1647     if ((style & SWT.NO_TRIM) is 0) return;
1648     super.setRegion (region);
1649 }
1650 
1651 /*
1652  * Shells are never labelled by other widgets, so no initialization is needed.
1653  */
1654 override void setRelations() {
1655 }
1656 
1657 public override void setText (String string) {
1658     super.setText (string);
1659 
1660     /*
1661     * GTK bug 82013.  For some reason, if the title string
1662     * is less than 7 bytes long and is not terminated by
1663     * a space, some window managers occasionally draw
1664     * garbage after the last character in  the title.
1665     * The fix is to pad the title.
1666     */
1667     ptrdiff_t length_ = string.length;
1668     char [] chars = new char [Math.max (6, length_) + 1];
1669     chars[ 0 .. length_ ] = string[ 0 .. length_];
1670     for (ptrdiff_t i=length_; i<chars.length; i++)  chars [i] = ' ';
1671     OS.gtk_window_set_title (cast(GtkWindow*)shellHandle, toStringz( chars ) );
1672 }
1673 
1674 public override void setVisible (bool visible) {
1675     checkWidget();
1676     int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
1677     if ((style & mask) !is 0) {
1678         if (visible) {
1679             display.setModalShell (this);
1680             OS.gtk_window_set_modal (shellHandle, true);
1681         } else {
1682             display.clearModal (this);
1683             OS.gtk_window_set_modal (shellHandle, false);
1684         }
1685     } else {
1686         updateModal ();
1687     }
1688     showWithParent = visible;
1689     if ((OS.GTK_WIDGET_MAPPED (shellHandle) is visible)) return;
1690     if (visible) {
1691         sendEvent (SWT.Show);
1692         if (isDisposed ()) return;
1693 
1694         /*
1695         * In order to ensure that the shell is visible
1696         * and fully painted, dispatch events such as
1697         * GDK_MAP and GDK_CONFIGURE, until the GDK_MAP
1698         * event for the shell is received.
1699         *
1700         * Note that if the parent is minimized or withdrawn
1701         * from the desktop, this should not be done since
1702         * the shell not will be mapped until the parent is
1703         * unminimized or shown on the desktop.
1704         */
1705         OS.gtk_widget_show (shellHandle);
1706         if (enableWindow !is null) OS.gdk_window_raise (enableWindow);
1707         if (!OS.GTK_IS_PLUG (cast(GTypeInstance*)shellHandle)) {
1708             mapped = false;
1709             if (isDisposed ()) return;
1710             display.dispatchEvents = [
1711                 OS.GDK_EXPOSE,
1712                 OS.GDK_FOCUS_CHANGE,
1713                 OS.GDK_CONFIGURE,
1714                 OS.GDK_MAP,
1715                 OS.GDK_UNMAP,
1716                 OS.GDK_NO_EXPOSE
1717             ];
1718             Display display = this.display;
1719             display.putGdkEvents();
1720             bool iconic = false;
1721             Shell shell = parent !is null ? parent.getShell() : null;
1722             do {
1723                 OS.g_main_context_iteration (null, false);
1724                 if (isDisposed ()) break;
1725                 iconic = minimized || (shell !is null && shell.minimized);
1726             } while (!mapped && !iconic);
1727             display.dispatchEvents = null;
1728             if (isDisposed ()) return;
1729             if (!iconic) {
1730                 update (true, true);
1731                 if (isDisposed ()) return;
1732                 adjustTrim ();
1733             }
1734         }
1735         mapped = true;
1736 
1737         if ((style & mask) !is 0) {
1738             OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME);
1739         }
1740         opened = true;
1741         if (!moved) {
1742             moved = true;
1743             Point location = getLocation();
1744             oldX = location.x;
1745             oldY = location.y;
1746             sendEvent (SWT.Move);
1747             if (isDisposed ()) return;
1748         }
1749         if (!resized) {
1750             resized = true;
1751             Point size = getSize ();
1752             oldWidth = size.x - trimWidth ();
1753             oldHeight = size.y - trimHeight ();
1754             sendEvent (SWT.Resize);
1755             if (isDisposed ()) return;
1756             if (layout_ !is null) {
1757                 markLayout (false, false);
1758                 updateLayout (false);
1759             }
1760         }
1761     } else {
1762         fixActiveShell ();
1763         OS.gtk_widget_hide (shellHandle);
1764         sendEvent (SWT.Hide);
1765     }
1766 }
1767 
1768 override void setZOrder (Control sibling, bool above, bool fixRelations) {
1769     /*
1770     * Bug in GTK+.  Changing the toplevel window Z-order causes
1771     * X to send a resize event.  Before the shell is mapped, these
1772     * resize events always have a size of 200x200, causing extra
1773     * layout work to occur.  The fix is to modify the Z-order only
1774     * if the shell has already been mapped at least once.
1775     */
1776     /* Shells are never included in labelled-by relations */
1777     if (mapped) setZOrder (sibling, above, false, false);
1778 }
1779 
1780 override int shellMapProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
1781     mapped = true;
1782     display.dispatchEvents = null;
1783     return 0;
1784 }
1785 
1786 override
1787 void showWidget () {
1788     if ((state & FOREIGN_HANDLE) !is 0) return;
1789     OS.gtk_container_add (cast(GtkContainer*)shellHandle, vboxHandle);
1790     if (scrolledHandle !is null) OS.gtk_widget_show (scrolledHandle);
1791     if (handle !is null) OS.gtk_widget_show (handle);
1792     if (vboxHandle !is null) OS.gtk_widget_show (vboxHandle);
1793 }
1794 
1795 override int sizeAllocateProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
1796     int offset = 16;
1797     int x, y;
1798     OS.gdk_window_get_pointer (null, &x, &y, null);
1799     y += offset;
1800     auto screen = OS.gdk_screen_get_default ();
1801     if (screen !is null) {
1802         int monitorNumber = OS.gdk_screen_get_monitor_at_point (screen, x, y);
1803         GdkRectangle* dest = new GdkRectangle ();
1804         OS.gdk_screen_get_monitor_geometry (screen, monitorNumber, dest);
1805         int width = OS.GTK_WIDGET_WIDTH (handle);
1806         int height = OS.GTK_WIDGET_HEIGHT (handle);
1807         if (x + width > dest.x + dest.width) {
1808             x = (dest.x + dest.width) - width;
1809         }
1810         if (y + height > dest.y + dest.height) {
1811             y = (dest.y + dest.height) - height;
1812         }
1813     }
1814     OS.gtk_window_move (cast(GtkWindow*)handle, x, y);
1815     return 0;
1816 }
1817 
1818 override int sizeRequestProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
1819     OS.gtk_widget_hide (handle);
1820     return 0;
1821 }
1822 
1823 override bool traverseEscape () {
1824     if (parent is null) return false;
1825     if (!isVisible () || !isEnabled ()) return false;
1826     close ();
1827     return true;
1828 }
1829 int trimHeight () {
1830     if ((style & SWT.NO_TRIM) !is 0) return 0;
1831     if (fullScreen) return 0;
1832     bool hasTitle = false, hasResize = false, hasBorder = false;
1833     hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) !is 0;
1834     hasResize = (style & SWT.RESIZE) !is 0;
1835     hasBorder = (style & SWT.BORDER) !is 0;
1836     if (hasTitle) {
1837         if (hasResize) return display.titleResizeTrimHeight;
1838         if (hasBorder) return display.titleBorderTrimHeight;
1839         return display.titleTrimHeight;
1840     }
1841     if (hasResize) return display.resizeTrimHeight;
1842     if (hasBorder) return display.borderTrimHeight;
1843     return 0;
1844 }
1845 
1846 int trimWidth () {
1847     if ((style & SWT.NO_TRIM) !is 0) return 0;
1848     if (fullScreen) return 0;
1849     bool hasTitle = false, hasResize = false, hasBorder = false;
1850     hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) !is 0;
1851     hasResize = (style & SWT.RESIZE) !is 0;
1852     hasBorder = (style & SWT.BORDER) !is 0;
1853     if (hasTitle) {
1854         if (hasResize) return display.titleResizeTrimWidth;
1855         if (hasBorder) return display.titleBorderTrimWidth;
1856         return display.titleTrimWidth;
1857     }
1858     if (hasResize) return display.resizeTrimWidth;
1859     if (hasBorder) return display.borderTrimWidth;
1860     return 0;
1861 }
1862 
1863 void updateModal () {
1864     GtkWidget* group = null;
1865     if (display.getModalDialog () is null) {
1866         Shell modal = getModalShell ();
1867         int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
1868         Composite shell = null;
1869         if (modal is null) {
1870             if ((style & mask) !is 0) shell = this;
1871         } else {
1872             shell = modal;
1873         }
1874         while (shell !is null) {
1875             if ((shell.style & mask) is 0) {
1876                 group = shell.getShell ().group;
1877                 break;
1878             }
1879             shell = shell.parent;
1880         }
1881     }
1882     if (OS.GTK_VERSION >= OS.buildVERSION (2, 10, 0) && group is null) {
1883         /*
1884         * Feature in GTK. Starting with GTK version 2.10, GTK
1885         * doesn't assign windows to a default group. The fix is to
1886         * get the handle of the default group and add windows to the
1887         * group.
1888         */
1889         group = cast(GtkWidget*)OS.gtk_window_get_group(null);
1890     }
1891     if (group !is null) {
1892         OS.gtk_window_group_add_window (group, shellHandle);
1893     } else {
1894         if (modalGroup !is null) {
1895             OS.gtk_window_group_remove_window (modalGroup, shellHandle);
1896         }
1897     }
1898     if (OS.GTK_VERSION < OS.buildVERSION (2, 4, 0)) {
1899         fixModal (group, modalGroup);
1900     }
1901     modalGroup = group;
1902 }
1903 
1904 void updateMinimized (bool minimized) {
1905     Shell[] shells = getShells ();
1906     for (int i = 0; i < shells.length; i++) {
1907         bool update = false;
1908         Shell shell = shells[i];
1909         while (shell !is null && shell !is this && !shell.isUndecorated ()) {
1910             shell = cast(Shell) shell.getParent ();
1911         }
1912         if (shell !is null && shell !is this) update = true;
1913         if (update) {
1914             if (minimized) {
1915                 if (shells[i].isVisible ()) {
1916                     shells[i].showWithParent = true;
1917                     OS.gtk_widget_hide(shells[i].shellHandle);
1918                 }
1919             } else {
1920                 if (shells[i].showWithParent) {
1921                     shells[i].showWithParent = false;
1922                     OS.gtk_widget_show(shells[i].shellHandle);
1923                 }
1924             }
1925         }
1926     }
1927 }
1928 
1929 override void deregister () {
1930     super.deregister ();
1931     display.removeWidget (shellHandle);
1932 }
1933 
1934 override public void dispose () {
1935     /*
1936     * Note:  It is valid to attempt to dispose a widget
1937     * more than once.  If this happens, fail silently.
1938     */
1939     if (isDisposed()) return;
1940     fixActiveShell ();
1941     OS.gtk_widget_hide (shellHandle);
1942     super.dispose ();
1943 }
1944 
1945 /**
1946  * If the receiver is visible, moves it to the top of the
1947  * drawing order for the display on which it was created
1948  * (so that all other shells on that display, which are not
1949  * the receiver's children will be drawn behind it) and forces
1950  * the window manager to make the shell active.
1951  *
1952  * @exception SWTException <ul>
1953  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1954  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1955  * </ul>
1956  *
1957  * @since 2.0
1958  * @see Control#moveAbove
1959  * @see Control#setFocus
1960  * @see Control#setVisible
1961  * @see Display#getActiveShell
1962  * @see Decorations#setDefaultButton(Button)
1963  * @see Shell#open
1964  * @see Shell#setActive
1965  */
1966 public void forceActive () {
1967     checkWidget ();
1968     bringToTop (true);
1969 }
1970 
1971 override public Rectangle getBounds () {
1972     checkWidget ();
1973     int x, y ;
1974     OS.gtk_window_get_position (cast(GtkWindow*)shellHandle, &x, &y);
1975     int width = OS.GTK_WIDGET_WIDTH (vboxHandle);
1976     int height = OS.GTK_WIDGET_HEIGHT (vboxHandle);
1977     int border = 0;
1978     if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.SHELL_TRIM)) is 0) {
1979         border = OS.gtk_container_get_border_width (cast(GtkContainer*)shellHandle);
1980     }
1981     return new Rectangle (x, y, width + trimWidth () + 2*border, height + trimHeight () + 2*border);
1982 }
1983 
1984 override void releaseHandle () {
1985     super.releaseHandle ();
1986     shellHandle = null;
1987 }
1988 
1989 override void releaseChildren (bool destroy) {
1990     Shell [] shells = getShells ();
1991     for (int i=0; i<shells.length; i++) {
1992         Shell shell = shells [i];
1993         if (shell !is null && !shell.isDisposed ()) {
1994             shell.release (false);
1995         }
1996     }
1997     super.releaseChildren (destroy);
1998 }
1999 
2000 override void releaseWidget () {
2001     super.releaseWidget ();
2002     destroyAccelGroup ();
2003     display.clearModal (this);
2004     if (display.activeShell is this) display.activeShell = null;
2005     if (tooltipsHandle !is null) OS.g_object_unref (tooltipsHandle);
2006     tooltipsHandle = null;
2007     if (group !is null) OS.g_object_unref (group);
2008     group = modalGroup = null;
2009     auto window = OS.GTK_WIDGET_WINDOW (shellHandle);
2010     display.doWindowRemoveFilter( &filterProcCallbackData, window, shellHandle );
2011 
2012     lastActive = null;
2013 }
2014 
2015 void setToolTipText (GtkWidget* tipWidget, String string) {
2016     setToolTipText (tipWidget, tipWidget, string);
2017 }
2018 
2019 void setToolTipText (GtkWidget* rootWidget, GtkWidget* tipWidget, String string) {
2020     if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
2021         char * buffer = null;
2022         if (string !is null && string.length > 0) {
2023             char [] chars = fixMnemonic (string, false);
2024             buffer = toStringz( chars );
2025         }
2026         OS.gtk_widget_set_tooltip_text (rootWidget, null);
2027         /*
2028         * Bug in GTK. In GTK 2.12, due to a miscalculation of window
2029         * coordinates, using gtk_tooltip_trigger_tooltip_query ()
2030         * to update an existing a tooltip will result in the tooltip
2031         * being displayed at a wrong position. The fix is to send out
2032         * 2 fake GDK_MOTION_NOTIFY events (to mimic the GTK call) which
2033         * contain the proper x and y coordinates.
2034         */
2035         GdkEvent* eventPtr = null;
2036         auto tipWindow = OS.GTK_WIDGET_WINDOW (rootWidget);
2037         if (tipWindow !is null) {
2038             int x, y;
2039             auto window = OS.gdk_window_at_pointer (&x, &y);
2040             void* user_data;
2041             if( window !is null ) OS.gdk_window_get_user_data (window, &user_data);
2042             if (tipWidget is user_data ) {
2043                 eventPtr = OS.gdk_event_new (OS.GDK_MOTION_NOTIFY);
2044                 eventPtr.type = OS.GDK_MOTION_NOTIFY;
2045                 eventPtr.motion.window = cast(GdkDrawable*)OS.g_object_ref (tipWindow);
2046                 eventPtr.motion.x = x;
2047                 eventPtr.motion.y = y;
2048                 OS.gdk_window_get_origin (window, &x, &y);
2049                 eventPtr.motion.x_root = eventPtr.motion.x + x;
2050                 eventPtr.motion.y_root = eventPtr.motion.y + y;
2051                 OS.gtk_main_do_event (eventPtr);
2052             }
2053         }
2054         OS.gtk_widget_set_tooltip_text (rootWidget, buffer);
2055         if (eventPtr !is null) {
2056             OS.gtk_main_do_event (eventPtr);
2057             OS.gdk_event_free (eventPtr);
2058         }
2059     } else {
2060         char* buffer = null;
2061         if (string !is null && string.length > 0) {
2062             char [] chars = fixMnemonic (string, false);
2063             buffer = toStringz( chars );
2064         }
2065         if (tooltipsHandle is null) {
2066             tooltipsHandle = cast(GtkWidget*)OS.gtk_tooltips_new ();
2067             if (tooltipsHandle is null) error (SWT.ERROR_NO_HANDLES);
2068             OS.g_object_ref (tooltipsHandle);
2069             OS.gtk_object_sink (cast(GtkObject*)tooltipsHandle);
2070         }
2071 
2072         /*
2073         * Feature in GTK.  There is no API to position a tooltip.
2074         * The fix is to connect to the size_allocate signal for
2075         * the tooltip window and position it before it is mapped.
2076         *
2077         * Bug in Solaris-GTK.  Invoking gtk_tooltips_force_window()
2078         * can cause a crash in older versions of GTK.  The fix is
2079         * to avoid this call if the GTK version is older than 2.2.x.
2080         */
2081         if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 1)) {
2082             OS.gtk_tooltips_force_window (cast(GtkTooltips*)tooltipsHandle);
2083         }
2084         auto tipWindow = OS.GTK_TOOLTIPS_TIP_WINDOW (cast(GtkTooltips*)tooltipsHandle);
2085         if (tipWindow !is null && tipWindow !is tooltipWindow) {
2086             display.doSizeAllocateConnect( &sizeAllocateProcCallbackData, tipWindow, shellHandle );
2087             tooltipWindow = tipWindow;
2088         }
2089 
2090         /*
2091         * Bug in GTK.  If the cursor is inside the window when a new
2092         * tooltip is set and the old tooltip is hidden, the new tooltip
2093         * is not displayed until the mouse re-enters the window.  The
2094         * fix is force the new tooltip to be active.
2095         */
2096         bool set = true;
2097         if (tipWindow !is null) {
2098             if ((OS.GTK_WIDGET_FLAGS (tipWidget) & (OS.GTK_REALIZED | OS.GTK_VISIBLE)) !is 0) {
2099                 int  x, y;
2100                 auto window = OS.gdk_window_at_pointer (&x, &y);
2101                 if (window !is null) {
2102                     GtkWidget* user_data;
2103                     OS.gdk_window_get_user_data (window, cast(void**)&user_data);
2104                     if (tipWidget is user_data) {
2105                         /*
2106                         * Feature in GTK.  Calling gtk_tooltips_set_tip() positions and
2107                         * shows the tooltip.  If the tooltip is already visible, moving
2108                         * it to a new location in the size_allocate signal causes flashing.
2109                         * The fix is to hide the tip window in the size_request signal
2110                         * and before the new tooltip is forced to be active.
2111                         */
2112                         set = false;
2113                         auto handler_id = display.doSizeRequestConnect( &sizeRequestProcCallbackData, tipWindow, shellHandle );
2114                         OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null);
2115                         OS.gtk_widget_hide (tipWindow);
2116                         auto data = OS.gtk_tooltips_data_get (tipWidget);
2117                         OS.GTK_TOOLTIPS_SET_ACTIVE (cast(GtkTooltips*)tooltipsHandle, cast(GtkTooltipsData*)data);
2118                         OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null);
2119                         if (handler_id !is 0) OS.g_signal_handler_disconnect (tipWindow, handler_id);
2120                     }
2121                 }
2122             }
2123         }
2124         if (set) OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null);
2125     }
2126 
2127 }
2128 }