1 /*******************************************************************************
2 * Copyright (c) 2000, 2019 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.widgets;
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.internal.*;
20 import org.eclipse.swt.internal.win32.*;
23 * Instances of this class are controls which are capable
24 * of containing other controls.
26 * <dt><b>Styles:</b></dt>
27 * <dd>NO_BACKGROUND, NO_FOCUS, NO_MERGE_PAINTS, NO_REDRAW_RESIZE, NO_RADIO_GROUP, EMBEDDED, DOUBLE_BUFFERED</dd>
28 * <dt><b>Events:</b></dt>
32 * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, <code>NO_MERGE_PAINTS</code>,
33 * and <code>NO_REDRAW_RESIZE</code> styles are intended for use with <code>Canvas</code>.
34 * They can be used with <code>Composite</code> if you are drawing your own, but their
35 * behavior is undefined if they are used with subclasses of <code>Composite</code> other
36 * than <code>Canvas</code>.
38 * Note: The <code>CENTER</code> style, although undefined for composites, has the
39 * same value as <code>EMBEDDED</code> which is used to embed widgets from other
40 * widget toolkits into SWT. On some operating systems (GTK), this may cause
41 * the children of this composite to be obscured.
43 * This class may be subclassed by custom control implementors
44 * who are building controls that are constructed from aggregates
49 * @see <a href="http://www.eclipse.org/swt/snippets/#composite">Composite snippets</a>
50 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
52 public class Composite extends Scrollable {
56 int layoutCount, backgroundMode;
58 static final int TOOLTIP_LIMIT = 4096;
61 * Prevents uninitialized instances from being created outside the package.
67 * Constructs a new instance of this class given its parent
68 * and a style value describing its behavior and appearance.
70 * The style value is either one of the style constants defined in
71 * class <code>SWT</code> which is applicable to instances of this
72 * class, or must be built by <em>bitwise OR</em>'ing together
73 * (that is, using the <code>int</code> "|" operator) two or more
74 * of those <code>SWT</code> style constants. The class description
75 * lists the style constants that are applicable to the class.
76 * Style bits are also inherited from superclasses.
79 * @param parent a widget which will be the parent of the new instance (cannot be null)
80 * @param style the style of widget to construct
82 * @exception IllegalArgumentException <ul>
83 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
85 * @exception SWTException <ul>
86 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
89 * @see SWT#NO_BACKGROUND
91 * @see SWT#NO_MERGE_PAINTS
92 * @see SWT#NO_REDRAW_RESIZE
93 * @see SWT#NO_RADIO_GROUP
95 * @see SWT#DOUBLE_BUFFERED
96 * @see Widget#getStyle
98 public Composite (Composite parent, int style) {
99 super (parent, style);
102 Control [] _getChildren () {
104 long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
105 if (hwndChild == 0) return new Control [0];
106 while (hwndChild != 0) {
108 hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
110 Control [] children = new Control [count];
112 hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
113 while (hwndChild != 0) {
114 Control control = display.getControl (hwndChild);
115 if (control != null && control != this) {
116 children [index++] = control;
118 hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
120 if (count == index) return children;
121 Control [] newChildren = new Control [index];
122 System.arraycopy (children, 0, newChildren, 0, index);
126 Control [] _getTabList () {
127 if (tabList == null) return tabList;
129 for (int i=0; i<tabList.length; i++) {
130 if (!tabList [i].isDisposed ()) count++;
132 if (count == tabList.length) return tabList;
133 Control [] newList = new Control [count];
135 for (int i=0; i<tabList.length; i++) {
136 if (!tabList [i].isDisposed ()) {
137 newList [index++] = tabList [i];
145 * Clears any data that has been cached by a Layout for all widgets that
146 * are in the parent hierarchy of the changed control up to and including the
147 * receiver. If an ancestor does not have a layout, it is skipped.
149 * @param changed an array of controls that changed state and require a recalculation of size
151 * @exception IllegalArgumentException <ul>
152 * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li>
153 * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li>
155 * @exception SWTException <ul>
156 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
157 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
160 * @deprecated use {@link Composite#layout(Control[], int)} instead
164 public void changed (Control[] changed) {
165 layout(changed, SWT.DEFER);
169 void checkBuffered () {
170 if ((state & CANVAS) == 0) {
171 super.checkBuffered ();
176 void checkComposited () {
177 if ((state & CANVAS) != 0) {
178 if ((style & SWT.TRANSPARENT) != 0) {
179 long hwndParent = parent.handle;
180 int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
181 bits |= OS.WS_EX_COMPOSITED;
182 OS.SetWindowLong (hwndParent, OS.GWL_EXSTYLE, bits);
188 protected void checkSubclass () {
189 /* Do nothing - Subclassing is allowed */
193 Widget [] computeTabList () {
194 Widget result [] = super.computeTabList ();
195 if (result.length == 0) return result;
196 Control [] list = tabList != null ? _getTabList () : _getChildren ();
197 for (int i=0; i<list.length; i++) {
198 Control child = list [i];
199 Widget [] childList = child.computeTabList ();
200 if (childList.length != 0) {
201 Widget [] newResult = new Widget [result.length + childList.length];
202 System.arraycopy (result, 0, newResult, 0, result.length);
203 System.arraycopy (childList, 0, newResult, result.length, childList.length);
211 Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
214 if (layout != null) {
215 if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
216 changed |= (state & LAYOUT_CHANGED) != 0;
217 state &= ~LAYOUT_CHANGED;
218 size = DPIUtil.autoScaleUp(layout.computeSize (this, DPIUtil.autoScaleDown(wHint), DPIUtil.autoScaleDown(hHint), changed));
220 size = new Point (wHint, hHint);
223 size = minimumSize (wHint, hHint, changed);
224 if (size.x == 0) size.x = DEFAULT_WIDTH;
225 if (size.y == 0) size.y = DEFAULT_HEIGHT;
227 if (wHint != SWT.DEFAULT) size.x = wHint;
228 if (hHint != SWT.DEFAULT) size.y = hHint;
230 * Since computeTrim can be overridden by subclasses, we cannot
231 * call computeTrimInPixels directly.
233 Rectangle trim = DPIUtil.autoScaleUp(computeTrim (0, 0, DPIUtil.autoScaleDown(size.x), DPIUtil.autoScaleDown(size.y)));
234 return new Point (trim.width, trim.height);
238 * Copies a rectangular area of the receiver at the specified
239 * position using the gc.
241 * @param gc the gc where the rectangle is to be filled
242 * @param x the x coordinate of the rectangle to be filled
243 * @param y the y coordinate of the rectangle to be filled
244 * @param width the width of the rectangle to be filled
245 * @param height the height of the rectangle to be filled
247 * @exception IllegalArgumentException <ul>
248 * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
249 * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li>
251 * @exception SWTException <ul>
252 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
253 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
256 /*public*/ void copyArea (GC gc, int x, int y, int width, int height) {
258 if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
259 if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
262 //#define PW_CLIENTONLY 0x00000001
264 //topHandle wrong for Tree?
265 long hDC = gc.handle;
266 int nSavedDC = OS.SaveDC (hDC);
267 OS.IntersectClipRect (hDC, 0, 0, width, height);
270 POINT lpPoint = new POINT ();
271 long hwndParent = OS.GetParent (handle);
272 OS.MapWindowPoints (handle, hwndParent, lpPoint, 1);
273 RECT rect = new RECT ();
274 OS.GetWindowRect (handle, rect);
275 POINT lpPoint1 = new POINT (), lpPoint2 = new POINT ();
276 x = x + (lpPoint.x - rect.left);
277 y = y + (lpPoint.y - rect.top);
278 OS.SetWindowOrgEx (hDC, x, y, lpPoint1);
279 OS.SetBrushOrgEx (hDC, x, y, lpPoint2);
280 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
281 if ((bits & OS.WS_VISIBLE) == 0) {
282 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
285 OS.RedrawWindow (handle, null, 0, OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN);
286 OS.PrintWindow (handle, hDC, 0);//0x00000001);
287 if ((bits & OS.WS_VISIBLE) == 0) {
288 OS.DefWindowProc(handle, OS.WM_SETREDRAW, 0, 0);
290 OS.RestoreDC (hDC, nSavedDC);
294 void createHandle () {
295 super.createHandle ();
297 if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0 || findThemeControl () == parent) {
298 state |= THEME_BACKGROUND;
300 if ((style & SWT.TRANSPARENT) != 0) {
301 int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
302 bits |= OS.WS_EX_TRANSPARENT;
303 OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
308 int applyThemeBackground () {
310 * Composite with scrollbars would not inherit the theme because it was
311 * probably being used to implement a control similar to a Text, List,
312 * Table, or Tree, and those controls do not inherit the background theme.
313 * We assume that a Composite that did not have scrollbars was probably just
314 * being used to group some other controls, therefore it should inherit.
316 * But when Composite background is set to COLOR_TRANSPARENT (i.e.
317 * backgroundAlpha as '0') which means parent theme should be inherited, so
318 * enable the THEME_BACKGROUND in 'state' to support background transparent.
319 * Refer bug 463127 & related bug 234649.
321 return (backgroundAlpha == 0 || (style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0 || findThemeControl () == parent) ? 1 : 0;
325 * Fills the interior of the rectangle specified by the arguments,
326 * with the receiver's background.
328 * <p>The <code>offsetX</code> and <code>offsetY</code> are used to map from
329 * the <code>gc</code> origin to the origin of the parent image background. This is useful
330 * to ensure proper alignment of the image background.</p>
332 * @param gc the gc where the rectangle is to be filled
333 * @param x the x coordinate of the rectangle to be filled
334 * @param y the y coordinate of the rectangle to be filled
335 * @param width the width of the rectangle to be filled
336 * @param height the height of the rectangle to be filled
337 * @param offsetX the image background x offset
338 * @param offsetY the image background y offset
340 * @exception IllegalArgumentException <ul>
341 * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
342 * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li>
344 * @exception SWTException <ul>
345 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
346 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
351 public void drawBackground (GC gc, int x, int y, int width, int height, int offsetX, int offsetY) {
353 x = DPIUtil.autoScaleUp(x);
354 y = DPIUtil.autoScaleUp(y);
355 width = DPIUtil.autoScaleUp(width);
356 height = DPIUtil.autoScaleUp(height);
357 offsetX = DPIUtil.autoScaleUp(offsetX);
358 offsetY = DPIUtil.autoScaleUp(offsetY);
359 drawBackgroundInPixels(gc, x, y, width, height, offsetX, offsetY);
362 void drawBackgroundInPixels(GC gc, int x, int y, int width, int height, int offsetX, int offsetY) {
363 if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
364 if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
365 RECT rect = new RECT ();
366 OS.SetRect (rect, x, y, x + width, y + height);
367 long hDC = gc.handle;
368 int pixel = background == -1 ? gc.getBackground ().handle : -1;
369 drawBackground (hDC, rect, pixel, offsetX, offsetY);
372 Composite findDeferredControl () {
373 return layoutCount > 0 ? this : parent.findDeferredControl ();
377 Menu [] findMenus (Control control) {
378 if (control == this) return new Menu [0];
379 Menu result [] = super.findMenus (control);
380 Control [] children = _getChildren ();
381 for (int i=0; i<children.length; i++) {
382 Control child = children [i];
383 Menu [] menuList = child.findMenus (control);
384 if (menuList.length != 0) {
385 Menu [] newResult = new Menu [result.length + menuList.length];
386 System.arraycopy (result, 0, newResult, 0, result.length);
387 System.arraycopy (menuList, 0, newResult, result.length, menuList.length);
395 void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) {
396 super.fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
397 Control [] children = _getChildren ();
398 for (int i=0; i<children.length; i++) {
399 children [i].fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
403 void fixTabList (Control control) {
404 if (tabList == null) return;
406 for (int i=0; i<tabList.length; i++) {
407 if (tabList [i] == control) count++;
409 if (count == 0) return;
410 Control [] newList = null;
411 int length = tabList.length - count;
413 newList = new Control [length];
415 for (int i=0; i<tabList.length; i++) {
416 if (tabList [i] != control) {
417 newList [index++] = tabList [i];
425 * Returns the receiver's background drawing mode. This
426 * will be one of the following constants defined in class
428 * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>,
429 * <code>INHERIT_FORCE</code>.
431 * @return the background mode
433 * @exception SWTException <ul>
434 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
435 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
442 public int getBackgroundMode () {
444 return backgroundMode;
448 * Returns a (possibly empty) array containing the receiver's children.
449 * Children are returned in the order that they are drawn. The topmost
450 * control appears at the beginning of the array. Subsequent controls
451 * draw beneath this control and appear later in the array.
453 * Note: This is not the actual structure used by the receiver
454 * to maintain its list of children, so modifying the array will
455 * not affect the receiver.
458 * @return an array of children
460 * @see Control#moveAbove
461 * @see Control#moveBelow
463 * @exception SWTException <ul>
464 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
465 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
468 public Control [] getChildren () {
470 return _getChildren ();
473 int getChildrenCount () {
475 * NOTE: The current implementation will count
476 * non-registered children.
479 long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
480 while (hwndChild != 0) {
482 hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
488 * Returns layout which is associated with the receiver, or
489 * null if one has not been set.
491 * @return the receiver's layout or null
493 * @exception SWTException <ul>
494 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
495 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
498 public Layout getLayout () {
504 * Gets the (possibly empty) tabbing order for the control.
506 * @return tabList the ordered list of controls representing the tab order
508 * @exception SWTException <ul>
509 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
510 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
515 public Control [] getTabList () {
517 Control [] tabList = _getTabList ();
518 if (tabList == null) {
520 Control [] list =_getChildren ();
521 for (int i=0; i<list.length; i++) {
522 if (list [i].isTabGroup ()) count++;
524 tabList = new Control [count];
526 for (int i=0; i<list.length; i++) {
527 if (list [i].isTabGroup ()) {
528 tabList [index++] = list [i];
535 boolean hooksKeys () {
536 return hooks (SWT.KeyDown) || hooks (SWT.KeyUp);
540 * Returns <code>true</code> if the receiver has deferred
541 * the performing of layout, and <code>false</code> otherwise.
543 * @return the receiver's deferred layout state
545 * @exception SWTException <ul>
546 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
547 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
550 * @see #setLayoutDeferred(boolean)
551 * @see #isLayoutDeferred()
555 public boolean getLayoutDeferred () {
557 return layoutCount > 0 ;
561 * Returns <code>true</code> if the receiver or any ancestor
562 * up to and including the receiver's nearest ancestor shell
563 * has deferred the performing of layouts. Otherwise, <code>false</code>
566 * @return the receiver's deferred layout state
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>
573 * @see #setLayoutDeferred(boolean)
574 * @see #getLayoutDeferred()
578 public boolean isLayoutDeferred () {
580 return findDeferredControl () != null;
584 * If the receiver has a layout, asks the layout to <em>lay out</em>
585 * (that is, set the size and location of) the receiver's children.
586 * If the receiver does not have a layout, do nothing.
588 * Use of this method is discouraged since it is the least-efficient
589 * way to trigger a layout. The use of <code>layout(true)</code>
590 * discards all cached layout information, even from controls which
591 * have not changed. It is much more efficient to invoke
592 * {@link Control#requestLayout()} on every control which has changed
593 * in the layout than it is to invoke this method on the layout itself.
596 * This is equivalent to calling <code>layout(true)</code>.
599 * Note: Layout is different from painting. If a child is
600 * moved or resized such that an area in the parent is
601 * exposed, then the parent will paint. If no child is
602 * affected, the parent will not paint.
605 * @exception SWTException <ul>
606 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
607 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
610 public void layout () {
616 * If the receiver has a layout, asks the layout to <em>lay out</em>
617 * (that is, set the size and location of) the receiver's children.
618 * If the argument is <code>true</code> the layout must not rely
619 * on any information it has cached about the immediate children. If it
620 * is <code>false</code> the layout may (potentially) optimize the
621 * work it is doing by assuming that none of the receiver's
622 * children has changed state since the last layout.
623 * If the receiver does not have a layout, do nothing.
625 * It is normally more efficient to invoke {@link Control#requestLayout()}
626 * on every control which has changed in the layout than it is to invoke
627 * this method on the layout itself. Clients are encouraged to use
628 * {@link Control#requestLayout()} where possible instead of calling
632 * If a child is resized as a result of a call to layout, the
633 * resize event will invoke the layout of the child. The layout
634 * will cascade down through all child widgets in the receiver's widget
635 * tree until a child is encountered that does not resize. Note that
636 * a layout due to a resize will not flush any cached information
637 * (same as <code>layout(false)</code>).
640 * Note: Layout is different from painting. If a child is
641 * moved or resized such that an area in the parent is
642 * exposed, then the parent will paint. If no child is
643 * affected, the parent will not paint.
646 * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise
648 * @exception SWTException <ul>
649 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
650 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
653 public void layout (boolean changed) {
655 if (layout == null) return;
656 layout (changed, false);
660 * If the receiver has a layout, asks the layout to <em>lay out</em>
661 * (that is, set the size and location of) the receiver's children.
662 * If the changed argument is <code>true</code> the layout must not rely
663 * on any information it has cached about its children. If it
664 * is <code>false</code> the layout may (potentially) optimize the
665 * work it is doing by assuming that none of the receiver's
666 * children has changed state since the last layout.
667 * If the all argument is <code>true</code> the layout will cascade down
668 * through all child widgets in the receiver's widget tree, regardless of
669 * whether the child has changed size. The changed argument is applied to
670 * all layouts. If the all argument is <code>false</code>, the layout will
671 * <em>not</em> cascade down through all child widgets in the receiver's widget
672 * tree. However, if a child is resized as a result of a call to layout, the
673 * resize event will invoke the layout of the child. Note that
674 * a layout due to a resize will not flush any cached information
675 * (same as <code>layout(false)</code>).
677 * It is normally more efficient to invoke {@link Control#requestLayout()}
678 * on every control which has changed in the layout than it is to invoke
679 * this method on the layout itself. Clients are encouraged to use
680 * {@link Control#requestLayout()} where possible instead of calling
684 * Note: Layout is different from painting. If a child is
685 * moved or resized such that an area in the parent is
686 * exposed, then the parent will paint. If no child is
687 * affected, the parent will not paint.
690 * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise
691 * @param all <code>true</code> if all children in the receiver's widget tree should be laid out, and <code>false</code> otherwise
693 * @exception SWTException <ul>
694 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
695 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
700 public void layout (boolean changed, boolean all) {
702 if (layout == null && !all) return;
703 markLayout (changed, all);
708 * Forces a lay out (that is, sets the size and location) of all widgets that
709 * are in the parent hierarchy of the changed control up to and including the
710 * receiver. The layouts in the hierarchy must not rely on any information
711 * cached about the changed control or any of its ancestors. The layout may
712 * (potentially) optimize the work it is doing by assuming that none of the
713 * peers of the changed control have changed state since the last layout.
714 * If an ancestor does not have a layout, skip it.
716 * It is normally more efficient to invoke {@link Control#requestLayout()}
717 * on every control which has changed in the layout than it is to invoke
718 * this method on the layout itself. Clients are encouraged to use
719 * {@link Control#requestLayout()} where possible instead of calling
723 * Note: Layout is different from painting. If a child is
724 * moved or resized such that an area in the parent is
725 * exposed, then the parent will paint. If no child is
726 * affected, the parent will not paint.
729 * @param changed a control that has had a state change which requires a recalculation of its size
731 * @exception IllegalArgumentException <ul>
732 * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li>
733 * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li>
735 * @exception SWTException <ul>
736 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
737 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
742 public void layout (Control [] changed) {
744 if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
745 layout (changed, SWT.NONE);
749 * Forces a lay out (that is, sets the size and location) of all widgets that
750 * are in the parent hierarchy of the changed control up to and including the
753 * The parameter <code>flags</code> may be a combination of:
756 * <dt><b>SWT.ALL</b></dt>
757 * <dd>all children in the receiver's widget tree should be laid out</dd>
758 * <dt><b>SWT.CHANGED</b></dt>
759 * <dd>the layout must flush its caches</dd>
760 * <dt><b>SWT.DEFER</b></dt>
761 * <dd>layout will be deferred</dd>
764 * When the <code>changed</code> array is specified, the flags <code>SWT.ALL</code>
765 * and <code>SWT.CHANGED</code> have no effect. In this case, the layouts in the
766 * hierarchy must not rely on any information cached about the changed control or
767 * any of its ancestors. The layout may (potentially) optimize the
768 * work it is doing by assuming that none of the peers of the changed
769 * control have changed state since the last layout.
770 * If an ancestor does not have a layout, skip it.
773 * When the <code>changed</code> array is not specified, the flag <code>SWT.ALL</code>
774 * indicates that the whole widget tree should be laid out. And the flag
775 * <code>SWT.CHANGED</code> indicates that the layouts should flush any cached
776 * information for all controls that are laid out.
779 * The <code>SWT.DEFER</code> flag always causes the layout to be deferred by
780 * calling <code>Composite.setLayoutDeferred(true)</code> and scheduling a call
781 * to <code>Composite.setLayoutDeferred(false)</code>, which will happen when
782 * appropriate (usually before the next event is handled). When this flag is set,
783 * the application should not call <code>Composite.setLayoutDeferred(boolean)</code>.
786 * Note: Layout is different from painting. If a child is
787 * moved or resized such that an area in the parent is
788 * exposed, then the parent will paint. If no child is
789 * affected, the parent will not paint.
792 * @param changed a control that has had a state change which requires a recalculation of its size
793 * @param flags the flags specifying how the layout should happen
795 * @exception IllegalArgumentException <ul>
796 * <li>ERROR_INVALID_ARGUMENT - if any of the controls in changed is null or has been disposed</li>
797 * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li>
799 * @exception SWTException <ul>
800 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
801 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
806 public void layout (Control [] changed, int flags) {
808 if (changed != null) {
809 for (int i=0; i<changed.length; i++) {
810 Control control = changed [i];
811 if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
812 if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
813 boolean ancestor = false;
814 Composite composite = control.parent;
815 while (composite != null) {
816 ancestor = composite == this;
818 composite = composite.parent;
820 if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
823 Composite [] update = new Composite [16];
824 for (int i=0; i<changed.length; i++) {
825 Control child = changed [i];
826 Composite composite = child.parent;
827 // Update layout when the list of children has changed.
829 child.markLayout(false, false);
830 while (child != this) {
831 if (composite.layout != null) {
832 composite.state |= LAYOUT_NEEDED;
833 if (!composite.layout.flushCache (child)) {
834 composite.state |= LAYOUT_CHANGED;
837 if (updateCount == update.length) {
838 Composite [] newUpdate = new Composite [update.length + 16];
839 System.arraycopy (update, 0, newUpdate, 0, update.length);
842 child = update [updateCount++] = composite;
843 composite = child.parent;
846 if (!display.externalEventLoop && (flags & SWT.DEFER) != 0) {
847 setLayoutDeferred (true);
848 display.addLayoutDeferred (this);
850 for (int i=updateCount-1; i>=0; i--) {
851 update [i].updateLayout (false);
854 if (layout == null && (flags & SWT.ALL) == 0) return;
855 markLayout ((flags & SWT.CHANGED) != 0, (flags & SWT.ALL) != 0);
856 if (!display.externalEventLoop && (flags & SWT.DEFER) != 0) {
857 setLayoutDeferred (true);
858 display.addLayoutDeferred (this);
860 updateLayout ((flags & SWT.ALL) != 0);
865 void markLayout (boolean changed, boolean all) {
866 if (layout != null) {
867 state |= LAYOUT_NEEDED;
868 if (changed) state |= LAYOUT_CHANGED;
871 Control [] children = _getChildren ();
872 for (int i=0; i<children.length; i++) {
873 children [i].markLayout (changed, all);
878 Point minimumSize (int wHint, int hHint, boolean changed) {
879 Control [] children = _getChildren ();
881 * Since getClientArea can be overridden by subclasses, we cannot
882 * call getClientAreaInPixels directly.
884 Rectangle clientArea = DPIUtil.autoScaleUp(getClientArea ());
885 int width = 0, height = 0;
886 for (int i=0; i<children.length; i++) {
887 Rectangle rect = DPIUtil.autoScaleUp(children [i].getBounds ());
888 width = Math.max (width, rect.x - clientArea.x + rect.width);
889 height = Math.max (height, rect.y - clientArea.y + rect.height);
891 return new Point (width, height);
895 boolean redrawChildren () {
896 if (!super.redrawChildren ()) return false;
897 Control [] children = _getChildren ();
898 for (int i=0; i<children.length; i++) {
899 children [i].redrawChildren ();
905 void releaseParent () {
906 super.releaseParent ();
907 if ((state & CANVAS) != 0) {
908 if ((style & SWT.TRANSPARENT) != 0) {
909 long hwndParent = parent.handle;
910 long hwndChild = OS.GetWindow (hwndParent, OS.GW_CHILD);
911 while (hwndChild != 0) {
912 if (hwndChild != handle) {
913 int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
914 if ((bits & OS.WS_EX_TRANSPARENT) != 0) return;
916 hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
918 int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
919 bits &= ~OS.WS_EX_COMPOSITED;
920 OS.SetWindowLong (hwndParent, OS.GWL_EXSTYLE, bits);
926 void releaseChildren (boolean destroy) {
927 Control [] children = _getChildren ();
928 for (int i=0; i<children.length; i++) {
929 Control child = children [i];
930 if (child != null && !child.isDisposed ()) {
931 child.release (false);
934 super.releaseChildren (destroy);
938 void releaseWidget () {
939 super.releaseWidget ();
940 if ((state & CANVAS) != 0 && (style & SWT.EMBEDDED) != 0) {
941 long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
942 if (hwndChild != 0) {
943 int threadId = OS.GetWindowThreadProcessId (hwndChild, null);
944 if (threadId != OS.GetCurrentThreadId ()) {
945 OS.ShowWindow (hwndChild, OS.SW_HIDE);
946 OS.SetParent (hwndChild, 0);
955 void removeControl (Control control) {
956 fixTabList (control);
961 void reskinChildren (int flags) {
962 super.reskinChildren (flags);
963 Control [] children = _getChildren ();
964 for (int i=0; i<children.length; i++) {
965 Control child = children [i];
966 if (child != null) child.reskin (flags);
970 void resizeChildren () {
971 if (lpwp == null) return;
973 WINDOWPOS [] currentLpwp = lpwp;
975 if (!resizeChildren (true, currentLpwp)) {
976 resizeChildren (false, currentLpwp);
978 } while (lpwp != null);
981 boolean resizeChildren (boolean defer, WINDOWPOS [] pwp) {
982 if (pwp == null) return true;
985 hdwp = OS.BeginDeferWindowPos (pwp.length);
986 if (hdwp == 0) return false;
988 for (int i=0; i<pwp.length; i++) {
989 WINDOWPOS wp = pwp [i];
992 * This code is intentionally commented. All widgets that
993 * are created by SWT have WS_CLIPSIBLINGS to ensure that
994 * application code does not draw outside of the control.
996 // int count = parent.getChildrenCount ();
998 // int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
999 // if ((bits & OS.WS_CLIPSIBLINGS) == 0) wp.flags |= OS.SWP_NOCOPYBITS;
1002 hdwp = OS.DeferWindowPos (hdwp, wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
1003 if (hdwp == 0) return false;
1005 OS.SetWindowPos (wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
1009 if (defer) return OS.EndDeferWindowPos (hdwp);
1013 void resizeEmbeddedHandle(long embeddedHandle, int width, int height) {
1014 if (embeddedHandle == 0) return;
1015 int [] processID = new int [1];
1016 int threadId = OS.GetWindowThreadProcessId (embeddedHandle, processID);
1017 if (threadId != OS.GetCurrentThreadId ()) {
1018 if (processID [0] == OS.GetCurrentProcessId ()) {
1019 if (display.msgHook == 0) {
1020 display.getMsgCallback = new Callback (display, "getMsgProc", 3);
1021 display.getMsgProc = display.getMsgCallback.getAddress ();
1022 if (display.getMsgProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
1023 display.msgHook = OS.SetWindowsHookEx (OS.WH_GETMESSAGE, display.getMsgProc, OS.GetLibraryHandle(), threadId);
1024 OS.PostThreadMessage (threadId, OS.WM_NULL, 0, 0);
1027 int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE | OS.SWP_ASYNCWINDOWPOS;
1028 OS.SetWindowPos (embeddedHandle, 0, 0, 0, width, height, flags);
1033 void sendResize () {
1034 setResizeChildren (false);
1035 super.sendResize ();
1036 if (isDisposed ()) return;
1037 if (layout != null) {
1038 markLayout (false, false);
1039 updateLayout (false, false);
1041 setResizeChildren (true);
1045 * Sets the background drawing mode to the argument which should
1046 * be one of the following constants defined in class <code>SWT</code>:
1047 * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>,
1048 * <code>INHERIT_FORCE</code>.
1050 * @param mode the new background mode
1052 * @exception SWTException <ul>
1053 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1054 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1061 public void setBackgroundMode (int mode) {
1063 backgroundMode = mode;
1064 Control [] children = _getChildren ();
1065 for (int i = 0; i < children.length; i++) {
1066 children [i].updateBackgroundMode ();
1071 void setBoundsInPixels (int x, int y, int width, int height, int flags, boolean defer) {
1072 if (display.resizeCount > Display.RESIZE_LIMIT) {
1075 if (!defer && (state & CANVAS) != 0) {
1076 state &= ~(RESIZE_OCCURRED | MOVE_OCCURRED);
1077 state |= RESIZE_DEFERRED | MOVE_DEFERRED;
1079 super.setBoundsInPixels (x, y, width, height, flags, defer);
1080 if (!defer && (state & CANVAS) != 0) {
1081 boolean wasMoved = (state & MOVE_OCCURRED) != 0;
1082 boolean wasResized = (state & RESIZE_OCCURRED) != 0;
1083 state &= ~(RESIZE_DEFERRED | MOVE_DEFERRED);
1084 if (wasMoved && !isDisposed ()) sendMove ();
1085 if (wasResized && !isDisposed ()) sendResize ();
1090 public boolean setFocus () {
1092 Control [] children = _getChildren ();
1093 for (int i=0; i<children.length; i++) {
1094 Control child = children [i];
1095 if (child.setRadioFocus (false)) return true;
1097 for (int i=0; i<children.length; i++) {
1098 Control child = children [i];
1099 if (child.setFocus ()) return true;
1101 return super.setFocus ();
1105 * Sets the layout which is associated with the receiver to be
1106 * the argument which may be null.
1108 * @param layout the receiver's new layout or null
1110 * @exception SWTException <ul>
1111 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1112 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1115 public void setLayout (Layout layout) {
1117 this.layout = layout;
1121 * If the argument is <code>true</code>, causes subsequent layout
1122 * operations in the receiver or any of its children to be ignored.
1123 * No layout of any kind can occur in the receiver or any of its
1124 * children until the flag is set to false.
1125 * Layout operations that occurred while the flag was
1126 * <code>true</code> are remembered and when the flag is set to
1127 * <code>false</code>, the layout operations are performed in an
1128 * optimized manner. Nested calls to this method are stacked.
1130 * @param defer the new defer state
1132 * @exception SWTException <ul>
1133 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1134 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1137 * @see #layout(boolean)
1138 * @see #layout(Control[])
1142 public void setLayoutDeferred (boolean defer) {
1145 if (--layoutCount == 0) {
1146 if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) {
1147 updateLayout (true);
1155 * Sets the tabbing order for the specified controls to
1156 * match the order that they occur in the argument list.
1158 * @param tabList the ordered list of controls representing the tab order or null
1160 * @exception IllegalArgumentException <ul>
1161 * <li>ERROR_INVALID_ARGUMENT - if a widget in the tabList is null or has been disposed</li>
1162 * <li>ERROR_INVALID_PARENT - if widget in the tabList is not in the same widget tree</li>
1164 * @exception SWTException <ul>
1165 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1166 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1169 public void setTabList (Control [] tabList) {
1171 if (tabList != null) {
1172 for (int i=0; i<tabList.length; i++) {
1173 Control control = tabList [i];
1174 if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
1175 if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
1176 if (control.parent != this) error (SWT.ERROR_INVALID_PARENT);
1178 Control [] newList = new Control [tabList.length];
1179 System.arraycopy (tabList, 0, newList, 0, tabList.length);
1182 this.tabList = tabList;
1185 void setResizeChildren (boolean resize) {
1189 if (display.resizeCount > Display.RESIZE_LIMIT) {
1192 int count = getChildrenCount ();
1193 if (count > 1 && lpwp == null) {
1194 lpwp = new WINDOWPOS [count];
1200 boolean setTabGroupFocus () {
1201 if (isTabItem ()) return setTabItemFocus ();
1202 boolean takeFocus = (style & SWT.NO_FOCUS) == 0;
1203 if ((state & CANVAS) != 0) {
1204 takeFocus = hooksKeys ();
1205 if ((style & SWT.EMBEDDED) != 0) takeFocus = true;
1207 if (takeFocus && setTabItemFocus ()) return true;
1208 Control [] children = _getChildren ();
1209 for (int i=0; i<children.length; i++) {
1210 Control child = children [i];
1211 if (child.isTabItem () && child.setRadioFocus (true)) return true;
1213 for (int i=0; i<children.length; i++) {
1214 Control child = children [i];
1215 if (child.isTabItem () && !child.isTabGroup () && child.setTabItemFocus ()) {
1223 boolean updateTextDirection(int textDirection) {
1224 super.updateTextDirection (textDirection);
1226 * Always continue, communicating the direction to the children since
1227 * OS.WS_EX_RTLREADING doesn't propagate to them natively, and since
1228 * the direction might need to be handled by each child individually.
1230 Control[] children = _getChildren ();
1231 int i = children.length;
1233 if (children[i] != null && !children[i].isDisposed ()) {
1234 children[i].updateTextDirection(textDirection);
1238 * Return value indicates whether or not to update derivatives, so in case
1239 * of AUTO always return true regardless of the actual update.
1244 String toolTipText (NMTTDISPINFO hdr) {
1245 Shell shell = getShell ();
1246 if ((hdr.uFlags & OS.TTF_IDISHWND) == 0) {
1247 String string = null;
1248 ToolTip toolTip = shell.findToolTip ((int)hdr.idFrom);
1249 if (toolTip != null) {
1250 string = toolTip.message;
1251 if (string == null || string.length () == 0) string = " ";
1253 * Bug in Windows. On Windows 7, tool tips hang when displaying large
1254 * unwrapped strings. The fix is to wrap the string ourselves.
1256 if (string.length () > TOOLTIP_LIMIT / 4) {
1257 string = display.wrapText (string, handle, toolTip.getWidth ());
1262 shell.setToolTipTitle (hdr.hwndFrom, null, 0);
1263 OS.SendMessage (hdr.hwndFrom, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
1264 Control control = display.getControl (hdr.idFrom);
1265 return control != null ? control.toolTipText : null;
1269 boolean translateMnemonic (Event event, Control control) {
1270 if (super.translateMnemonic (event, control)) return true;
1271 if (control != null) {
1272 Control [] children = _getChildren ();
1273 for (int i=0; i<children.length; i++) {
1274 Control child = children [i];
1275 if (child.translateMnemonic (event, control)) return true;
1282 boolean translateTraversal (MSG msg) {
1283 if ((state & CANVAS) != 0 ) {
1284 if ((style & SWT.EMBEDDED) != 0) return false;
1285 switch ((int)msg.wParam) {
1292 int uiState = (int)OS.SendMessage (msg.hwnd, OS.WM_QUERYUISTATE, 0, 0);
1293 if ((uiState & OS.UISF_HIDEFOCUS) != 0) {
1294 OS.SendMessage (msg.hwnd, OS.WM_UPDATEUISTATE, OS.MAKEWPARAM (OS.UIS_CLEAR, OS.UISF_HIDEFOCUS), 0);
1299 return super.translateTraversal (msg);
1303 void updateBackgroundColor () {
1304 super.updateBackgroundColor ();
1305 Control [] children = _getChildren ();
1306 for (int i=0; i<children.length; i++) {
1307 if ((children [i].state & PARENT_BACKGROUND) != 0) {
1308 children [i].updateBackgroundColor ();
1314 void updateBackgroundImage () {
1315 super.updateBackgroundImage ();
1316 Control [] children = _getChildren ();
1317 for (int i=0; i<children.length; i++) {
1318 if ((children [i].state & PARENT_BACKGROUND) != 0) {
1319 children [i].updateBackgroundImage ();
1325 void updateBackgroundMode () {
1326 super.updateBackgroundMode ();
1327 Control [] children = _getChildren ();
1328 for (int i = 0; i < children.length; i++) {
1329 children [i].updateBackgroundMode ();
1334 void updateFont (Font oldFont, Font newFont) {
1335 super.updateFont (oldFont, newFont);
1336 Control [] children = _getChildren ();
1337 for (int i=0; i<children.length; i++) {
1338 Control control = children [i];
1339 if (!control.isDisposed ()) {
1340 control.updateFont (oldFont, newFont);
1345 void updateLayout (boolean all) {
1346 updateLayout (true, all);
1350 void updateLayout (boolean resize, boolean all) {
1351 Composite parent = findDeferredControl ();
1352 if (parent != null) {
1353 parent.state |= LAYOUT_CHILD;
1356 if ((state & LAYOUT_NEEDED) != 0) {
1357 boolean changed = (state & LAYOUT_CHANGED) != 0;
1358 state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED);
1360 if (resize) setResizeChildren (false);
1361 layout.layout (this, changed);
1362 if (resize) setResizeChildren (true);
1365 state &= ~LAYOUT_CHILD;
1366 Control [] children = _getChildren ();
1367 for (int i=0; i<children.length; i++) {
1368 children [i].updateLayout (resize, all);
1374 void updateOrientation () {
1375 Control [] controls = _getChildren ();
1376 RECT [] rects = new RECT [controls.length];
1377 for (int i=0; i<controls.length; i++) {
1378 Control control = controls [i];
1379 RECT rect = rects [i] = new RECT();
1380 control.forceResize ();
1381 OS.GetWindowRect (control.topHandle (), rect);
1382 OS.MapWindowPoints (0, handle, rect, 2);
1384 int orientation = style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
1385 super.updateOrientation ();
1386 for (int i=0; i<controls.length; i++) {
1387 Control control = controls [i];
1388 RECT rect = rects [i];
1389 control.setOrientation (orientation);
1390 int flags = OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;
1391 OS.SetWindowPos (control.topHandle (), 0, rect.left, rect.top, 0, 0, flags);
1395 void updateUIState () {
1396 long hwndShell = getShell ().handle;
1397 int uiState = (int)OS.SendMessage (hwndShell, OS.WM_QUERYUISTATE, 0, 0);
1398 if ((uiState & OS.UISF_HIDEFOCUS) != 0) {
1399 OS.SendMessage (hwndShell, OS.WM_CHANGEUISTATE, OS.MAKEWPARAM (OS.UIS_CLEAR, OS.UISF_HIDEFOCUS), 0);
1404 int widgetStyle () {
1405 /* Force clipping of children by setting WS_CLIPCHILDREN */
1406 return super.widgetStyle () | OS.WS_CLIPCHILDREN;
1410 LRESULT WM_ERASEBKGND (long wParam, long lParam) {
1411 LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
1412 if (result != null) return result;
1413 if ((state & CANVAS) != 0) {
1414 /* Return zero to indicate that the background was not erased */
1415 if ((style & (SWT.NO_BACKGROUND | SWT.TRANSPARENT)) != 0) {
1416 return LRESULT.ZERO;
1423 LRESULT WM_GETDLGCODE (long wParam, long lParam) {
1424 LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
1425 if (result != null) return result;
1426 if ((state & CANVAS) != 0) {
1429 flags |= OS.DLGC_WANTALLKEYS | OS.DLGC_WANTARROWS | OS.DLGC_WANTTAB;
1431 if ((style & SWT.NO_FOCUS) != 0) flags |= OS.DLGC_STATIC;
1432 if (OS.GetWindow (handle, OS.GW_CHILD) != 0) flags |= OS.DLGC_STATIC;
1433 if (flags != 0) return new LRESULT (flags);
1439 LRESULT WM_GETFONT (long wParam, long lParam) {
1440 LRESULT result = super.WM_GETFONT (wParam, lParam);
1441 if (result != null) return result;
1442 long code = callWindowProc (handle, OS.WM_GETFONT, wParam, lParam);
1443 if (code != 0) return new LRESULT (code);
1444 return new LRESULT (font != null ? font.handle : defaultFont ());
1448 LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
1449 LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
1450 if (result == LRESULT.ZERO) return result;
1452 /* Set focus for a canvas with no children */
1453 if ((state & CANVAS) != 0) {
1454 if ((style & SWT.NO_FOCUS) == 0 && hooksKeys ()) {
1455 if (OS.GetWindow (handle, OS.GW_CHILD) == 0) setFocus ();
1462 LRESULT WM_NCHITTEST (long wParam, long lParam) {
1463 LRESULT result = super.WM_NCHITTEST (wParam, lParam);
1464 if (result != null) return result;
1466 * Bug in Windows. For some reason, under circumstances
1467 * that are not understood, when one scrolled window is
1468 * embedded in another and the outer window scrolls the
1469 * inner horizontally by moving the location of the inner
1470 * one, the vertical scroll bars of the inner window no
1471 * longer function. Specifically, WM_NCHITTEST returns
1472 * HTCLIENT instead of HTVSCROLL. The fix is to detect
1473 * the case where the result of WM_NCHITTEST is HTCLIENT
1474 * and the point is not in the client area, and redraw
1475 * the trim, which somehow fixes the next WM_NCHITTEST.
1477 if (OS.IsAppThemed ()) {
1478 if ((state & CANVAS)!= 0) {
1479 long code = callWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam);
1480 if (code == OS.HTCLIENT) {
1481 RECT rect = new RECT ();
1482 OS.GetClientRect (handle, rect);
1483 POINT pt = new POINT ();
1484 pt.x = OS.GET_X_LPARAM (lParam);
1485 pt.y = OS.GET_Y_LPARAM (lParam);
1486 OS.MapWindowPoints (0, handle, pt, 1);
1487 if (!OS.PtInRect (rect, pt)) {
1488 int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE;
1489 OS.RedrawWindow (handle, null, 0, flags);
1492 return new LRESULT (code);
1499 LRESULT WM_PARENTNOTIFY (long wParam, long lParam) {
1500 if ((state & CANVAS) != 0 && (style & SWT.EMBEDDED) != 0) {
1501 if (OS.LOWORD (wParam) == OS.WM_CREATE) {
1502 RECT rect = new RECT ();
1503 OS.GetClientRect (handle, rect);
1504 resizeEmbeddedHandle (lParam, rect.right - rect.left, rect.bottom - rect.top);
1507 return super.WM_PARENTNOTIFY (wParam, lParam);
1511 LRESULT WM_PAINT (long wParam, long lParam) {
1512 if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
1513 if ((state & CANVAS) == 0 || (state & FOREIGN_HANDLE) != 0) {
1514 return super.WM_PAINT (wParam, lParam);
1517 /* Set the clipping bits */
1518 int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1519 int newBits = oldBits | OS.WS_CLIPSIBLINGS | OS.WS_CLIPCHILDREN;
1520 if (newBits != oldBits) OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
1522 /* Paint the control and the background */
1523 PAINTSTRUCT ps = new PAINTSTRUCT ();
1524 if (hooks (SWT.Paint) || filters (SWT.Paint)) {
1526 /* Use the buffered paint when possible */
1527 boolean bufferedPaint = false;
1528 if ((style & SWT.DOUBLE_BUFFERED) != 0) {
1529 if ((style & (SWT.NO_MERGE_PAINTS | SWT.RIGHT_TO_LEFT | SWT.TRANSPARENT)) == 0) {
1530 bufferedPaint = true;
1533 if (bufferedPaint) {
1534 long hDC = OS.BeginPaint (handle, ps);
1535 int width = ps.right - ps.left;
1536 int height = ps.bottom - ps.top;
1537 if (width != 0 && height != 0) {
1538 long [] phdc = new long [1];
1539 int flags = OS.BPBF_COMPATIBLEBITMAP;
1540 RECT prcTarget = new RECT ();
1541 OS.SetRect (prcTarget, ps.left, ps.top, ps.right, ps.bottom);
1542 long hBufferedPaint = OS.BeginBufferedPaint (hDC, prcTarget, flags, null, phdc);
1543 GCData data = new GCData ();
1544 data.device = display;
1545 data.foreground = getForegroundPixel ();
1546 Control control = findBackgroundControl ();
1547 if (control == null) control = this;
1548 data.background = control.getBackgroundPixel ();
1549 data.font = Font.win32_new(display, OS.SendMessage (handle, OS.WM_GETFONT, 0, 0));
1550 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1551 if ((style & SWT.NO_BACKGROUND) != 0) {
1552 /* This code is intentionally commented because it may be slow to copy bits from the screen */
1553 //paintGC.copyArea (image, ps.left, ps.top);
1555 RECT rect = new RECT ();
1556 OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1557 drawBackground (phdc [0], rect);
1559 GC gc = GC.win32_new (phdc [0], data);
1560 Event event = new Event ();
1562 event.setBoundsInPixels(new Rectangle(ps.left, ps.top, width, height));
1563 sendEvent (SWT.Paint, event);
1564 if (data.focusDrawn && !isDisposed ()) updateUIState ();
1566 OS.EndBufferedPaint (hBufferedPaint, true);
1568 OS.EndPaint (handle, ps);
1571 /* Create the paint GC */
1572 GCData data = new GCData ();
1575 GC gc = GC.win32_new (this, data);
1577 /* Get the system region for the paint HDC */
1579 if ((style & (SWT.DOUBLE_BUFFERED | SWT.TRANSPARENT)) != 0 || (style & SWT.NO_MERGE_PAINTS) != 0) {
1580 sysRgn = OS.CreateRectRgn (0, 0, 0, 0);
1581 if (OS.GetRandomRgn (gc.handle, sysRgn, OS.SYSRGN) == 1) {
1582 if ((OS.GetLayout (gc.handle) & OS.LAYOUT_RTL) != 0) {
1583 int nBytes = OS.GetRegionData (sysRgn, 0, null);
1584 int [] lpRgnData = new int [nBytes / 4];
1585 OS.GetRegionData (sysRgn, nBytes, lpRgnData);
1586 long newSysRgn = OS.ExtCreateRegion (new float [] {-1, 0, 0, 1, 0, 0}, nBytes, lpRgnData);
1587 OS.DeleteObject (sysRgn);
1590 POINT pt = new POINT();
1591 OS.MapWindowPoints (0, handle, pt, 1);
1592 OS.OffsetRgn (sysRgn, pt.x, pt.y);
1596 /* Send the paint event */
1597 int width = ps.right - ps.left;
1598 int height = ps.bottom - ps.top;
1599 if (width != 0 && height != 0) {
1602 if ((style & (SWT.DOUBLE_BUFFERED | SWT.TRANSPARENT)) != 0) {
1603 image = new Image (display, width, height);
1605 gc = new GC (image, paintGC.getStyle() & SWT.RIGHT_TO_LEFT);
1606 GCData gcData = gc.getGCData ();
1607 gcData.uiState = data.uiState;
1608 gc.setForeground (getForeground ());
1609 gc.setBackground (getBackground ());
1610 gc.setFont (getFont ());
1611 if ((style & SWT.TRANSPARENT) != 0) {
1612 OS.BitBlt (gc.handle, 0, 0, width, height, paintGC.handle, ps.left, ps.top, OS.SRCCOPY);
1614 OS.OffsetRgn (sysRgn, -ps.left, -ps.top);
1615 OS.SelectClipRgn (gc.handle, sysRgn);
1616 OS.OffsetRgn (sysRgn, ps.left, ps.top);
1617 OS.SetMetaRgn (gc.handle);
1618 OS.SetWindowOrgEx (gc.handle, ps.left, ps.top, null);
1619 OS.SetBrushOrgEx (gc.handle, ps.left, ps.top, null);
1620 if ((style & (SWT.NO_BACKGROUND | SWT.TRANSPARENT)) != 0) {
1621 /* This code is intentionally commented because it may be slow to copy bits from the screen */
1622 //paintGC.copyArea (image, ps.left, ps.top);
1624 RECT rect = new RECT ();
1625 OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1626 drawBackground (gc.handle, rect);
1629 Event event = new Event ();
1632 if ((style & SWT.NO_MERGE_PAINTS) != 0 && OS.GetRgnBox (sysRgn, rect = new RECT ()) == OS.COMPLEXREGION) {
1633 int nBytes = OS.GetRegionData (sysRgn, 0, null);
1634 int [] lpRgnData = new int [nBytes / 4];
1635 OS.GetRegionData (sysRgn, nBytes, lpRgnData);
1636 int count = lpRgnData [2];
1637 for (int i=0; i<count; i++) {
1638 int offset = 8 + (i << 2);
1639 OS.SetRect (rect, lpRgnData [offset], lpRgnData [offset + 1], lpRgnData [offset + 2], lpRgnData [offset + 3]);
1640 if ((style & (SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.TRANSPARENT)) == 0) {
1641 drawBackground (gc.handle, rect);
1643 event.setBoundsInPixels(new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top));
1644 event.count = count - 1 - i;
1645 sendEvent (SWT.Paint, event);
1648 if ((style & (SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.TRANSPARENT)) == 0) {
1649 if (rect == null) rect = new RECT ();
1650 OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1651 drawBackground (gc.handle, rect);
1653 event.setBoundsInPixels(new Rectangle(ps.left, ps.top, width, height));
1654 sendEvent (SWT.Paint, event);
1656 // widget could be disposed at this point
1658 if ((style & (SWT.DOUBLE_BUFFERED | SWT.TRANSPARENT)) != 0) {
1659 if (!gc.isDisposed ()) {
1660 GCData gcData = gc.getGCData ();
1661 if (gcData.focusDrawn && !isDisposed ()) updateUIState ();
1664 if (!isDisposed ()) paintGC.drawImage (image, DPIUtil.autoScaleDown(ps.left), DPIUtil.autoScaleDown(ps.top));
1669 if (sysRgn != 0) OS.DeleteObject (sysRgn);
1670 if (data.focusDrawn && !isDisposed ()) updateUIState ();
1672 /* Dispose the paint GC */
1676 long hDC = OS.BeginPaint (handle, ps);
1677 if ((style & (SWT.NO_BACKGROUND | SWT.TRANSPARENT)) == 0) {
1678 RECT rect = new RECT ();
1679 OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1680 drawBackground (hDC, rect);
1682 OS.EndPaint (handle, ps);
1685 /* Restore the clipping bits */
1686 if (!isDisposed ()) {
1687 if (newBits != oldBits) {
1689 * It is possible (but unlikely), that application
1690 * code could have disposed the widget in the paint
1691 * event. If this happens, don't attempt to restore
1694 if (!isDisposed ()) {
1695 OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits);
1699 return LRESULT.ZERO;
1703 LRESULT WM_PRINTCLIENT (long wParam, long lParam) {
1704 LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
1705 if (result != null) return result;
1706 if ((state & CANVAS) != 0) {
1708 int nSavedDC = OS.SaveDC (wParam);
1709 RECT rect = new RECT ();
1710 OS.GetClientRect (handle, rect);
1711 if ((style & (SWT.NO_BACKGROUND | SWT.TRANSPARENT)) == 0) {
1712 drawBackground (wParam, rect);
1714 if (hooks (SWT.Paint) || filters (SWT.Paint)) {
1715 GCData data = new GCData ();
1716 data.device = display;
1717 data.foreground = getForegroundPixel ();
1718 Control control = findBackgroundControl ();
1719 if (control == null) control = this;
1720 data.background = control.getBackgroundPixel ();
1721 data.font = Font.win32_new(display, OS.SendMessage (handle, OS.WM_GETFONT, 0, 0));
1722 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1723 GC gc = GC.win32_new (wParam, data);
1724 Event event = new Event ();
1726 event.setBoundsInPixels(new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top));
1727 sendEvent (SWT.Paint, event);
1731 OS.RestoreDC (wParam, nSavedDC);
1737 LRESULT WM_SETFONT (long wParam, long lParam) {
1738 if (lParam != 0) OS.InvalidateRect (handle, null, true);
1739 return super.WM_SETFONT (wParam, lParam);
1743 LRESULT WM_SIZE (long wParam, long lParam) {
1744 LRESULT result = null;
1745 if ((state & RESIZE_DEFERRED) != 0) {
1746 result = super.WM_SIZE (wParam, lParam);
1748 /* Begin deferred window positioning */
1749 setResizeChildren (false);
1751 /* Resize and Layout */
1752 result = super.WM_SIZE (wParam, lParam);
1754 * It is possible (but unlikely), that application
1755 * code could have disposed the widget in the resize
1756 * event. If this happens, end the processing of the
1757 * Windows message by returning the result of the
1760 if (isDisposed ()) return result;
1761 if (layout != null) {
1762 markLayout (false, false);
1763 updateLayout (false, false);
1766 /* End deferred window positioning */
1767 setResizeChildren (true);
1770 /* Damage the widget to cause a repaint */
1771 if (OS.IsWindowVisible (handle)) {
1772 if ((state & CANVAS) != 0) {
1773 if ((style & SWT.NO_REDRAW_RESIZE) == 0) {
1774 if (hooks (SWT.Paint)) {
1775 OS.InvalidateRect (handle, null, true);
1779 if (OS.IsAppThemed ()) {
1780 if (findThemeControl () != null) redrawChildren ();
1784 /* Resize the embedded window */
1785 if ((state & CANVAS) != 0 && (style & SWT.EMBEDDED) != 0) {
1786 resizeEmbeddedHandle (OS.GetWindow (handle, OS.GW_CHILD), OS.LOWORD (lParam), OS.HIWORD (lParam));
1792 LRESULT WM_SYSCOLORCHANGE (long wParam, long lParam) {
1793 LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
1794 if (result != null) return result;
1795 long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
1796 while (hwndChild != 0) {
1797 OS.SendMessage (hwndChild, OS.WM_SYSCOLORCHANGE, 0, 0);
1798 hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
1804 LRESULT WM_SYSCOMMAND (long wParam, long lParam) {
1805 LRESULT result = super.WM_SYSCOMMAND (wParam, lParam);
1806 if (result != null) return result;
1809 * Check to see if the command is a system command or
1810 * a user menu item that was added to the system menu.
1812 * NOTE: This is undocumented.
1814 if ((wParam & 0xF000) == 0) return result;
1817 * Bug in Windows. When a vertical or horizontal scroll bar is
1818 * hidden or shown while the opposite scroll bar is being scrolled
1819 * by the user (with WM_HSCROLL code SB_LINEDOWN), the scroll bar
1820 * does not redraw properly. The fix is to detect this case and
1821 * redraw the non-client area.
1823 int cmd = (int)wParam & 0xFFF0;
1827 boolean showHBar = horizontalBar != null && horizontalBar.getVisible ();
1828 boolean showVBar = verticalBar != null && verticalBar.getVisible ();
1829 long code = callWindowProc (handle, OS.WM_SYSCOMMAND, wParam, lParam);
1830 if ((showHBar != (horizontalBar != null && horizontalBar.getVisible ())) ||
1831 (showVBar != (verticalBar != null && verticalBar.getVisible ()))) {
1832 int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_UPDATENOW;
1833 OS.RedrawWindow (handle, null, 0, flags);
1835 if (code == 0) return LRESULT.ZERO;
1836 return new LRESULT (code);
1839 /* Return the result */
1844 LRESULT WM_UPDATEUISTATE (long wParam, long lParam) {
1845 LRESULT result = super.WM_UPDATEUISTATE (wParam, lParam);
1846 if (result != null) return result;
1847 if ((state & CANVAS) != 0 && hooks (SWT.Paint)) {
1848 OS.InvalidateRect (handle, null, true);
1854 LRESULT wmNCPaint (long hwnd, long wParam, long lParam) {
1855 LRESULT result = super.wmNCPaint (hwnd, wParam, lParam);
1856 if (result != null) return result;
1857 long borderHandle = borderHandle ();
1858 if ((state & CANVAS) != 0 || (hwnd == borderHandle && handle != borderHandle)) {
1859 if (OS.IsAppThemed ()) {
1860 int bits1 = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE);
1861 if ((bits1 & OS.WS_EX_CLIENTEDGE) != 0) {
1863 int bits2 = OS.GetWindowLong (hwnd, OS.GWL_STYLE);
1864 if ((bits2 & (OS.WS_HSCROLL | OS.WS_VSCROLL)) != 0) {
1865 code = callWindowProc (hwnd, OS.WM_NCPAINT, wParam, lParam);
1867 long hDC = OS.GetWindowDC (hwnd);
1868 RECT rect = new RECT ();
1869 OS.GetWindowRect (hwnd, rect);
1870 rect.right -= rect.left;
1871 rect.bottom -= rect.top;
1872 rect.left = rect.top = 0;
1873 int border = OS.GetSystemMetrics (OS.SM_CXEDGE);
1874 OS.ExcludeClipRect (hDC, border, border, rect.right - border, rect.bottom - border);
1875 OS.DrawThemeBackground (display.hEditTheme (), hDC, OS.EP_EDITTEXT, OS.ETS_NORMAL, rect, null);
1876 OS.ReleaseDC (hwnd, hDC);
1877 return new LRESULT (code);
1885 LRESULT wmNotify (NMHDR hdr, long wParam, long lParam) {
1888 * Feature in Windows. When the tool tip control is
1889 * created, the parent of the tool tip is the shell.
1890 * If SetParent () is used to reparent the tool bar
1891 * into a new shell, the tool tip is not reparented
1892 * and pops up underneath the new shell. The fix is
1893 * to make sure the tool tip is a topmost window.
1898 * Bug in Windows 98 and NT. Setting the tool tip to be the
1899 * top most window using HWND_TOPMOST can result in a parent
1900 * dialog shell being moved behind its parent if the dialog
1901 * has a sibling that is currently on top. The fix is to
1902 * lock the z-order of the active window.
1904 * Feature in Windows. Using SetWindowPos() with HWND_NOTOPMOST
1905 * to clear the topmost state of a window whose parent is already
1906 * topmost clears the topmost state of the parent. The fix is to
1907 * check if the parent is already on top and neither set or clear
1908 * the topmost status of the tool tip.
1910 long hwndParent = hdr.hwndFrom;
1912 hwndParent = OS.GetParent (hwndParent);
1913 if (hwndParent == 0) break;
1914 int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
1915 if ((bits & OS.WS_EX_TOPMOST) != 0) break;
1917 if (hwndParent != 0) break;
1919 * Bug in Windows. TTN_SHOW is sent for inactive shells. When
1920 * SetWindowPos is called as a reaction, inactive shells can
1921 * wrongly end up on top. The fix is to swallow such requests.
1923 * A visible effect is that spurious tool tips can show up and
1924 * disappear in a split second. This is a mostly harmless
1925 * feature that can also be observed in the Windows Explorer.
1926 * See bug 491627 for more details.
1928 if (display.getActiveShell () == null) return LRESULT.ONE;
1930 display.lockActiveWindow = true;
1931 int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOSIZE;
1932 long hwndInsertAfter = hdr.code == OS.TTN_SHOW ? OS.HWND_TOPMOST : OS.HWND_NOTOPMOST;
1933 OS.SetWindowPos (hdr.hwndFrom, hwndInsertAfter, 0, 0, 0, 0, flags);
1934 display.lockActiveWindow = false;
1937 case OS.TTN_GETDISPINFO: {
1938 NMTTDISPINFO lpnmtdi = new NMTTDISPINFO ();
1939 OS.MoveMemory (lpnmtdi, lParam, NMTTDISPINFO.sizeof);
1940 String string = toolTipText (lpnmtdi);
1941 if (string != null) {
1942 Shell shell = getShell ();
1943 string = Display.withCrLf (string);
1945 * Bug in Windows. On Windows 7, tool tips hang when displaying large
1946 * strings. The fix is to limit the tool tip string to 4Kb.
1948 if (string.length() > TOOLTIP_LIMIT) {
1949 string = string.substring(0, TOOLTIP_LIMIT);
1952 * Bug 475858: In Japanese like languages where mnemonics are not taken from the
1953 * source label text but appended in parentheses like "(&M)" at end. In order to
1954 * allow the reuse of such label text as a tool-tip text as well, "(&M)" like
1955 * character sequence has to be removed from the end of CJK-style mnemonics.
1957 char [] chars = fixMnemonic (string, false, true);
1960 * Ensure that the orientation of the tool tip matches
1961 * the orientation of the control.
1963 Widget widget = null;
1964 long hwnd = hdr.idFrom;
1965 if ((lpnmtdi.uFlags & OS.TTF_IDISHWND) != 0) {
1966 widget = display.getControl (hwnd);
1968 if (hdr.hwndFrom == shell.toolTipHandle || hdr.hwndFrom == shell.balloonTipHandle) {
1969 widget = shell.findToolTip ((int)hdr.idFrom);
1972 if (widget != null) {
1973 int style = widget.getStyle();
1974 int flags = SWT.RIGHT_TO_LEFT | SWT.FLIP_TEXT_DIRECTION;
1975 if ((style & flags) != 0 && (style & flags) != flags) {
1976 lpnmtdi.uFlags |= OS.TTF_RTLREADING;
1978 lpnmtdi.uFlags &= ~OS.TTF_RTLREADING;
1981 shell.setToolTipText (lpnmtdi, chars);
1982 OS.MoveMemory (lParam, lpnmtdi, NMTTDISPINFO.sizeof);
1983 return LRESULT.ZERO;
1988 return super.wmNotify (hdr, wParam, lParam);