Source code: org/eclipse/swt/widgets/Shell.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.swt.widgets;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.internal.*;
16 import org.eclipse.swt.internal.gtk.*;
17 import org.eclipse.swt.graphics.*;
18 import org.eclipse.swt.events.*;
19
20 /**
21 * Instances of this class represent the "windows"
22 * which the desktop or "window manager" is managing.
23 * Instances that do not have a parent (that is, they
24 * are built using the constructor, which takes a
25 * <code>Display</code> as the argument) are described
26 * as <em>top level</em> shells. Instances that do have
27 * a parent are described as <em>secondary</em> or
28 * <em>dialog</em> shells.
29 * <p>
30 * Instances are always displayed in one of the maximized,
31 * minimized or normal states:
32 * <ul>
33 * <li>
34 * When an instance is marked as <em>maximized</em>, the
35 * window manager will typically resize it to fill the
36 * entire visible area of the display, and the instance
37 * is usually put in a state where it can not be resized
38 * (even if it has style <code>RESIZE</code>) until it is
39 * no longer maximized.
40 * </li><li>
41 * When an instance is in the <em>normal</em> state (neither
42 * maximized or minimized), its appearance is controlled by
43 * the style constants which were specified when it was created
44 * and the restrictions of the window manager (see below).
45 * </li><li>
46 * When an instance has been marked as <em>minimized</em>,
47 * its contents (client area) will usually not be visible,
48 * and depending on the window manager, it may be
49 * "iconified" (that is, replaced on the desktop by a small
50 * simplified representation of itself), relocated to a
51 * distinguished area of the screen, or hidden. Combinations
52 * of these changes are also possible.
53 * </li>
54 * </ul>
55 * </p>
56 * <p>
57 * Note: The styles supported by this class must be treated
58 * as <em>HINT</em>s, since the window manager for the
59 * desktop on which the instance is visible has ultimate
60 * control over the appearance and behavior of decorations
61 * and modality. For example, some window managers only
62 * support resizable windows and will always assume the
63 * RESIZE style, even if it is not set. In addition, if a
64 * modality style is not supported, it is "upgraded" to a
65 * more restrictive modality style that is supported. For
66 * example, if <code>PRIMARY_MODAL</code> is not supported,
67 * it would be upgraded to <code>APPLICATION_MODAL</code>.
68 * <dl>
69 * <dt><b>Styles:</b></dt>
70 * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE</dd>
71 * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd>
72 * <dt><b>Events:</b></dt>
73 * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd>
74 * </dl>
75 * Class <code>SWT</code> provides two "convenience constants"
76 * for the most commonly required style combinations:
77 * <dl>
78 * <dt><code>SHELL_TRIM</code></dt>
79 * <dd>
80 * the result of combining the constants which are required
81 * to produce a typical application top level shell: (that
82 * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
83 * </dd>
84 * <dt><code>DIALOG_TRIM</code></dt>
85 * <dd>
86 * the result of combining the constants which are required
87 * to produce a typical application dialog shell: (that
88 * is, <code>TITLE | CLOSE | BORDER</code>)
89 * </dd>
90 * </dl>
91 * </p>
92 * <p>
93 * Note: Only one of the styles APPLICATION_MODAL, MODELESS,
94 * PRIMARY_MODAL and SYSTEM_MODAL may be specified.
95 * </p><p>
96 * IMPORTANT: This class is not intended to be subclassed.
97 * </p>
98 *
99 * @see Decorations
100 * @see SWT
101 */
102 public class Shell extends Decorations {
103 long /*int*/ shellHandle, tooltipsHandle;
104 boolean hasFocus, mapped;
105 int oldX, oldY, oldWidth, oldHeight;
106 Control lastActive;
107 Region region;
108
109 /**
110 * Constructs a new instance of this class. This is equivalent
111 * to calling <code>Shell((Display) null)</code>.
112 *
113 * @exception SWTException <ul>
114 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
115 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
116 * </ul>
117 */
118 public Shell () {
119 this ((Display) null);
120 }
121 /**
122 * Constructs a new instance of this class given only the style
123 * value describing its behavior and appearance. This is equivalent
124 * to calling <code>Shell((Display) null, style)</code>.
125 * <p>
126 * The style value is either one of the style constants defined in
127 * class <code>SWT</code> which is applicable to instances of this
128 * class, or must be built by <em>bitwise OR</em>'ing together
129 * (that is, using the <code>int</code> "|" operator) two or more
130 * of those <code>SWT</code> style constants. The class description
131 * lists the style constants that are applicable to the class.
132 * Style bits are also inherited from superclasses.
133 * </p>
134 *
135 * @param style the style of control to construct
136 *
137 * @exception SWTException <ul>
138 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
139 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
140 * </ul>
141 *
142 * @see SWT#BORDER
143 * @see SWT#CLOSE
144 * @see SWT#MIN
145 * @see SWT#MAX
146 * @see SWT#RESIZE
147 * @see SWT#TITLE
148 * @see SWT#NO_TRIM
149 * @see SWT#SHELL_TRIM
150 * @see SWT#DIALOG_TRIM
151 * @see SWT#MODELESS
152 * @see SWT#PRIMARY_MODAL
153 * @see SWT#APPLICATION_MODAL
154 * @see SWT#SYSTEM_MODAL
155 */
156 public Shell (int style) {
157 this ((Display) null, style);
158 }
159
160 /**
161 * Constructs a new instance of this class given only the display
162 * to create it on. It is created with style <code>SWT.SHELL_TRIM</code>.
163 * <p>
164 * Note: Currently, null can be passed in for the display argument.
165 * This has the effect of creating the shell on the currently active
166 * display if there is one. If there is no current display, the
167 * shell is created on a "default" display. <b>Passing in null as
168 * the display argument is not considered to be good coding style,
169 * and may not be supported in a future release of SWT.</b>
170 * </p>
171 *
172 * @param display the display to create the shell on
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 Shell (Display display) {
180 this (display, SWT.SHELL_TRIM);
181 }
182 /**
183 * Constructs a new instance of this class given the display
184 * to create it on and a style value describing its behavior
185 * and appearance.
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><p>
195 * Note: Currently, null can be passed in for the display argument.
196 * This has the effect of creating the shell on the currently active
197 * display if there is one. If there is no current display, the
198 * shell is created on a "default" display. <b>Passing in null as
199 * the display argument is not considered to be good coding style,
200 * and may not be supported in a future release of SWT.</b>
201 * </p>
202 *
203 * @param display the display to create the shell on
204 * @param style the style of control to construct
205 *
206 * @exception SWTException <ul>
207 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
208 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
209 * </ul>
210 *
211 * @see SWT#BORDER
212 * @see SWT#CLOSE
213 * @see SWT#MIN
214 * @see SWT#MAX
215 * @see SWT#RESIZE
216 * @see SWT#TITLE
217 * @see SWT#NO_TRIM
218 * @see SWT#SHELL_TRIM
219 * @see SWT#DIALOG_TRIM
220 * @see SWT#MODELESS
221 * @see SWT#PRIMARY_MODAL
222 * @see SWT#APPLICATION_MODAL
223 * @see SWT#SYSTEM_MODAL
224 */
225 public Shell (Display display, int style) {
226 this (display, null, style, 0);
227 }
228
229 Shell (Display display, Shell parent, int style, long /*int*/ handle) {
230 super ();
231 checkSubclass ();
232 if (display == null) display = Display.getCurrent ();
233 if (display == null) display = Display.getDefault ();
234 if (!display.isValidThread ()) {
235 error (SWT.ERROR_THREAD_INVALID_ACCESS);
236 }
237 this.style = checkStyle (style);
238 this.parent = parent;
239 this.display = display;
240 this.handle = handle;
241 createWidget (0);
242 }
243
244 /**
245 * Constructs a new instance of this class given only its
246 * parent. It is created with style <code>SWT.DIALOG_TRIM</code>.
247 * <p>
248 * Note: Currently, null can be passed in for the parent.
249 * This has the effect of creating the shell on the currently active
250 * display if there is one. If there is no current display, the
251 * shell is created on a "default" display. <b>Passing in null as
252 * the parent is not considered to be good coding style,
253 * and may not be supported in a future release of SWT.</b>
254 * </p>
255 *
256 * @param parent a shell which will be the parent of the new instance
257 *
258 * @exception IllegalArgumentException <ul>
259 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
260 * </ul>
261 * @exception SWTException <ul>
262 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
263 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
264 * </ul>
265 */
266 public Shell (Shell parent) {
267 this (parent, SWT.DIALOG_TRIM);
268 }
269
270 /**
271 * Constructs a new instance of this class given its parent
272 * and a style value describing its behavior and appearance.
273 * <p>
274 * The style value is either one of the style constants defined in
275 * class <code>SWT</code> which is applicable to instances of this
276 * class, or must be built by <em>bitwise OR</em>'ing together
277 * (that is, using the <code>int</code> "|" operator) two or more
278 * of those <code>SWT</code> style constants. The class description
279 * lists the style constants that are applicable to the class.
280 * Style bits are also inherited from superclasses.
281 * </p><p>
282 * Note: Currently, null can be passed in for the parent.
283 * This has the effect of creating the shell on the currently active
284 * display if there is one. If there is no current display, the
285 * shell is created on a "default" display. <b>Passing in null as
286 * the parent is not considered to be good coding style,
287 * and may not be supported in a future release of SWT.</b>
288 * </p>
289 *
290 * @param parent a shell which will be the parent of the new instance
291 * @param style the style of control to construct
292 *
293 * @exception SWTException <ul>
294 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
295 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
296 * </ul>
297 *
298 * @see SWT#BORDER
299 * @see SWT#CLOSE
300 * @see SWT#MIN
301 * @see SWT#MAX
302 * @see SWT#RESIZE
303 * @see SWT#TITLE
304 * @see SWT#NO_TRIM
305 * @see SWT#SHELL_TRIM
306 * @see SWT#DIALOG_TRIM
307 * @see SWT#MODELESS
308 * @see SWT#PRIMARY_MODAL
309 * @see SWT#APPLICATION_MODAL
310 * @see SWT#SYSTEM_MODAL
311 */
312 public Shell (Shell parent, int style) {
313 this (parent != null ? parent.display : null, parent, style, 0);
314 }
315
316 public static Shell gtk_new (Display display, long /*int*/ handle) {
317 return new Shell (display, null, SWT.NO_TRIM, handle);
318 }
319
320 static int checkStyle (int style) {
321 style = Decorations.checkStyle (style);
322 if ((style & SWT.ON_TOP) != 0) style &= ~SWT.SHELL_TRIM;
323 int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL;
324 int bits = style & ~mask;
325 if ((style & SWT.SYSTEM_MODAL) != 0) return bits | SWT.SYSTEM_MODAL;
326 if ((style & SWT.APPLICATION_MODAL) != 0) return bits | SWT.APPLICATION_MODAL;
327 if ((style & SWT.PRIMARY_MODAL) != 0) return bits | SWT.PRIMARY_MODAL;
328 return bits;
329 }
330
331 /**
332 * Adds the listener to the collection of listeners who will
333 * be notified when operations are performed on the receiver,
334 * by sending the listener one of the messages defined in the
335 * <code>ShellListener</code> interface.
336 *
337 * @param listener the listener which should be notified
338 *
339 * @exception IllegalArgumentException <ul>
340 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
341 * </ul>
342 * @exception SWTException <ul>
343 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
344 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
345 * </ul>
346 *
347 * @see ShellListener
348 * @see #removeShellListener
349 */
350 public void addShellListener (ShellListener listener) {
351 checkWidget();
352 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
353 TypedListener typedListener = new TypedListener (listener);
354 addListener (SWT.Close,typedListener);
355 addListener (SWT.Iconify,typedListener);
356 addListener (SWT.Deiconify,typedListener);
357 addListener (SWT.Activate, typedListener);
358 addListener (SWT.Deactivate, typedListener);
359 }
360
361 void adjustTrim () {
362 int [] width = new int [1], height = new int [1];
363 OS.gtk_window_get_size (shellHandle, width, height);
364 long /*int*/ window = OS.GTK_WIDGET_WINDOW (shellHandle);
365 GdkRectangle rect = new GdkRectangle ();
366 OS.gdk_window_get_frame_extents (window, rect);
367 int trimWidth = Math.max (0, rect.width - width [0]);
368 int trimHeight = Math.max (0, rect.height - height [0]);
369 boolean hasTitle = false, hasResize = false, hasBorder = false;
370 if ((style & SWT.NO_TRIM) == 0) {
371 hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) != 0;
372 hasResize = (style & SWT.RESIZE) != 0;
373 hasBorder = (style & SWT.BORDER) != 0;
374 }
375 if (hasTitle) {
376 if (hasResize) {
377 display.titleResizeTrimWidth = trimWidth;
378 display.titleResizeTrimHeight = trimHeight;
379 return;
380 }
381 if (hasBorder) {
382 display.titleBorderTrimWidth = trimWidth;
383 display.titleBorderTrimHeight = trimHeight;
384 return;
385 }
386 display.titleTrimWidth = trimWidth;
387 display.titleTrimHeight = trimHeight;
388 return;
389 }
390 if (hasResize) {
391 display.resizeTrimWidth = trimWidth;
392 display.resizeTrimHeight = trimHeight;
393 return;
394 }
395 if (hasBorder) {
396 display.borderTrimWidth = trimWidth;
397 display.borderTrimHeight = trimHeight;
398 return;
399 }
400 }
401
402 void bringToTop (boolean force) {
403 if (!OS.GTK_WIDGET_VISIBLE (shellHandle)) return;
404 if (hasFocus) return;
405 Shell shell = display.getActiveShell ();
406 if (!force) {
407 if (shell == null) return;
408 long /*int*/ focusHandle = OS.gtk_window_get_focus (shell.shellHandle);
409 if (focusHandle != 0) {
410 if (!OS.GTK_WIDGET_HAS_FOCUS (focusHandle)) return;
411 }
412 }
413 if (shell != null) shell.hasFocus = false;
414 /*
415 * Feature in GTK. When the shell is an override redirect
416 * window, gdk_window_focus() does not give focus to the
417 * window. The fix is to use XSetInputFocus() to force
418 * the focus.
419 */
420 long /*int*/ window = OS.GTK_WIDGET_WINDOW (shellHandle);
421 if ((style & SWT.ON_TOP) != 0 && OS.GDK_WINDOWING_X11 ()) {
422 long /*int*/ xDisplay = OS.gdk_x11_drawable_get_xdisplay (window);
423 long /*int*/ xWindow = OS.gdk_x11_drawable_get_xid (window);
424 OS.gdk_error_trap_push ();
425 OS.XSetInputFocus (xDisplay, xWindow, OS.RevertToParent, OS.gtk_get_current_event_time ());
426 OS.gdk_error_trap_pop ();
427 } else {
428 OS.gdk_window_focus (window, OS.gtk_get_current_event_time ());
429 }
430 hasFocus = true;
431 }
432
433 /**
434 * Requests that the window manager close the receiver in
435 * the same way it would be closed when the user clicks on
436 * the "close box" or performs some other platform specific
437 * key or mouse combination that indicates the window
438 * should be removed.
439 *
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 SWT#Close
446 * @see #dispose
447 */
448 public void close () {
449 checkWidget ();
450 closeWidget ();
451 }
452 void closeWidget () {
453 if (!isEnabled()) return;
454 Event event = new Event ();
455 sendEvent (SWT.Close, event);
456 if (event.doit && !isDisposed ()) dispose ();
457 }
458
459 public Rectangle computeTrim (int x, int y, int width, int height) {
460 checkWidget();
461 Rectangle trim = super.computeTrim (x, y, width, height);
462 int trimWidth = trimWidth (), trimHeight = trimHeight ();
463 trim.x -= trimWidth / 2; trim.y -= trimHeight - (trimWidth / 2);
464 trim.width += trimWidth; trim.height += trimHeight;
465 if (menuBar != null) {
466 int menuBarHeight = OS.GTK_WIDGET_HEIGHT (menuBar.handle);
467 trim.y -= menuBarHeight;
468 trim.height += menuBarHeight;
469 }
470 return trim;
471 }
472
473 void createHandle (int index) {
474 state |= HANDLE | CANVAS;
475 if (handle == 0) {
476 int type = OS.GTK_WINDOW_TOPLEVEL;
477 if ((style & SWT.ON_TOP) != 0) type = OS.GTK_WINDOW_POPUP;
478 shellHandle = OS.gtk_window_new (type);
479 } else {
480 shellHandle = OS.gtk_plug_new (handle);
481 }
482 if (shellHandle == 0) SWT.error (SWT.ERROR_NO_HANDLES);
483 if (parent != null) {
484 OS.gtk_window_set_transient_for (shellHandle, parent.topHandle ());
485 OS.gtk_window_set_destroy_with_parent (shellHandle, true);
486 int orientations = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
487 if (!((style & ~orientations) == SWT.NONE || (style & (SWT.NO_TRIM | SWT.ON_TOP)) != 0)) {
488 OS.gtk_window_set_type_hint (shellHandle, OS.GDK_WINDOW_TYPE_HINT_DIALOG);
489 }
490 }
491 /*
492 * Feature in GTK. The window size must be set when the window
493 * is created or it will not be allowed to be resized smaller that the
494 * initial size by the user. The fix is to set the size to zero.
495 */
496 if ((style & SWT.RESIZE) != 0) {
497 OS.gtk_widget_set_size_request (shellHandle, 0, 0);
498 OS.gtk_window_set_resizable (shellHandle, true);
499 } else {
500 OS.gtk_window_set_resizable (shellHandle, false);
501 }
502 createHandle (index, shellHandle, true);
503 OS.gtk_widget_realize (shellHandle);
504 long /*int*/ window = OS.GTK_WIDGET_WINDOW (shellHandle);
505 int decorations = 0;
506 if ((style & SWT.NO_TRIM) == 0) {
507 if ((style & SWT.MIN) != 0) decorations |= OS.GDK_DECOR_MINIMIZE;
508 if ((style & SWT.MAX) != 0) decorations |= OS.GDK_DECOR_MAXIMIZE;
509 if ((style & SWT.RESIZE) != 0) decorations |= OS.GDK_DECOR_RESIZEH;
510 if ((style & SWT.BORDER) != 0) decorations |= OS.GDK_DECOR_BORDER;
511 if ((style & SWT.MENU) != 0) decorations |= OS.GDK_DECOR_MENU;
512 if ((style & SWT.TITLE) != 0) decorations |= OS.GDK_DECOR_TITLE;
513 /*
514 * Feature in GTK. Under some Window Managers (Sawmill), in order
515 * to get any border at all from the window manager it is necessary to
516 * set GDK_DECOR_BORDER. The fix is to force these bits when any
517 * kind of border is requested.
518 */
519 if ((style & SWT.RESIZE) != 0) decorations |= OS.GDK_DECOR_BORDER;
520 }
521 OS.gdk_window_set_decorations (window, decorations);
522 OS.gtk_window_set_title (shellHandle, new byte [1]);
523 if ((style & SWT.ON_TOP) != 0) {
524 OS.gdk_window_set_override_redirect (window, true);
525 }
526 if ((style & (SWT.NO_TRIM | SWT.BORDER | SWT.RESIZE)) == 0) {
527 OS.gtk_container_set_border_width (shellHandle, 1);
528 GdkColor color = new GdkColor ();
529 OS.gtk_style_get_black (OS.gtk_widget_get_style (shellHandle), color);
530 OS.gtk_widget_modify_bg (shellHandle, OS.GTK_STATE_NORMAL, color);
531 }
532 int bits = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
533 boolean modal = (style & bits) != 0;
534 //TEMPORARY CODE
535 if ((style & SWT.ON_TOP) == 0) modal |= (parent != null && (parent.style & bits) != 0);
536 OS.gtk_window_set_modal (shellHandle, modal);
537 }
538
539 boolean hasBorder () {
540 return false;
541 }
542
543 void hookEvents () {
544 super.hookEvents ();
545 long /*int*/ shellMapProc = display.shellMapProc;
546 long /*int*/ windowProc3 = display.windowProc3;
547 OS.g_signal_connect (shellHandle, OS.map_event, windowProc3, MAP_EVENT);
548 OS.g_signal_connect (shellHandle, OS.unmap_event, windowProc3, UNMAP_EVENT);
549 OS.g_signal_connect (shellHandle, OS.window_state_event, windowProc3, WINDOW_STATE_EVENT);
550 OS.g_signal_connect (shellHandle, OS.size_allocate, windowProc3, SIZE_ALLOCATE);
551 OS.g_signal_connect (shellHandle, OS.configure_event, windowProc3, CONFIGURE_EVENT);
552 OS.g_signal_connect (shellHandle, OS.delete_event, windowProc3, DELETE_EVENT);
553 OS.g_signal_connect (shellHandle, OS.focus_in_event, windowProc3, FOCUS_IN_EVENT);
554 OS.g_signal_connect (shellHandle, OS.focus_out_event, windowProc3, FOCUS_OUT_EVENT);
555 OS.g_signal_connect (shellHandle, OS.map_event, shellMapProc, 0);
556 OS.g_signal_connect (shellHandle, OS.enter_notify_event, windowProc3, ENTER_NOTIFY_EVENT);
557 if (OS.GDK_WINDOWING_X11 ()) {
558 long /*int*/ window = OS.GTK_WIDGET_WINDOW (shellHandle);
559 OS.gdk_window_add_filter (window, display.filterProc, shellHandle);
560 }
561 }
562
563 public boolean isEnabled () {
564 checkWidget ();
565 return getEnabled ();
566 }
567
568 public boolean isVisible () {
569 checkWidget();
570 return getVisible ();
571 }
572
573 void register () {
574 super.register ();
575 display.addWidget (shellHandle, this);
576 }
577
578 void releaseChild () {
579 /* Do nothing */
580 }
581
582 long /*int*/ topHandle () {
583 return shellHandle;
584 }
585
586 long /*int*/ filterProc (long /*int*/ xEvent, long /*int*/ gdkEvent, long /*int*/ data) {
587 /*
588 * Bug in GTK. When a shell that has no window manager trimmings
589 * is given focus, GTK gets stuck in "focus follows pointer" mode when
590 * the pointer is within the shell and its parent when the shell is disposed.
591 * The fix is to modify the X events that cause this to happen.
592 */
593 XFocusChangeEvent focusEvent = new XFocusChangeEvent ();
594 OS.memmove (focusEvent, xEvent, 4);
595 switch (focusEvent.type) {
596 case OS.FocusIn: {
597 OS.memmove (focusEvent, xEvent, XFocusChangeEvent.sizeof);
598 if (focusEvent.detail == OS.NotifyPointer) {
599 focusEvent.detail = OS.NotifyNonlinear;
600 OS.memmove (xEvent, focusEvent, XFocusChangeEvent.sizeof);
601 }
602 break;
603 }
604 case OS.EnterNotify: {
605 XCrossingEvent crossingEvent = new XCrossingEvent ();
606 OS.memmove (crossingEvent, xEvent, XCrossingEvent.sizeof);
607 if (crossingEvent.focus) {
608 crossingEvent.focus = false;
609 OS.memmove (xEvent, crossingEvent, XCrossingEvent.sizeof);
610 }
611 break;
612 }
613 }
614 return 0;
615 }
616
617 void fixShell (Shell newShell, Control control) {
618 if (this == newShell) return;
619 if (control == lastActive) setActiveControl (null);
620 if (tooltipsHandle != 0) {
621 setToolTipText (control.handle, null);
622 }
623 newShell.setToolTipText (control.handle, control.toolTipText);
624 }
625
626 public Point getLocation () {
627 checkWidget ();
628 int [] x = new int [1], y = new int [1];
629 OS.gtk_window_get_position (shellHandle, x,y);
630 return new Point (x [0], y [0]);
631 }
632
633 public Point getSize () {
634 checkWidget ();
635 int width = OS.GTK_WIDGET_WIDTH (scrolledHandle);
636 int height = OS.GTK_WIDGET_HEIGHT (scrolledHandle);
637 if (menuBar != null) {
638 long /*int*/ barHandle = menuBar.handle;
639 height += OS.GTK_WIDGET_HEIGHT (barHandle);
640 }
641 return new Point (width + trimWidth (), height + trimHeight ());
642 }
643
644 /**
645 * Returns the region that defines the shape of the shell,
646 * or null if the shell has the default shape.
647 *
648 * @return the region that defines the shape of the shell (or null)
649 *
650 * @exception SWTException <ul>
651 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
652 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
653 * </ul>
654 *
655 * @since 3.0
656 *
657 */
658 public Region getRegion () {
659 checkWidget ();
660 return region;
661 }
662
663 /**
664 * Returns the receiver's input method editor mode. This
665 * will be the result of bitwise OR'ing together one or
666 * more of the following constants defined in class
667 * <code>SWT</code>:
668 * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>,
669 * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
670 *
671 * @return the IME mode
672 *
673 * @exception SWTException <ul>
674 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
675 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
676 * </ul>
677 *
678 * @see SWT
679 */
680 public int getImeInputMode () {
681 checkWidget();
682 return SWT.NONE;
683 }
684
685 Shell _getShell () {
686 return this;
687 }
688 /**
689 * Returns an array containing all shells which are
690 * descendents of the receiver.
691 * <p>
692 * @return the dialog shells
693 *
694 * @exception SWTException <ul>
695 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
696 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
697 * </ul>
698 */
699 public Shell [] getShells () {
700 checkWidget();
701 int count = 0;
702 Shell [] shells = display.getShells ();
703 for (int i=0; i<shells.length; i++) {
704 Control shell = shells [i];
705 do {
706 shell = shell.getParent ();
707 } while (shell != null && shell != this);
708 if (shell == this) count++;
709 }
710 int index = 0;
711 Shell [] result = new Shell [count];
712 for (int i=0; i<shells.length; i++) {
713 Control shell = shells [i];
714 do {
715 shell = shell.getParent ();
716 } while (shell != null && shell != this);
717 if (shell == this) {
718 result [index++] = shells [i];
719 }
720 }
721 return result;
722 }
723
724 long /*int*/ gtk_configure_event (long /*int*/ widget, long /*int*/ event) {
725 int [] x = new int [1], y = new int [1];
726 OS.gtk_window_get_position (shellHandle, x, y);
727 if (oldX != x [0] || oldY != y [0]) {
728 oldX = x [0];
729 oldY = y [0];
730 sendEvent (SWT.Move);
731 }
732 return 0;
733 }
734
735 long /*int*/ gtk_delete_event (long /*int*/ widget, long /*int*/ event) {
736 closeWidget ();
737 return 1;
738 }
739
740 long /*int*/ gtk_enter_notify_event (long /*int*/ widget, long /*int*/ event) {
741 if (widget != shellHandle) {
742 return super.gtk_enter_notify_event (widget, event);
743 }
744 return 0;
745 }
746
747 long /*int*/ gtk_focus (long /*int*/ widget, long /*int*/ directionType) {
748 switch ((int)/*64*/directionType) {
749 case OS.GTK_DIR_TAB_FORWARD:
750 case OS.GTK_DIR_TAB_BACKWARD:
751 Control control = display.getFocusControl ();
752 if (control != null) {
753 if ((control.state & CANVAS) != 0 && (control.style & SWT.EMBEDDED) != 0) {
754 int traversal = directionType == OS.GTK_DIR_TAB_FORWARD ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS;
755 control.traverse (traversal);
756 return 1;
757 }
758 }
759 break;
760 }
761 return super.gtk_focus (widget, directionType);
762 }
763
764 long /*int*/ gtk_focus_in_event (long /*int*/ widget, long /*int*/ event) {
765 if (widget != shellHandle) {
766 return super.gtk_focus_in_event (widget, event);
767 }
768 if (tooltipsHandle != 0) OS.gtk_tooltips_enable (tooltipsHandle);
769 hasFocus = true;
770 sendEvent (SWT.Activate);
771 return 0;
772 }
773
774 long /*int*/ gtk_focus_out_event (long /*int*/ widget, long /*int*/ event) {
775 if (widget != shellHandle) {
776 return super.gtk_focus_out_event (widget, event);
777 }
778 if (tooltipsHandle != 0) OS.gtk_tooltips_disable (tooltipsHandle);
779 hasFocus = false;
780 sendEvent (SWT.Deactivate);
781 return 0;
782 }
783
784 long /*int*/ gtk_map_event (long /*int*/ widget, long /*int*/ event) {
785 minimized = false;
786 sendEvent (SWT.Deiconify);
787 return 0;
788 }
789
790 long /*int*/ gtk_size_allocate (long /*int*/ widget, long /*int*/ allocation) {
791 int [] width = new int [1], height = new int [1];
792 OS.gtk_window_get_size (shellHandle, width, height);
793 if (oldWidth != width [0] || oldHeight != height [0]) {
794 oldWidth = width [0];
795 oldHeight = height [0];
796 resizeBounds (width [0], height [0], true);
797 }
798 return 0;
799 }
800
801 long /*int*/ gtk_unmap_event (long /*int*/ widget, long /*int*/ event) {
802 minimized = true;
803 sendEvent (SWT.Iconify);
804 return 0;
805 }
806
807 long /*int*/ gtk_window_state_event (long /*int*/ widget, long /*int*/ event) {
808 GdkEventWindowState gdkEvent = new GdkEventWindowState ();
809 OS.memmove (gdkEvent, event, GdkEventWindowState.sizeof);
810 minimized = (gdkEvent.new_window_state & OS.GDK_WINDOW_STATE_ICONIFIED) != 0;
811 maximized = (gdkEvent.new_window_state & OS.GDK_WINDOW_STATE_MAXIMIZED) != 0;
812 return 0;
813 }
814
815 /**
816 * Moves the receiver to the top of the drawing order for
817 * the display on which it was created (so that all other
818 * shells on that display, which are not the receiver's
819 * children will be drawn behind it), marks it visible,
820 * sets the focus and asks the window manager to make the
821 * shell active.
822 *
823 * @exception SWTException <ul>
824 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
825 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
826 * </ul>
827 *
828 * @see Control#moveAbove
829 * @see Control#setFocus
830 * @see Control#setVisible
831 * @see Display#getActiveShell
832 * @see Decorations#setDefaultButton
833 * @see Shell#setActive
834 * @see Shell#forceActive
835 */
836 public void open () {
837 checkWidget ();
838 setVisible (true);
839 bringToTop (false);
840 if (!restoreFocus ()) {
841 long /*int*/ focusHandle = OS.gtk_window_get_focus (shellHandle);
842 if (focusHandle == 0 || focusHandle == handle) {
843 if (!traverseGroup (true)) {
844 focusHandle = OS.gtk_window_get_focus (shellHandle);
845 if (focusHandle == 0) OS.gtk_widget_grab_focus (focusHandle ());
846 }
847 }
848 }
849 }
850
851 /**
852 * Removes the listener from the collection of listeners who will
853 * be notified when operations are performed on the receiver.
854 *
855 * @param listener the listener which should no longer be notified
856 *
857 * @exception IllegalArgumentException <ul>
858 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
859 * </ul>
860 * @exception SWTException <ul>
861 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
862 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
863 * </ul>
864 *
865 * @see ShellListener
866 * @see #addShellListener
867 */
868 public void removeShellListener (ShellListener listener) {
869 checkWidget();
870 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
871 if (eventTable == null) return;
872 eventTable.unhook (SWT.Close, listener);
873 eventTable.unhook (SWT.Iconify,listener);
874 eventTable.unhook (SWT.Deiconify,listener);
875 eventTable.unhook (SWT.Activate, listener);
876 eventTable.unhook (SWT.Deactivate, listener);
877 }
878
879 /**
880 * Moves the receiver to the top of the drawing order for
881 * the display on which it was created (so that all other
882 * shells on that display, which are not the receiver's
883 * children will be drawn behind it) and asks the window
884 * manager to make the shell active.
885 *
886 * @exception SWTException <ul>
887 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
888 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
889 * </ul>
890 *
891 * @since 2.0
892 * @see Control#moveAbove
893 * @see Control#setFocus
894 * @see Control#setVisible
895 * @see Display#getActiveShell
896 * @see Decorations#setDefaultButton
897 * @see Shell#open
898 * @see Shell#setActive
899 */
900 public void setActive () {
901 checkWidget ();
902 bringToTop (false);
903 }
904
905 void setActiveControl (Control control) {
906 if (control != null && control.isDisposed ()) control = null;
907 if (lastActive != null && lastActive.isDisposed ()) lastActive = null;
908 if (lastActive == control) return;
909
910 /*
911 * Compute the list of controls to be activated and
912 * deactivated by finding the first common parent
913 * control.
914 */
915 Control [] activate = (control == null) ? new Control[0] : control.getPath ();
916 Control [] deactivate = (lastActive == null) ? new Control[0] : lastActive.getPath ();
917 lastActive = control;
918 int index = 0, length = Math.min (activate.length, deactivate.length);
919 while (index < length) {
920 if (activate [index] != deactivate [index]) break;
921 index++;
922 }
923
924 /*
925 * It is possible (but unlikely), that application
926 * code could have destroyed some of the widgets. If
927 * this happens, keep processing those widgets that
928 * are not disposed.
929 */
930 for (int i=deactivate.length-1; i>=index; --i) {
931 if (!deactivate [i].isDisposed ()) {
932 deactivate [i].sendEvent (SWT.Deactivate);
933 }
934 }
935 for (int i=activate.length-1; i>=index; --i) {
936 if (!activate [i].isDisposed ()) {
937 activate [i].sendEvent (SWT.Activate);
938 }
939 }
940 }
941
942 void resizeBounds (int width, int height, boolean notify) {
943 if (redrawWindow != 0) {
944 OS.gdk_window_resize (redrawWindow, width, height);
945 }
946 if (enableWindow != 0) {
947 OS.gdk_window_resize (enableWindow, width, height);
948 }
949 int border = OS.gtk_container_get_border_width (shellHandle);
950 int menuHeight = 0;
951 if (menuBar != null) {
952 long /*int*/ menuHandle = menuBar.handle;
953 OS.gtk_widget_set_size_request (menuHandle, -1, -1);
954 GtkRequisition requisition = new GtkRequisition ();
955 OS.gtk_widget_size_request (menuHandle, requisition);
956 menuHeight = requisition.height;
957 OS.gtk_widget_set_size_request (menuHandle, width - (border * 2), menuHeight);
958 height = Math.max (1, height - menuHeight);
959 }
960 OS.gtk_fixed_move (fixedHandle, scrolledHandle, 0, menuHeight);
961 OS.gtk_widget_set_size_request (scrolledHandle, width - (border * 2), height - (border * 2));
962 OS.gtk_container_resize_children (fixedHandle);
963 if (notify) {
964 sendEvent (SWT.Resize);
965 if (layout != null) layout.layout (this, false);
966 }
967 }
968
969 boolean setBounds (int x, int y, int width, int height, boolean move, boolean resize) {
970 if (move) {
971 int [] x_pos = new int [1], y_pos = new int [1];
972 OS.gtk_window_get_position (shellHandle, x_pos, y_pos);
973 OS.gtk_window_move (shellHandle, x, y);
974 if (x_pos [0] != x || y_pos [0] != y) {
975 oldX = x;
976 oldY = y;
977 sendEvent(SWT.Move);
978 }
979 }
980 if (resize) {
981 int [] w = new int [1], h = new int [1];
982 OS.gtk_window_get_size (shellHandle, w, h);
983 width = Math.max (1, width - trimWidth ());
984 height = Math.max (1, height - trimHeight ());
985 OS.gtk_window_resize (shellHandle, width, height);
986 boolean changed = width != oldWidth || height != oldHeight;
987 if (changed) {
988 oldWidth = width;
989 oldHeight = height;
990 }
991 resizeBounds (width, height, changed);
992 }
993 return move || resize;
994 }
995
996 void setCursor (long /*int*/ cursor) {
997 if (enableWindow != 0) {
998 OS.gdk_window_set_cursor (enableWindow, cursor);
999 OS.gdk_flush ();
1000 }
1001 super.setCursor (cursor);
1002}
1003
1004public void setEnabled (boolean enabled) {
1005 checkWidget();
1006 if (((state & DISABLED) == 0) == enabled) return;
1007 Control control = null;
1008 boolean fixFocus = false;
1009 if (!enabled) {
1010 control = display.getFocusControl ();
1011 fixFocus = isFocusAncestor (control);
1012 }
1013 if (enabled) {
1014 state &= ~DISABLED;
1015 } else {
1016 state |= DISABLED;
1017 }
1018 enableWidget (enabled);
1019 if (enabled) {
1020 if (enableWindow != 0) {
1021 OS.gdk_window_set_user_data (enableWindow, 0);
1022 OS.gdk_window_destroy (enableWindow);
1023 enableWindow = 0;
1024 }
1025 } else {
1026 long /*int*/ parentHandle = shellHandle;
1027 OS.gtk_widget_realize (parentHandle);
1028 long /*int*/ window = OS.GTK_WIDGET_WINDOW (parentHandle);
1029 Rectangle rect = getBounds ();
1030 GdkWindowAttr attributes = new GdkWindowAttr ();
1031 attributes.width = rect.width;
1032 attributes.height = rect.height;
1033 attributes.event_mask = (0xFFFFFFFF & ~OS.ExposureMask);
1034 attributes.wclass = OS.GDK_INPUT_ONLY;
1035 attributes.window_type = OS.GDK_WINDOW_CHILD;
1036 enableWindow = OS.gdk_window_new (window, attributes, 0);
1037 if (enableWindow != 0) {
1038 if (cursor != null) {
1039 OS.gdk_window_set_cursor (enableWindow, cursor.handle);
1040 OS.gdk_flush ();
1041 }
1042 OS.gdk_window_set_user_data (enableWindow, parentHandle);
1043 OS.gdk_window_raise (enableWindow);
1044 OS.gdk_window_show (enableWindow);
1045 }
1046 }
1047 if (fixFocus) fixFocus (control);
1048 if (enabled && hasFocus) {
1049 if (!restoreFocus ()) traverseGroup (false);
1050 }
1051}
1052
1053/**
1054 * Sets the input method editor mode to the argument which
1055 * should be the result of bitwise OR'ing together one or more
1056 * of the following constants defined in class <code>SWT</code>:
1057 * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>,
1058 * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
1059 *
1060 * @param mode the new IME mode
1061 *
1062 * @exception SWTException <ul>
1063 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1064 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1065 * </ul>
1066 *
1067 * @see SWT
1068 */
1069public void setImeInputMode (int mode) {
1070 checkWidget();
1071}
1072
1073void setInitialSize () {
1074 Monitor monitor = getMonitor ();
1075 Rectangle rect = monitor.getClientArea ();
1076 int width = rect.width * 5 / 8;
1077 int height = rect.height * 5 / 8;
1078 OS.gtk_widget_set_size_request (scrolledHandle, width, height);
1079 OS.gtk_window_resize (shellHandle, width, height);
1080 OS.gtk_container_resize_children (fixedHandle);
1081}
1082
1083public void setMaximized (boolean maximized) {
1084 checkWidget();
1085 super.setMaximized (maximized);
1086 if (maximized) {
1087 OS.gtk_window_maximize (shellHandle);
1088 } else {
1089 OS.gtk_window_unmaximize (shellHandle);
1090 }
1091}
1092
1093public void setMenuBar (Menu menu) {
1094 checkWidget();
1095 if (menuBar == menu) return;
1096 boolean both = menu != null && menuBar != null;
1097 if (menu != null) {
1098 if ((menu.style & SWT.BAR) == 0) error (SWT.ERROR_MENU_NOT_BAR);
1099 if (menu.parent != this) error (SWT.ERROR_INVALID_PARENT);
1100 }
1101 if (menuBar != null) {
1102 long /*int*/ menuHandle = menuBar.handle;
1103 OS.gtk_widget_hide (menuHandle);
1104 destroyAccelGroup ();
1105 }
1106 menuBar = menu;
1107 if (menuBar != null) {
1108 long /*int*/ menuHandle = menu.handle;
1109 OS.gtk_widget_show (menuHandle);
1110 createAccelGroup ();
1111 menuBar.addAccelerators (accelGroup);
1112 }
1113 int [] width = new int [1], height = new int [1];
1114 OS.gtk_window_get_size (shellHandle, width, height);
1115 resizeBounds (width [0], height [0], !both);
1116}
1117
1118public void setMinimized (boolean minimized) {
1119 checkWidget();
1120 if (this.minimized == minimized) return;
1121 super.setMinimized (minimized);
1122 if (minimized) {
1123 OS.gtk_window_iconify (shellHandle);
1124 } else {
1125 OS.gtk_window_deiconify (shellHandle);
1126 bringToTop (false);
1127 }
1128}
1129
1130/**
1131 * Sets the shape of the shell to the region specified
1132 * by the argument. When the argument is null, the
1133 * default shape of the shell is restored. The shell
1134 * must be created with the style SWT.NO_TRIM in order
1135 * to specify a region.
1136 *
1137 * @param region the region that defines the shape of the shell (or null)
1138 *
1139 * @exception IllegalArgumentException <ul>
1140 * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
1141 * </ul>
1142 * @exception SWTException <ul>
1143 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1144 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1145 * </ul>
1146 *
1147 * @since 3.0
1148 *
1149 */
1150public void setRegion (Region region) {
1151 checkWidget ();
1152 if ((style & SWT.NO_TRIM) == 0) return;
1153 if (region != null && region.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
1154 long /*int*/ window = OS.GTK_WIDGET_WINDOW (shellHandle);
1155 long /*int*/ shape_region = (region == null) ? 0 : region.handle;
1156 OS.gdk_window_shape_combine_region (window, shape_region, 0, 0);
1157 this.region = region;
1158}
1159
1160public void setText (String string) {
1161 super.setText (string);
1162
1163 /*
1164 * GTK bug 82013. For some reason, if the title string
1165 * is less that 7 bytes long and is not terminated by
1166 * a space, some window managers occasionally draw
1167 * garbage after the last character in the title.
1168 * The fix is to pad the title.
1169 */
1170 int length = string.length ();
1171 char [] chars = new char [Math.max (6, length) + 1];
1172 string.getChars (0, length , chars, 0);
1173 for (int i=length; i<chars.length; i++) chars [i] = ' ';
1174 byte [] buffer = Converter.wcsToMbcs (null, chars, true);
1175 OS.gtk_window_set_title (shellHandle, buffer);
1176}
1177
1178public void setVisible (boolean visible) {
1179 checkWidget();
1180 if ((OS.GTK_WIDGET_MAPPED (shellHandle) == visible)) return;
1181 if (visible) {
1182 sendEvent (SWT.Show);
1183 if (isDisposed ()) return;
1184
1185 /*
1186 * In order to ensure that the shell is visible
1187 * and fully painted, dispatch events such as
1188 * GDK_MAP and GDK_CONFIGURE, until the GDK_MAP
1189 * event for the shell is received.
1190 */
1191 mapped = false;
1192 OS.gtk_widget_show (shellHandle);
1193 display.dispatchEvents = new int [] {
1194 OS.GDK_EXPOSE,
1195 OS.GDK_CONFIGURE,
1196 OS.GDK_MAP,
1197 OS.GDK_UNMAP,
1198 OS.GDK_NO_EXPOSE,
1199 };
1200 display.putGdkEvents();
1201 while (!isDisposed () && !mapped) {
1202 OS.gtk_main_iteration ();
1203 }
1204 display.dispatchEvents = null;
1205 if (isDisposed ()) return;
1206 update (true);
1207 if (isDisposed ()) return;
1208 adjustTrim ();
1209
1210 int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
1211 if ((style & mask) != 0) {
1212 OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME);
1213 }
1214 } else {
1215 OS.gtk_widget_hide (shellHandle);
1216 sendEvent (SWT.Hide);
1217 }
1218}
1219
1220void setZOrder (Control sibling, boolean above) {
1221 setZOrder (sibling, above, false);
1222}
1223
1224long /*int*/ shellMapProc (long /*int*/ handle, long /*int*/ arg0, long /*int*/ user_data) {
1225 mapped = true;
1226 display.dispatchEvents = null;
1227 return 0;
1228}
1229
1230boolean traverseEscape () {
1231 if (parent == null) return false;
1232 if (!isVisible () || !isEnabled ()) return false;
1233 close ();
1234 return true;
1235}
1236int trimHeight () {
1237 if ((style & SWT.NO_TRIM) != 0) return 0;
1238 boolean hasTitle = false, hasResize = false, hasBorder = false;
1239 hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) != 0;
1240 hasResize = (style & SWT.RESIZE) != 0;
1241 hasBorder = (style & SWT.BORDER) != 0;
1242 if (hasTitle) {
1243 if (hasResize) return display.titleResizeTrimHeight;
1244 if (hasBorder) return display.titleBorderTrimHeight;
1245 return display.titleTrimHeight;
1246 }
1247 if (hasResize) return display.resizeTrimHeight;
1248 if (hasBorder) return display.borderTrimHeight;
1249 return 0;
1250}
1251
1252int trimWidth () {
1253 if ((style & SWT.NO_TRIM) != 0) return 0;
1254 boolean hasTitle = false, hasResize = false, hasBorder = false;
1255 hasTitle = (style & (SWT.MIN | SWT.MAX | SWT.TITLE | SWT.MENU)) != 0;
1256 hasResize = (style & SWT.RESIZE) != 0;
1257 hasBorder = (style & SWT.BORDER) != 0;
1258 if (hasTitle) {
1259 if (hasResize) return display.titleResizeTrimWidth;
1260 if (hasBorder) return display.titleBorderTrimWidth;
1261 return display.titleTrimWidth;
1262 }
1263 if (hasResize) return display.resizeTrimWidth;
1264 if (hasBorder) return display.borderTrimWidth;
1265 return 0;
1266}
1267
1268void deregister () {
1269 super.deregister ();
1270 display.removeWidget (shellHandle);
1271}
1272
1273public void dispose () {
1274 /*
1275 * Note: It is valid to attempt to dispose a widget
1276 * more than once. If this happens, fail silently.
1277 */
1278 if (isDisposed()) return;
1279
1280 /*
1281 * Feature in GTK. When the active shell is disposed,
1282 * GTK assigns focus temporarily to the root window
1283 * unless it has previously been told to do otherwise.
1284 * The fix is to make the parent be the active top level
1285 * shell when the child shell is disposed.
1286 */
1287 OS.gtk_widget_hide (shellHandle);
1288 if (parent != null) {
1289 Shell activeShell = display.getActiveShell ();
1290 if (activeShell == this) {
1291 Shell shell = parent.getShell ();
1292 shell.bringToTop (false);
1293 }
1294 }
1295 super.dispose ();
1296}
1297
1298/**
1299 * Moves the receiver to the top of the drawing order for
1300 * the display on which it was created (so that all other
1301 * shells on that display, which are not the receiver's
1302 * children will be drawn behind it) and forces the window
1303 * manager to make the shell active.
1304 *
1305 * @exception SWTException <ul>
1306 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1307 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1308 * </ul>
1309 *
1310 * @since 2.0
1311 * @see Control#moveAbove
1312 * @see Control#setFocus
1313 * @see Control#setVisible
1314 * @see Display#getActiveShell
1315 * @see Decorations#setDefaultButton
1316 * @see Shell#open
1317 * @see Shell#setActive
1318 */
1319public void forceActive () {
1320 checkWidget ();
1321 bringToTop (true);
1322}
1323
1324public Rectangle getBounds () {
1325 checkWidget ();
1326 int [] x = new int [1], y = new int [1];
1327 OS.gtk_window_get_position (shellHandle, x, y);
1328 int width = OS.GTK_WIDGET_WIDTH (scrolledHandle);
1329 int height = OS.GTK_WIDGET_HEIGHT (scrolledHandle);
1330 if (menuBar != null) {
1331 long /*int*/ barHandle = menuBar.handle;
1332 height += OS.GTK_WIDGET_HEIGHT (barHandle);
1333 }
1334 return new Rectangle (x [0], y [0], width + trimWidth (), height + trimHeight ());
1335}
1336
1337void releaseHandle () {
1338 super.releaseHandle ();
1339 shellHandle = 0;
1340}
1341
1342void releaseShells () {
1343 Shell [] shells = getShells ();
1344 for (int i=0; i<shells.length; i++) {
1345 Shell shell = shells [i];
1346 if (!shell.isDisposed ()) shell.releaseResources ();
1347 }
1348}
1349
1350void releaseWidget () {
1351 releaseShells ();
1352 destroyAccelGroup ();
1353 super.releaseWidget ();
1354 if (tooltipsHandle != 0) OS.g_object_unref (tooltipsHandle);
1355 tooltipsHandle = 0;
1356 region = null;
1357 lastActive = null;
1358}
1359
1360void setToolTipText (long /*int*/ widget, String string) {
1361 byte [] buffer = null;
1362 if (string != null && string.length () > 0) {
1363 buffer = Converter.wcsToMbcs (null, string, true);
1364 }
1365 if (tooltipsHandle == 0) {
1366 tooltipsHandle = OS.gtk_tooltips_new ();
1367 if (tooltipsHandle == 0) error (SWT.ERROR_NO_HANDLES);
1368 OS.g_object_ref (tooltipsHandle);
1369 OS.gtk_object_sink (tooltipsHandle);
1370 }
1371 OS.gtk_tooltips_set_tip (tooltipsHandle, widget, buffer, null);
1372}
1373}