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.Composite; 14 15 import org.eclipse.swt.widgets.Control; 16 import org.eclipse.swt.widgets.Scrollable; 17 import org.eclipse.swt.widgets.Layout; 18 import org.eclipse.swt.widgets.Decorations; 19 import org.eclipse.swt.widgets.ScrollBar; 20 import org.eclipse.swt.widgets.Shell; 21 import org.eclipse.swt.widgets.Menu; 22 import org.eclipse.swt.widgets.Event; 23 import org.eclipse.swt.widgets.Widget; 24 import org.eclipse.swt.widgets.Display; 25 import org.eclipse.swt.graphics.GCData; 26 27 import org.eclipse.swt.internal.gtk.OS; 28 import org.eclipse.swt.graphics.GC; 29 import org.eclipse.swt.SWT; 30 import org.eclipse.swt.graphics.Region; 31 import org.eclipse.swt.internal.cairo.Cairo : Cairo; 32 import org.eclipse.swt.internal.gtk.OS; 33 import org.eclipse.swt.graphics.Rectangle; 34 import java.lang.all; 35 36 /** 37 * Instances of this class are controls which are capable 38 * of containing other controls. 39 * <dl> 40 * <dt><b>Styles:</b></dt> 41 * <dd>NO_BACKGROUND, NO_FOCUS, NO_MERGE_PAINTS, NO_REDRAW_RESIZE, NO_RADIO_GROUP, EMBEDDED, DOUBLE_BUFFERED</dd> 42 * <dt><b>Events:</b></dt> 43 * <dd>(none)</dd> 44 * </dl> 45 * <p> 46 * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, <code>NO_MERGE_PAINTS</code>, 47 * and <code>NO_REDRAW_RESIZE</code> styles are intended for use with <code>Canvas</code>. 48 * They can be used with <code>Composite</code> if you are drawing your own, but their 49 * behavior is undefined if they are used with subclasses of <code>Composite</code> other 50 * than <code>Canvas</code>. 51 * </p><p> 52 * Note: The <code>CENTER</code> style, although undefined for composites, has the 53 * same value as <code>EMBEDDED</code> (which is used to embed widgets from other 54 * widget toolkits into SWT). On some operating systems (GTK, Motif), this may cause 55 * the children of this composite to be obscured. The <code>EMBEDDED</code> style 56 * is for use by other widget toolkits and should normally never be used. 57 * </p><p> 58 * This class may be subclassed by custom control implementors 59 * who are building controls that are constructed from aggregates 60 * of other controls. 61 * </p> 62 * 63 * @see Canvas 64 * @see <a href="http://www.eclipse.org/swt/snippets/#composite">Composite snippets</a> 65 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 66 */ 67 public class Composite : Scrollable { 68 69 alias Scrollable.computeSize computeSize; 70 alias Scrollable.fixStyle fixStyle; 71 alias Scrollable.forceFocus forceFocus; 72 alias Scrollable.gtk_button_press_event gtk_button_press_event; 73 alias Scrollable.moveAbove moveAbove; 74 alias Scrollable.moveBelow moveBelow; 75 alias Scrollable.setBounds setBounds; 76 alias Scrollable.translateMnemonic translateMnemonic; 77 alias Scrollable.translateTraversal translateTraversal; 78 79 public size_t embeddedHandle; 80 GtkIMContext* imHandle_; 81 GtkWidget* socketHandle; 82 Layout layout_; 83 Control[] tabList; 84 int layoutCount, backgroundMode; 85 86 static const String NO_INPUT_METHOD = "org.eclipse.swt.internal.gtk.noInputMethod"; //$NON-NLS-1$ 87 88 this () { 89 /* Do nothing */ 90 } 91 92 /** 93 * Constructs a new instance of this class given its parent 94 * and a style value describing its behavior and appearance. 95 * <p> 96 * The style value is either one of the style constants defined in 97 * class <code>SWT</code> which is applicable to instances of this 98 * class, or must be built by <em>bitwise OR</em>'ing together 99 * (that is, using the <code>int</code> "|" operator) two or more 100 * of those <code>SWT</code> style constants. The class description 101 * lists the style constants that are applicable to the class. 102 * Style bits are also inherited from superclasses. 103 * </p> 104 * 105 * @param parent a widget which will be the parent of the new instance (cannot be null) 106 * @param style the style of widget to construct 107 * 108 * @exception IllegalArgumentException <ul> 109 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 110 * </ul> 111 * @exception SWTException <ul> 112 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> 113 * </ul> 114 * 115 * @see SWT#NO_BACKGROUND 116 * @see SWT#NO_FOCUS 117 * @see SWT#NO_MERGE_PAINTS 118 * @see SWT#NO_REDRAW_RESIZE 119 * @see SWT#NO_RADIO_GROUP 120 * @see Widget#getStyle 121 */ 122 public this (Composite parent, int style) { 123 super (parent, checkStyle (style)); 124 } 125 126 static int checkStyle (int style) { 127 style &= ~SWT.TRANSPARENT; 128 return style; 129 } 130 131 Control [] _getChildren () { 132 auto parentHandle = parentingHandle (); 133 auto list = OS.gtk_container_get_children (cast(GtkContainer*)parentHandle); 134 if (list is null) return new Control [0]; 135 int count = OS.g_list_length (list); 136 Control [] children = new Control [count]; 137 int i = 0; 138 auto temp = list; 139 while (temp !is null) { 140 auto handle = cast(GtkWidget*)OS.g_list_data (temp); 141 if (handle !is null) { 142 Widget widget = display.getWidget (handle); 143 if (widget !is null && widget !is this) { 144 if (auto c = cast(Control)widget) { 145 children [i++] = c; 146 } 147 } 148 } 149 temp = cast(GList*)OS.g_list_next (temp); 150 } 151 OS.g_list_free (list); 152 if (i is count) return children; 153 Control [] newChildren = new Control [i]; 154 System.arraycopy (children, 0, newChildren, 0, i); 155 return newChildren; 156 } 157 158 Control [] _getTabList () { 159 if (tabList is null) return tabList; 160 int count = 0; 161 for (int i=0; i<tabList.length; i++) { 162 if (!tabList [i].isDisposed ()) count++; 163 } 164 if (count is tabList.length) return tabList; 165 Control [] newList = new Control [count]; 166 int index = 0; 167 for (int i=0; i<tabList.length; i++) { 168 if (!tabList [i].isDisposed ()) { 169 newList [index++] = tabList [i]; 170 } 171 } 172 tabList = newList; 173 return tabList; 174 } 175 176 /** 177 * Clears any data that has been cached by a Layout for all widgets that 178 * are in the parent hierarchy of the changed control up to and including the 179 * receiver. If an ancestor does not have a layout, it is skipped. 180 * 181 * @param changed an array of controls that changed state and require a recalculation of size 182 * 183 * @exception IllegalArgumentException <ul> 184 * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li> 185 * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li> 186 * </ul> 187 * @exception SWTException <ul> 188 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 189 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 190 * </ul> 191 * 192 * @since 3.1 193 */ 194 public void changed (Control[] changed) { 195 checkWidget (); 196 if (changed is null) error (SWT.ERROR_INVALID_ARGUMENT); 197 for (int i=0; i<changed.length; i++) { 198 Control control = changed [i]; 199 if (control is null) error (SWT.ERROR_INVALID_ARGUMENT); 200 if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); 201 bool ancestor = false; 202 Composite composite = control.parent; 203 while (composite !is null) { 204 ancestor = composite is this; 205 if (ancestor) break; 206 composite = composite.parent; 207 } 208 if (!ancestor) error (SWT.ERROR_INVALID_PARENT); 209 } 210 for (int i=0; i<changed.length; i++) { 211 Control child = changed [i]; 212 Composite composite = child.parent; 213 while (child !is this) { 214 if (composite.layout_ is null || !composite.layout_.flushCache (child)) { 215 composite.state |= LAYOUT_CHANGED; 216 } 217 child = composite; 218 composite = child.parent; 219 } 220 } 221 } 222 223 override void checkBuffered () { 224 if ((style & SWT.DOUBLE_BUFFERED) is 0 && (style & SWT.NO_BACKGROUND) !is 0) { 225 return; 226 } 227 super.checkBuffered(); 228 } 229 230 override protected void checkSubclass () { 231 /* Do nothing - Subclassing is allowed */ 232 } 233 234 override GtkStyle* childStyle () { 235 if (scrolledHandle !is null) return null; 236 return super.childStyle (); 237 } 238 239 override public Point computeSize (int wHint, int hHint, bool changed) { 240 checkWidget (); 241 if (wHint !is SWT.DEFAULT && wHint < 0) wHint = 0; 242 if (hHint !is SWT.DEFAULT && hHint < 0) hHint = 0; 243 Point size; 244 if (layout_ !is null) { 245 if (wHint is SWT.DEFAULT || hHint is SWT.DEFAULT) { 246 changed |= (state & LAYOUT_CHANGED) !is 0; 247 size = layout_.computeSize (this, wHint, hHint, changed); 248 state &= ~LAYOUT_CHANGED; 249 } else { 250 size = new Point (wHint, hHint); 251 } 252 } else { 253 size = minimumSize (wHint, hHint, changed); 254 } 255 if (size.x is 0) size.x = DEFAULT_WIDTH; 256 if (size.y is 0) size.y = DEFAULT_HEIGHT; 257 if (wHint !is SWT.DEFAULT) size.x = wHint; 258 if (hHint !is SWT.DEFAULT) size.y = hHint; 259 Rectangle trim = computeTrim (0, 0, size.x, size.y); 260 return new Point (trim.width, trim.height); 261 } 262 263 override Control [] computeTabList () { 264 Control[] result = super.computeTabList (); 265 if (result.length is 0) return result; 266 Control [] list = tabList !is null ? _getTabList () : _getChildren (); 267 for (int i=0; i<list.length; i++) { 268 Control child = list [i]; 269 Control [] childList = child.computeTabList (); 270 if (childList.length !is 0) { 271 Control [] newResult = new Control [result.length + childList.length]; 272 System.arraycopy (result, 0, newResult, 0, result.length); 273 System.arraycopy (childList, 0, newResult, result.length, childList.length); 274 result = newResult; 275 } 276 } 277 return result; 278 } 279 280 override void createHandle (int index) { 281 state |= HANDLE | CANVAS; 282 bool scrolled = (style & (SWT.H_SCROLL | SWT.V_SCROLL)) !is 0; 283 if (!scrolled) state |= THEME_BACKGROUND; 284 createHandle (index, true, scrolled || (style & SWT.BORDER) !is 0); 285 } 286 287 void createHandle (int index, bool fixed, bool scrolled) { 288 if (scrolled) { 289 if (fixed) { 290 fixedHandle = cast(GtkWidget*) OS.g_object_new (display.gtk_fixed_get_type (), null); 291 if (fixedHandle is null) error (SWT.ERROR_NO_HANDLES); 292 OS.gtk_fixed_set_has_window (cast(GtkFixed*)fixedHandle, true); 293 } 294 auto vadj = cast(GtkAdjustment*)OS.gtk_adjustment_new (0, 0, 100, 1, 10, 10); 295 if (vadj is null) error (SWT.ERROR_NO_HANDLES); 296 auto hadj = cast(GtkAdjustment*)OS.gtk_adjustment_new (0, 0, 100, 1, 10, 10); 297 if (hadj is null) error (SWT.ERROR_NO_HANDLES); 298 scrolledHandle = cast(GtkWidget*) OS.gtk_scrolled_window_new (hadj, vadj); 299 if (scrolledHandle is null) SWT.error (SWT.ERROR_NO_HANDLES); 300 } 301 handle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null); 302 if (handle is null) SWT.error (SWT.ERROR_NO_HANDLES); 303 OS.gtk_fixed_set_has_window (cast(GtkFixed*)handle, true); 304 OS.GTK_WIDGET_SET_FLAGS(handle, OS.GTK_CAN_FOCUS); 305 if ((style & SWT.EMBEDDED) is 0) { 306 if ((state & CANVAS) !is 0) { 307 /* Prevent an input method context from being created for the Browser widget */ 308 if (display.getData (NO_INPUT_METHOD) is null) { 309 imHandle_ = OS.gtk_im_multicontext_new (); 310 if (imHandle_ is null) error (SWT.ERROR_NO_HANDLES); 311 } 312 } 313 } 314 if (scrolled) { 315 if (fixed) OS.gtk_container_add (cast(GtkContainer*)fixedHandle, scrolledHandle); 316 /* 317 * Force the scrolledWindow to have a single child that is 318 * not scrolled automatically. Calling gtk_container_add() 319 * seems to add the child correctly but cause a warning. 320 */ 321 bool warnings = display.getWarnings (); 322 display.setWarnings (false); 323 OS.gtk_container_add (cast(GtkContainer*)scrolledHandle, handle); 324 display.setWarnings (warnings); 325 326 int hsp = (style & SWT.H_SCROLL) !is 0 ? OS.GTK_POLICY_ALWAYS : OS.GTK_POLICY_NEVER; 327 int vsp = (style & SWT.V_SCROLL) !is 0 ? OS.GTK_POLICY_ALWAYS : OS.GTK_POLICY_NEVER; 328 OS.gtk_scrolled_window_set_policy (cast(GtkScrolledWindow*)scrolledHandle, hsp, vsp); 329 if (hasBorder ()) { 330 OS.gtk_scrolled_window_set_shadow_type (cast(GtkScrolledWindow*)scrolledHandle, OS.GTK_SHADOW_ETCHED_IN); 331 } 332 } 333 if ((style & SWT.EMBEDDED) !is 0) { 334 socketHandle = OS.gtk_socket_new (); 335 if (socketHandle is null) SWT.error (SWT.ERROR_NO_HANDLES); 336 OS.gtk_container_add (cast(GtkContainer*)handle, cast(GtkWidget*)socketHandle); 337 } 338 if ((style & SWT.NO_REDRAW_RESIZE) !is 0 && (style & SWT.RIGHT_TO_LEFT) is 0) { 339 OS.gtk_widget_set_redraw_on_allocate (handle, false); 340 } 341 /* 342 * Bug in GTK. When a widget is double buffered and the back 343 * pixmap is null, the double buffer pixmap is filled with the 344 * background of the widget rather than the current contents of 345 * the screen. If nothing is drawn during an expose event, 346 * the pixels are altered. The fix is to clear double buffering 347 * when NO_BACKGROUND is set and DOUBLE_BUFFERED 348 * is not explicitly set. 349 */ 350 if ((style & SWT.DOUBLE_BUFFERED) is 0 && (style & SWT.NO_BACKGROUND) !is 0) { 351 OS.gtk_widget_set_double_buffered (handle, false); 352 } 353 } 354 355 override void deregister () { 356 super.deregister (); 357 if (socketHandle !is null) display.removeWidget (cast(GtkWidget*)socketHandle); 358 } 359 360 void drawBackground (GC gc, int x, int y, int width, int height) { 361 Control control = findBackgroundControl (); 362 if (control !is null) { 363 GCData data = gc.getGCData (); 364 auto cairo = data.cairo; 365 if (cairo !is null) { 366 Cairo.cairo_save (cairo); 367 if (control.backgroundImage !is null) { 368 Point pt = display.map (this, control, 0, 0); 369 Cairo.cairo_translate (cairo, -pt.x, -pt.y); 370 x += pt.x; 371 y += pt.y; 372 auto xDisplay = OS.GDK_DISPLAY (); 373 auto xVisual = OS.gdk_x11_visual_get_xvisual (OS.gdk_visual_get_system()); 374 auto drawable = control.backgroundImage.pixmap; 375 auto xDrawable = OS.GDK_PIXMAP_XID (drawable); 376 int w, h; 377 OS.gdk_drawable_get_size (cast(GdkDrawable*)drawable, &w, &h); 378 auto surface = Cairo.cairo_xlib_surface_create (xDisplay, xDrawable, xVisual, w, h); 379 if (surface is null) error (SWT.ERROR_NO_HANDLES); 380 auto pattern = Cairo.cairo_pattern_create_for_surface (surface); 381 if (pattern is null) error (SWT.ERROR_NO_HANDLES); 382 Cairo.cairo_pattern_set_extend (pattern, Cairo.CAIRO_EXTEND_REPEAT); 383 if ((data.style & SWT.MIRRORED) !is 0) { 384 double[] matrix = [-1.0, 0, 0, 1, 0, 0 ]; 385 Cairo.cairo_pattern_set_matrix(pattern, cast(cairo_matrix_t*)matrix.ptr); 386 } 387 Cairo.cairo_set_source (cairo, pattern); 388 Cairo.cairo_surface_destroy (surface); 389 Cairo.cairo_pattern_destroy (pattern); 390 } else { 391 GdkColor* color = control.getBackgroundColor (); 392 Cairo.cairo_set_source_rgba (cairo, (color.red & 0xFFFF) / cast(float)0xFFFF, (color.green & 0xFFFF) / cast(float)0xFFFF, (color.blue & 0xFFFF) / cast(float)0xFFFF, data.alpha / cast(float)0xFF); 393 } 394 Cairo.cairo_rectangle (cairo, x, y, width, height); 395 Cairo.cairo_fill (cairo); 396 Cairo.cairo_restore (cairo); 397 } else { 398 auto gdkGC = gc.handle; 399 GdkGCValues* values = new GdkGCValues (); 400 OS.gdk_gc_get_values (gdkGC, values); 401 if (control.backgroundImage !is null) { 402 Point pt = display.map (this, control, 0, 0); 403 OS.gdk_gc_set_fill (gdkGC, OS.GDK_TILED); 404 OS.gdk_gc_set_ts_origin (gdkGC, -pt.x, -pt.y); 405 OS.gdk_gc_set_tile (gdkGC, control.backgroundImage.pixmap); 406 OS.gdk_draw_rectangle (data.drawable, gdkGC, 1, x, y, width, height); 407 OS.gdk_gc_set_fill (gdkGC, values.fill); 408 OS.gdk_gc_set_ts_origin (gdkGC, values.ts_x_origin, values.ts_y_origin); 409 } else { 410 GdkColor* color = control.getBackgroundColor (); 411 OS.gdk_gc_set_foreground (gdkGC, color); 412 OS.gdk_draw_rectangle (data.drawable, gdkGC, 1, x, y, width, height); 413 color.pixel = values.foreground.pixel; 414 OS.gdk_gc_set_foreground (gdkGC, color); 415 } 416 } 417 } else { 418 gc.fillRectangle (x, y, width, height); 419 } 420 } 421 422 override void enableWidget (bool enabled) { 423 if ((state & CANVAS) !is 0) return; 424 super.enableWidget (enabled); 425 } 426 427 Composite findDeferredControl () { 428 return layoutCount > 0 ? this : parent.findDeferredControl (); 429 } 430 431 override Menu [] findMenus (Control control) { 432 if (control is this) return new Menu [0]; 433 Menu[] result = super.findMenus (control); 434 Control [] children = _getChildren (); 435 for (int i=0; i<children.length; i++) { 436 Control child = children [i]; 437 Menu [] menuList = child.findMenus (control); 438 if (menuList.length !is 0) { 439 Menu [] newResult = new Menu [result.length + menuList.length]; 440 System.arraycopy (result, 0, newResult, 0, result.length); 441 System.arraycopy (menuList, 0, newResult, result.length, menuList.length); 442 result = newResult; 443 } 444 } 445 return result; 446 } 447 448 override void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) { 449 super.fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus); 450 Control [] children = _getChildren (); 451 for (int i=0; i<children.length; i++) { 452 children [i].fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus); 453 } 454 } 455 456 override 457 void fixModal(GtkWidget* group, GtkWidget* modalGroup) { 458 Control[] controls = _getChildren (); 459 for (int i = 0; i < controls.length; i++) { 460 controls[i].fixModal (group, modalGroup); 461 } 462 } 463 464 override void fixStyle () { 465 super.fixStyle (); 466 if (scrolledHandle is null) fixStyle (handle); 467 Control[] children = _getChildren (); 468 for (int i = 0; i < children.length; i++) { 469 children [i].fixStyle (); 470 } 471 } 472 473 void fixTabList (Control control) { 474 if (tabList is null) return; 475 int count = 0; 476 for (int i=0; i<tabList.length; i++) { 477 if (tabList [i] is control) count++; 478 } 479 if (count is 0) return; 480 Control [] newList = null; 481 ptrdiff_t length = tabList.length - count; 482 if (length !is 0) { 483 newList = new Control [length]; 484 int index = 0; 485 for (int i=0; i<tabList.length; i++) { 486 if (tabList [i] !is control) { 487 newList [index++] = tabList [i]; 488 } 489 } 490 } 491 tabList = newList; 492 } 493 494 void fixZOrder () { 495 if ((state & CANVAS) !is 0) return; 496 auto parentHandle = parentingHandle (); 497 auto parentWindow = OS.GTK_WIDGET_WINDOW (cast(GtkWidget*)parentHandle); 498 if (parentWindow is null) return; 499 GObject* userData; 500 auto windowList = OS.gdk_window_get_children (parentWindow); 501 if (windowList !is null) { 502 auto windows = windowList; 503 while (windows !is null) { 504 auto window = cast(GdkDrawable*)OS.g_list_data (windows); 505 if (window !is redrawWindow) { 506 OS.gdk_window_get_user_data (window, cast(void**)&userData); 507 if (userData is null || OS.G_OBJECT_TYPE (cast(GTypeInstance*)userData) !is display.gtk_fixed_get_type ()) { 508 OS.gdk_window_lower (window); 509 } 510 } 511 windows = cast(GList*)OS.g_list_next (windows); 512 } 513 OS.g_list_free (windowList); 514 } 515 } 516 517 override GtkWidget* focusHandle () { 518 if (socketHandle !is null) return socketHandle; 519 return super.focusHandle (); 520 } 521 522 override bool forceFocus (GtkWidget* focusHandle) { 523 if (socketHandle !is null) OS.GTK_WIDGET_SET_FLAGS (focusHandle, OS.GTK_CAN_FOCUS); 524 bool result = super.forceFocus (focusHandle); 525 if (socketHandle !is null) OS.GTK_WIDGET_UNSET_FLAGS (focusHandle, OS.GTK_CAN_FOCUS); 526 return result; 527 } 528 529 /** 530 * Returns the receiver's background drawing mode. This 531 * will be one of the following constants defined in class 532 * <code>SWT</code>: 533 * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, 534 * <code>INHERTIT_FORCE</code>. 535 * 536 * @return the background mode 537 * 538 * @exception SWTException <ul> 539 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 540 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 541 * </ul> 542 * 543 * @see SWT 544 * 545 * @since 3.2 546 */ 547 public int getBackgroundMode () { 548 checkWidget (); 549 return backgroundMode; 550 } 551 552 /** 553 * Returns a (possibly empty) array containing the receiver's children. 554 * Children are returned in the order that they are drawn. The topmost 555 * control appears at the beginning of the array. Subsequent controls 556 * draw beneath this control and appear later in the array. 557 * <p> 558 * Note: This is not the actual structure used by the receiver 559 * to maintain its list of children, so modifying the array will 560 * not affect the receiver. 561 * </p> 562 * 563 * @return an array of children 564 * 565 * @see Control#moveAbove 566 * @see Control#moveBelow 567 * 568 * @exception SWTException <ul> 569 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 570 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 571 * </ul> 572 */ 573 public Control [] getChildren () { 574 checkWidget(); 575 return _getChildren (); 576 } 577 578 int getChildrenCount () { 579 /* 580 * NOTE: The current implementation will count 581 * non-registered children. 582 */ 583 auto list = OS.gtk_container_get_children (cast(GtkContainer*)handle); 584 if (list is null) return 0; 585 int count = OS.g_list_length (list); 586 OS.g_list_free (list); 587 return count; 588 } 589 590 override public Rectangle getClientArea () { 591 checkWidget(); 592 if ((state & CANVAS) !is 0) { 593 if ((state & ZERO_WIDTH) !is 0 && (state & ZERO_HEIGHT) !is 0) { 594 return new Rectangle (0, 0, 0, 0); 595 } 596 forceResize (); 597 auto clientHandle = clientHandle (); 598 int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (clientHandle); 599 int height = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (clientHandle); 600 return new Rectangle (0, 0, width, height); 601 } 602 return super.getClientArea(); 603 } 604 605 override 606 int getClientWidth() { 607 return (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (clientHandle ()); 608 } 609 610 /** 611 * Returns layout which is associated with the receiver, or 612 * null if one has not been set. 613 * 614 * @return the receiver's layout or null 615 * 616 * @exception SWTException <ul> 617 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 618 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 619 * </ul> 620 */ 621 public Layout getLayout () { 622 checkWidget(); 623 return layout_; 624 } 625 626 /** 627 * Returns <code>true</code> if the receiver has deferred 628 * the performing of layout, and <code>false</code> otherwise. 629 * 630 * @return the receiver's deferred layout state 631 * 632 * @exception SWTException <ul> 633 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 634 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 635 * </ul> 636 * 637 * @see #setLayoutDeferred(bool) 638 * @see #isLayoutDeferred() 639 * 640 * @since 3.1 641 */ 642 public bool getLayoutDeferred () { 643 checkWidget (); 644 return layoutCount > 0 ; 645 } 646 647 /** 648 * Gets the (possibly empty) tabbing order for the control. 649 * 650 * @return tabList the ordered list of controls representing the tab order 651 * 652 * @exception SWTException <ul> 653 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 654 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 655 * </ul> 656 * 657 * @see #setTabList 658 */ 659 public Control [] getTabList () { 660 checkWidget (); 661 Control [] tabList = _getTabList (); 662 if (tabList is null) { 663 int count = 0; 664 Control [] list =_getChildren (); 665 for (int i=0; i<list.length; i++) { 666 if (list [i].isTabGroup ()) count++; 667 } 668 tabList = new Control [count]; 669 int index = 0; 670 for (int i=0; i<list.length; i++) { 671 if (list [i].isTabGroup ()) { 672 tabList [index++] = list [i]; 673 } 674 } 675 } 676 return tabList; 677 } 678 679 override int gtk_button_press_event (GtkWidget* widget, GdkEventButton* event) { 680 auto result = super.gtk_button_press_event (widget, event); 681 if (result !is 0) return result; 682 if ((state & CANVAS) !is 0) { 683 if ((style & SWT.NO_FOCUS) is 0 && hooksKeys ()) { 684 if (event.button is 1) { 685 if (getChildrenCount () is 0) setFocus (); 686 } 687 } 688 } 689 return result; 690 } 691 692 override int gtk_expose_event (GtkWidget* widget, GdkEventExpose* eventPtr) { 693 if ((state & OBSCURED) !is 0) return 0; 694 if ((state & CANVAS) is 0) { 695 return super.gtk_expose_event (widget, eventPtr); 696 } 697 if ((style & SWT.NO_MERGE_PAINTS) is 0) { 698 return super.gtk_expose_event (widget, eventPtr); 699 } 700 if (!hooks (SWT.Paint) && !filters (SWT.Paint)) return 0; 701 GdkEventExpose* gdkEvent = eventPtr; 702 GdkRectangle* rectangles; 703 int n_rectangles; 704 OS.gdk_region_get_rectangles (gdkEvent.region, &rectangles, &n_rectangles); 705 for (int i=0; i<n_rectangles; i++) { 706 Event event = new Event (); 707 event.x = rectangles[i].x; 708 event.y = rectangles[i].y; 709 event.width = rectangles[i].width; 710 event.height = rectangles[i].height; 711 if ((style & SWT.MIRRORED) !is 0) event.x = getClientWidth () - event.width - event.x; 712 auto damageRgn = OS.gdk_region_new (); 713 OS.gdk_region_union_with_rect (damageRgn, rectangles + i ); 714 GCData data = new GCData (); 715 data.damageRgn = damageRgn; 716 GC gc = event.gc = GC.gtk_new (this, data); 717 OS.gdk_gc_set_clip_region (gc.handle, damageRgn); 718 sendEvent (SWT.Paint, event); 719 gc.dispose (); 720 OS.gdk_region_destroy (damageRgn); 721 event.gc = null; 722 } 723 OS.g_free (rectangles); 724 return 0; 725 } 726 727 override int gtk_key_press_event (GtkWidget* widget, GdkEventKey* event) { 728 auto result = super.gtk_key_press_event (widget, event); 729 if (result !is 0) return result; 730 /* 731 * Feature in GTK. The default behavior when the return key 732 * is pressed is to select the default button. This is not the 733 * expected behavior for Composite and its subclasses. The 734 * fix is to avoid calling the default handler. 735 */ 736 if ((state & CANVAS) !is 0 && socketHandle is null) { 737 GdkEventKey* keyEvent = event; 738 int key = keyEvent.keyval; 739 switch (key) { 740 case OS.GDK_Return: 741 case OS.GDK_KP_Enter: return 1; 742 default: 743 } 744 } 745 return result; 746 } 747 748 override int gtk_focus (GtkWidget* widget, ptrdiff_t directionType) { 749 if (widget is socketHandle) return 0; 750 return super.gtk_focus (widget, directionType); 751 } 752 753 override int gtk_focus_in_event (GtkWidget* widget, GdkEventFocus* event) { 754 int result = super.gtk_focus_in_event (widget, event); 755 return (state & CANVAS) !is 0 ? 1 : result; 756 } 757 758 override int gtk_focus_out_event (GtkWidget* widget, GdkEventFocus* event) { 759 auto result = super.gtk_focus_out_event (widget, event); 760 return (state & CANVAS) !is 0 ? 1 : result; 761 } 762 763 override int gtk_map (GtkWidget* widget) { 764 fixZOrder (); 765 return 0; 766 } 767 768 override int gtk_realize (GtkWidget* widget) { 769 auto result = super.gtk_realize (widget); 770 if ((style & SWT.NO_BACKGROUND) !is 0) { 771 auto window = OS.GTK_WIDGET_WINDOW (paintHandle ()); 772 if (window !is null) OS.gdk_window_set_back_pixmap (window, null, false); 773 } 774 if (socketHandle !is null) { 775 embeddedHandle = OS.gtk_socket_get_id (cast(GtkSocket*)socketHandle); 776 } 777 return result; 778 } 779 780 override int gtk_scroll_child (GtkWidget* widget, ptrdiff_t scrollType, ptrdiff_t horizontal) { 781 /* Stop GTK scroll child signal for canvas */ 782 OS.g_signal_stop_emission_by_name (widget, OS.scroll_child.ptr); 783 return 1; 784 } 785 786 override int gtk_style_set (GtkWidget* widget, ptrdiff_t previousStyle) { 787 auto result = super.gtk_style_set (widget, previousStyle); 788 if ((style & SWT.NO_BACKGROUND) !is 0) { 789 auto window = OS.GTK_WIDGET_WINDOW (paintHandle ()); 790 if (window !is null) OS.gdk_window_set_back_pixmap (window, null, false); 791 } 792 return result; 793 } 794 795 bool hasBorder () { 796 return (style & SWT.BORDER) !is 0; 797 } 798 799 override void hookEvents () { 800 super.hookEvents (); 801 if ((state & CANVAS) !is 0) { 802 OS.gtk_widget_add_events (handle, OS.GDK_POINTER_MOTION_HINT_MASK); 803 if (scrolledHandle !is null) { 804 OS.g_signal_connect_closure (scrolledHandle, OS.scroll_child.ptr, display.closures [SCROLL_CHILD], false); 805 } 806 } 807 } 808 809 bool hooksKeys () { 810 return hooks (SWT.KeyDown) || hooks (SWT.KeyUp); 811 } 812 813 override GtkIMContext* imHandle () { 814 return imHandle_; 815 } 816 817 /** 818 * Returns <code>true</code> if the receiver or any ancestor 819 * up to and including the receiver's nearest ancestor shell 820 * has deferred the performing of layouts. Otherwise, <code>false</code> 821 * is returned. 822 * 823 * @return the receiver's deferred layout state 824 * 825 * @exception SWTException <ul> 826 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 827 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 828 * </ul> 829 * 830 * @see #setLayoutDeferred(bool) 831 * @see #getLayoutDeferred() 832 * 833 * @since 3.1 834 */ 835 public bool isLayoutDeferred () { 836 checkWidget (); 837 return findDeferredControl () !is null; 838 } 839 840 override bool isTabGroup() { 841 if ((state & CANVAS) !is 0) return true; 842 return super.isTabGroup(); 843 } 844 845 /** 846 * If the receiver has a layout, asks the layout to <em>lay out</em> 847 * (that is, set the size and location of) the receiver's children. 848 * If the receiver does not have a layout, do nothing. 849 * <p> 850 * This is equivalent to calling <code>layout(true)</code>. 851 * </p> 852 * <p> 853 * Note: Layout is different from painting. If a child is 854 * moved or resized such that an area in the parent is 855 * exposed, then the parent will paint. If no child is 856 * affected, the parent will not paint. 857 * </p> 858 * 859 * @exception SWTException <ul> 860 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 861 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 862 * </ul> 863 */ 864 public void layout () { 865 checkWidget (); 866 layout (true); 867 } 868 869 /** 870 * If the receiver has a layout, asks the layout to <em>lay out</em> 871 * (that is, set the size and location of) the receiver's children. 872 * If the argument is <code>true</code> the layout must not rely 873 * on any information it has cached about the immediate children. If it 874 * is <code>false</code> the layout may (potentially) optimize the 875 * work it is doing by assuming that none of the receiver's 876 * children has changed state since the last layout. 877 * If the receiver does not have a layout, do nothing. 878 * <p> 879 * If a child is resized as a result of a call to layout, the 880 * resize event will invoke the layout of the child. The layout 881 * will cascade down through all child widgets in the receiver's widget 882 * tree until a child is encountered that does not resize. Note that 883 * a layout due to a resize will not flush any cached information 884 * (same as <code>layout(false)</code>). 885 * </p> 886 * <p> 887 * Note: Layout is different from painting. If a child is 888 * moved or resized such that an area in the parent is 889 * exposed, then the parent will paint. If no child is 890 * affected, the parent will not paint. 891 * </p> 892 * 893 * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise 894 * 895 * @exception SWTException <ul> 896 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 897 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 898 * </ul> 899 */ 900 public void layout (bool changed) { 901 checkWidget (); 902 if (layout_ is null) return; 903 layout (changed, false); 904 } 905 906 /** 907 * If the receiver has a layout, asks the layout to <em>lay out</em> 908 * (that is, set the size and location of) the receiver's children. 909 * If the changed argument is <code>true</code> the layout must not rely 910 * on any information it has cached about its children. If it 911 * is <code>false</code> the layout may (potentially) optimize the 912 * work it is doing by assuming that none of the receiver's 913 * children has changed state since the last layout. 914 * If the all argument is <code>true</code> the layout will cascade down 915 * through all child widgets in the receiver's widget tree, regardless of 916 * whether the child has changed size. The changed argument is applied to 917 * all layouts. If the all argument is <code>false</code>, the layout will 918 * <em>not</em> cascade down through all child widgets in the receiver's widget 919 * tree. However, if a child is resized as a result of a call to layout, the 920 * resize event will invoke the layout of the child. Note that 921 * a layout due to a resize will not flush any cached information 922 * (same as <code>layout(false)</code>). 923 * </p> 924 * <p> 925 * Note: Layout is different from painting. If a child is 926 * moved or resized such that an area in the parent is 927 * exposed, then the parent will paint. If no child is 928 * affected, the parent will not paint. 929 * </p> 930 * 931 * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise 932 * @param all <code>true</code> if all children in the receiver's widget tree should be laid out, and <code>false</code> otherwise 933 * 934 * @exception SWTException <ul> 935 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 936 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 937 * </ul> 938 * 939 * @since 3.1 940 */ 941 public void layout (bool changed, bool all) { 942 checkWidget (); 943 if (layout_ is null && !all) return; 944 markLayout (changed, all); 945 updateLayout (all); 946 } 947 948 /** 949 * Forces a lay out (that is, sets the size and location) of all widgets that 950 * are in the parent hierarchy of the changed control up to and including the 951 * receiver. The layouts in the hierarchy must not rely on any information 952 * cached about the changed control or any of its ancestors. The layout may 953 * (potentially) optimize the work it is doing by assuming that none of the 954 * peers of the changed control have changed state since the last layout. 955 * If an ancestor does not have a layout, skip it. 956 * <p> 957 * Note: Layout is different from painting. If a child is 958 * moved or resized such that an area in the parent is 959 * exposed, then the parent will paint. If no child is 960 * affected, the parent will not paint. 961 * </p> 962 * 963 * @param changed a control that has had a state change which requires a recalculation of its size 964 * 965 * @exception IllegalArgumentException <ul> 966 * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li> 967 * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li> 968 * </ul> 969 * @exception SWTException <ul> 970 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 971 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 972 * </ul> 973 * 974 * @since 3.1 975 */ 976 public void layout (Control [] changed) { 977 checkWidget (); 978 if (changed is null) error (SWT.ERROR_INVALID_ARGUMENT); 979 for (int i=0; i<changed.length; i++) { 980 Control control = changed [i]; 981 if (control is null) error (SWT.ERROR_INVALID_ARGUMENT); 982 if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); 983 bool ancestor = false; 984 Composite composite = control.parent; 985 while (composite !is null) { 986 ancestor = composite is this; 987 if (ancestor) break; 988 composite = composite.parent; 989 } 990 if (!ancestor) error (SWT.ERROR_INVALID_PARENT); 991 } 992 int updateCount = 0; 993 Composite [] update = new Composite [16]; 994 for (int i=0; i<changed.length; i++) { 995 Control child = changed [i]; 996 Composite composite = child.parent; 997 while (child !is this) { 998 if (composite.layout_ !is null) { 999 composite.state |= LAYOUT_NEEDED; 1000 if (!composite.layout_.flushCache (child)) { 1001 composite.state |= LAYOUT_CHANGED; 1002 } 1003 } 1004 if (updateCount is update.length) { 1005 Composite [] newUpdate = new Composite [update.length + 16]; 1006 System.arraycopy (update, 0, newUpdate, 0, update.length); 1007 update = newUpdate; 1008 } 1009 child = update [updateCount++] = composite; 1010 composite = child.parent; 1011 } 1012 } 1013 for (int i=updateCount-1; i>=0; i--) { 1014 update [i].updateLayout (false); 1015 } 1016 } 1017 1018 override void markLayout (bool changed, bool all) { 1019 if (layout_ !is null) { 1020 state |= LAYOUT_NEEDED; 1021 if (changed) state |= LAYOUT_CHANGED; 1022 } 1023 if (all) { 1024 Control [] children = _getChildren (); 1025 for (int i=0; i<children.length; i++) { 1026 children [i].markLayout (changed, all); 1027 } 1028 } 1029 } 1030 1031 void moveAbove (GtkWidget* child, GtkWidget* sibling) { 1032 if (child is sibling) return; 1033 auto parentHandle = parentingHandle (); 1034 auto fixed = cast(GtkFixed*)parentHandle; 1035 GList* children = fixed.children; 1036 if (children is null) return; 1037 void* data; 1038 GtkWidget* widget; 1039 void* childData; 1040 GList* childLink, siblingLink; 1041 GList* temp = children; 1042 while (temp !is null) { 1043 data = temp.data; 1044 widget = *cast(GtkWidget**) data; 1045 if (child is widget) { 1046 childLink = temp; 1047 childData = data; 1048 } else if (sibling is widget) { 1049 siblingLink = temp; 1050 } 1051 if (childData !is null && (sibling is null || siblingLink !is null)) break; 1052 temp = cast(GList*)OS.g_list_next (temp); 1053 } 1054 children = OS.g_list_remove_link (children, childLink); 1055 if (siblingLink is null || siblingLink.prev is null) { 1056 OS.g_list_free_1 (childLink); 1057 children = OS.g_list_prepend (children, childData); 1058 } else { 1059 temp = siblingLink.prev; 1060 childLink.prev = temp; 1061 temp.next = childLink; 1062 childLink.next = siblingLink; 1063 siblingLink.prev = childLink; 1064 } 1065 fixed.children = children; 1066 parentHandle = cast(GtkWidget*)fixed; 1067 } 1068 1069 alias Scrollable.moveBelow moveBelow; 1070 void moveBelow (GtkWidget* child, GtkWidget* sibling) { 1071 if (child is sibling) return; 1072 auto parentHandle = parentingHandle (); 1073 if (sibling is null && cast(GtkWidget*)parentHandle is cast(GtkWidget*)fixedHandle) { 1074 moveAbove (child, scrolledHandle !is null ? cast(GtkWidget*)scrolledHandle : handle); 1075 return; 1076 } 1077 auto fixed = cast(GtkFixed*)parentHandle; 1078 GList* children = fixed.children; 1079 if (children is null) return; 1080 void* data; 1081 GtkWidget* widget; 1082 void* childData; 1083 GList* childLink; 1084 GList* siblingLink; 1085 GList* temp = children; 1086 while (temp !is null) { 1087 data = temp.data; 1088 widget = *cast(GtkWidget**) temp.data; 1089 if (child is widget) { 1090 childLink = temp; 1091 childData = data; 1092 } else if (sibling is widget) { 1093 siblingLink = temp; 1094 } 1095 if (childData !is null && (sibling is null || siblingLink !is null)) break; 1096 temp = OS.g_list_next(temp); 1097 } 1098 children = OS.g_list_remove_link (children, childLink); 1099 if (siblingLink is null || OS.g_list_next(siblingLink) is null) { 1100 OS.g_list_free_1 (childLink); 1101 children = OS.g_list_append (children, childData); 1102 } else { 1103 temp = OS.g_list_next( siblingLink ); 1104 OS.g_list_set_next (childLink, temp); 1105 OS.g_list_set_previous (temp, childLink); 1106 OS.g_list_set_previous (childLink, siblingLink); 1107 OS.g_list_set_next (siblingLink, childLink); 1108 } 1109 fixed.children = children; 1110 parentHandle = cast(GtkWidget*)fixed; 1111 } 1112 1113 override 1114 void moveChildren(int oldWidth) { 1115 Control[] children = _getChildren (); 1116 for (int i = 0; i < children.length; i++) { 1117 Control child = children[i]; 1118 auto topHandle = child.topHandle (); 1119 int x = OS.GTK_WIDGET_X (topHandle); 1120 int y = OS.GTK_WIDGET_Y (topHandle); 1121 int controlWidth = (child.state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle); 1122 x = oldWidth - controlWidth - x; 1123 int clientWidth = getClientWidth (); 1124 x = clientWidth - controlWidth - x; 1125 if (child.enableWindow !is null) { 1126 OS.gdk_window_move (child.enableWindow, x, y); 1127 } 1128 child.moveHandle (x, y); 1129 /* 1130 * Cause a size allocation this widget's topHandle. Note that 1131 * all calls to gtk_widget_size_allocate() must be preceded by 1132 * a call to gtk_widget_size_request(). 1133 */ 1134 GtkRequisition requisition; 1135 gtk_widget_size_request (topHandle, &requisition); 1136 GtkAllocation allocation; 1137 allocation.x = x; 1138 allocation.y = y; 1139 allocation.width = OS.GTK_WIDGET_WIDTH (topHandle); 1140 allocation.height = OS.GTK_WIDGET_HEIGHT (topHandle); 1141 OS.gtk_widget_size_allocate (topHandle, &allocation); 1142 Control control = child.findBackgroundControl (); 1143 if (control !is null && control.backgroundImage !is null) { 1144 if (child.isVisible ()) child.redrawWidget (0, 0, 0, 0, true, true, true); 1145 } 1146 } 1147 } 1148 1149 Point minimumSize (int wHint, int hHint, bool changed) { 1150 Control [] children = _getChildren (); 1151 int width = 0, height = 0; 1152 for (int i=0; i<children.length; i++) { 1153 Rectangle rect = children [i].getBounds (); 1154 width = Math.max (width, rect.x + rect.width); 1155 height = Math.max (height, rect.y + rect.height); 1156 } 1157 return new Point (width, height); 1158 } 1159 1160 GtkWidget* parentingHandle () { 1161 if ((state & CANVAS) !is 0) return handle; 1162 return fixedHandle !is null ? fixedHandle : handle; 1163 } 1164 1165 override void printWidget (GC gc, GdkDrawable* drawable, int depth, int x, int y) { 1166 Region oldClip = new Region (gc.getDevice ()); 1167 Region newClip = new Region (gc.getDevice ()); 1168 gc.getClipping (oldClip); 1169 Rectangle rect = getBounds (); 1170 newClip.add (oldClip); 1171 newClip.intersect (x, y, rect.width, rect.height); 1172 gc.setClipping (newClip); 1173 super.printWidget (gc, drawable, depth, x, y); 1174 Rectangle clientRect = getClientArea (); 1175 Point pt = display.map (this, parent, clientRect.x, clientRect.y); 1176 clientRect.x = x + pt.x - rect.x; 1177 clientRect.y = y + pt.y - rect.y; 1178 newClip.intersect (clientRect); 1179 gc.setClipping (newClip); 1180 Control [] children = _getChildren (); 1181 for (ptrdiff_t i=cast(ptrdiff_t) (children.length)-1; i>=0; --i) { 1182 Control child = children [i]; 1183 if (child.getVisible ()) { 1184 Point location = child.getLocation (); 1185 child.printWidget (gc, drawable, depth, x + location.x, y + location.y); 1186 } 1187 } 1188 gc.setClipping (oldClip); 1189 oldClip.dispose (); 1190 newClip.dispose (); 1191 } 1192 1193 override void redrawChildren () { 1194 super.redrawChildren (); 1195 Control [] children = _getChildren (); 1196 for (int i = 0; i < children.length; i++) { 1197 Control child = children [i]; 1198 if ((child.state & PARENT_BACKGROUND) !is 0) { 1199 child.redrawWidget (0, 0, 0, 0, true, false, true); 1200 child.redrawChildren (); 1201 } 1202 } 1203 } 1204 1205 override void register () { 1206 super.register (); 1207 if (socketHandle !is null) display.addWidget (socketHandle, this); 1208 } 1209 1210 override void releaseChildren (bool destroy) { 1211 Control [] children = _getChildren (); 1212 for (int i=0; i<children.length; i++) { 1213 Control child = children [i]; 1214 if (child !is null && !child.isDisposed ()) { 1215 child.release (false); 1216 } 1217 } 1218 super.releaseChildren (destroy); 1219 } 1220 1221 override void releaseHandle () { 1222 super.releaseHandle (); 1223 socketHandle = null; 1224 embeddedHandle = 0; 1225 } 1226 1227 override void releaseWidget () { 1228 super.releaseWidget (); 1229 if (imHandle_ !is null) OS.g_object_unref (imHandle_); 1230 imHandle_ = null; 1231 layout_ = null; 1232 tabList = null; 1233 } 1234 1235 void removeControl (Control control) { 1236 fixTabList (control); 1237 } 1238 1239 override void resizeHandle (int width, int height) { 1240 super.resizeHandle (width, height); 1241 if (socketHandle !is null) OS.gtk_widget_set_size_request (socketHandle, width, height); 1242 } 1243 1244 /** 1245 * Sets the background drawing mode to the argument which should 1246 * be one of the following constants defined in class <code>SWT</code>: 1247 * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, 1248 * <code>INHERIT_FORCE</code>. 1249 * 1250 * @param mode the new background mode 1251 * 1252 * @exception SWTException <ul> 1253 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1254 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1255 * </ul> 1256 * 1257 * @see SWT 1258 * 1259 * @since 3.2 1260 */ 1261 public void setBackgroundMode (int mode) { 1262 checkWidget (); 1263 backgroundMode = mode; 1264 Control[] children = _getChildren (); 1265 for (int i = 0; i < children.length; i++) { 1266 children [i].updateBackgroundMode (); 1267 } 1268 } 1269 1270 override int setBounds (int x, int y, int width, int height, bool move, bool resize) { 1271 int result = super.setBounds (x, y, width, height, move, resize); 1272 if ((result & RESIZED) !is 0 && layout_ !is null) { 1273 markLayout (false, false); 1274 updateLayout (false); 1275 } 1276 return result; 1277 } 1278 1279 override public bool setFocus () { 1280 checkWidget(); 1281 Control [] children = _getChildren (); 1282 for (int i=0; i<children.length; i++) { 1283 Control child = children [i]; 1284 if (child.getVisible () && child.setFocus ()) return true; 1285 } 1286 return super.setFocus (); 1287 } 1288 1289 /** 1290 * Sets the layout which is associated with the receiver to be 1291 * the argument which may be null. 1292 * 1293 * @param layout the receiver's new layout or null 1294 * 1295 * @exception SWTException <ul> 1296 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1297 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1298 * </ul> 1299 */ 1300 public void setLayout (Layout layout) { 1301 checkWidget(); 1302 this.layout_ = layout; 1303 } 1304 1305 /** 1306 * If the argument is <code>true</code>, causes subsequent layout 1307 * operations in the receiver or any of its children to be ignored. 1308 * No layout of any kind can occur in the receiver or any of its 1309 * children until the flag is set to false. 1310 * Layout operations that occurred while the flag was 1311 * <code>true</code> are remembered and when the flag is set to 1312 * <code>false</code>, the layout operations are performed in an 1313 * optimized manner. Nested calls to this method are stacked. 1314 * 1315 * @param defer the new defer state 1316 * 1317 * @exception SWTException <ul> 1318 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1319 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1320 * </ul> 1321 * 1322 * @see #layout(bool) 1323 * @see #layout(Control[]) 1324 * 1325 * @since 3.1 1326 */ 1327 public void setLayoutDeferred (bool defer) { 1328 if (!defer) { 1329 if (--layoutCount is 0) { 1330 if ((state & LAYOUT_CHILD) !is 0 || (state & LAYOUT_NEEDED) !is 0) { 1331 updateLayout (true); 1332 } 1333 } 1334 } else { 1335 layoutCount++; 1336 } 1337 } 1338 1339 override bool setScrollBarVisible (ScrollBar bar, bool visible) { 1340 bool changed = super.setScrollBarVisible (bar, visible); 1341 if (changed && layout_ !is null) { 1342 markLayout (false, false); 1343 updateLayout (false); 1344 } 1345 return changed; 1346 } 1347 1348 override bool setTabGroupFocus (bool next) { 1349 if (isTabItem ()) return setTabItemFocus (next); 1350 bool takeFocus = (style & SWT.NO_FOCUS) is 0; 1351 if ((state & CANVAS) !is 0) takeFocus = hooksKeys (); 1352 if (socketHandle !is null) takeFocus = true; 1353 if (takeFocus && setTabItemFocus (next)) return true; 1354 Control [] children = _getChildren (); 1355 for (int i=0; i<children.length; i++) { 1356 Control child = children [i]; 1357 if (child.isTabItem () && child.setTabItemFocus (next)) return true; 1358 } 1359 return false; 1360 } 1361 1362 override bool setTabItemFocus (bool next) { 1363 if (!super.setTabItemFocus (next)) return false; 1364 if (socketHandle !is null) { 1365 int direction = next ? OS.GTK_DIR_TAB_FORWARD : OS.GTK_DIR_TAB_BACKWARD; 1366 OS.GTK_WIDGET_UNSET_FLAGS (socketHandle, OS.GTK_HAS_FOCUS); 1367 OS.gtk_widget_child_focus (socketHandle, direction); 1368 OS.GTK_WIDGET_SET_FLAGS (socketHandle, OS.GTK_HAS_FOCUS); 1369 } 1370 return true; 1371 } 1372 1373 /** 1374 * Sets the tabbing order for the specified controls to 1375 * match the order that they occur in the argument list. 1376 * 1377 * @param tabList the ordered list of controls representing the tab order or null 1378 * 1379 * @exception IllegalArgumentException <ul> 1380 * <li>ERROR_INVALID_ARGUMENT - if a widget in the tabList is null or has been disposed</li> 1381 * <li>ERROR_INVALID_PARENT - if widget in the tabList is not in the same widget tree</li> 1382 * </ul> 1383 * @exception SWTException <ul> 1384 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1385 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1386 * </ul> 1387 */ 1388 public void setTabList (Control [] tabList) { 1389 checkWidget (); 1390 if (tabList !is null) { 1391 for (int i=0; i<tabList.length; i++) { 1392 Control control = tabList [i]; 1393 if (control is null) error (SWT.ERROR_INVALID_ARGUMENT); 1394 if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); 1395 if (control.parent !is this) error (SWT.ERROR_INVALID_PARENT); 1396 } 1397 Control [] newList = new Control [tabList.length]; 1398 System.arraycopy (tabList, 0, newList, 0, tabList.length); 1399 tabList = newList; 1400 } 1401 this.tabList = tabList; 1402 } 1403 1404 override void showWidget () { 1405 super.showWidget (); 1406 if (socketHandle !is null) { 1407 OS.gtk_widget_show (socketHandle); 1408 embeddedHandle = OS.gtk_socket_get_id (cast(GtkSocket*)socketHandle); 1409 } 1410 if (scrolledHandle is null) fixStyle (handle); 1411 } 1412 1413 override bool translateMnemonic (Event event, Control control) { 1414 if (super.translateMnemonic (event, control)) return true; 1415 if (control !is null) { 1416 Control [] children = _getChildren (); 1417 for (int i=0; i<children.length; i++) { 1418 Control child = children [i]; 1419 if (child.translateMnemonic (event, control)) return true; 1420 } 1421 } 1422 return false; 1423 } 1424 1425 override int traversalCode(int key, GdkEventKey* event) { 1426 if ((state & CANVAS) !is 0) { 1427 if ((style & SWT.NO_FOCUS) !is 0) return 0; 1428 if (hooksKeys ()) return 0; 1429 } 1430 return super.traversalCode (key, event); 1431 } 1432 1433 override bool translateTraversal (GdkEventKey* keyEvent) { 1434 if (socketHandle !is null) return false; 1435 return super.translateTraversal (keyEvent); 1436 } 1437 1438 override void updateBackgroundMode () { 1439 super.updateBackgroundMode (); 1440 Control [] children = _getChildren (); 1441 for (int i = 0; i < children.length; i++) { 1442 children [i].updateBackgroundMode (); 1443 } 1444 } 1445 1446 override void updateLayout (bool all) { 1447 Composite parent = findDeferredControl (); 1448 if (parent !is null) { 1449 parent.state |= LAYOUT_CHILD; 1450 return; 1451 } 1452 if ((state & LAYOUT_NEEDED) !is 0) { 1453 bool changed = (state & LAYOUT_CHANGED) !is 0; 1454 state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED); 1455 layout_.layout (this, changed); 1456 } 1457 if (all) { 1458 state &= ~LAYOUT_CHILD; 1459 Control [] children = _getChildren (); 1460 for (int i=0; i<children.length; i++) { 1461 children [i].updateLayout (all); 1462 } 1463 } 1464 } 1465 }