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 }