KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > widgets > Composite


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  *******************************************************************************/

11 package org.eclipse.swt.widgets;
12
13
14 import org.eclipse.swt.internal.*;
15 import org.eclipse.swt.internal.win32.*;
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.graphics.*;
18
19 /**
20  * Instances of this class are controls which are capable
21  * of containing other controls.
22  * <dl>
23  * <dt><b>Styles:</b></dt>
24  * <dd>NO_BACKGROUND, NO_FOCUS, NO_MERGE_PAINTS, NO_REDRAW_RESIZE, NO_RADIO_GROUP, EMBEDDED, DOUBLE_BUFFERED</dd>
25  * <dt><b>Events:</b></dt>
26  * <dd>(none)</dd>
27  * </dl>
28  * <p>
29  * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, <code>NO_MERGE_PAINTS</code>,
30  * and <code>NO_REDRAW_RESIZE</code> styles are intended for use with <code>Canvas</code>.
31  * They can be used with <code>Composite</code> if you are drawing your own, but their
32  * behavior is undefined if they are used with subclasses of <code>Composite</code> other
33  * than <code>Canvas</code>.
34  * </p><p>
35  * Note: The <code>CENTER</code> style, although undefined for composites, has the
36  * same value as <code>EMBEDDED</code> (which is used to embed widgets from other
37  * widget toolkits into SWT). On some operating systems (GTK, Motif), this may cause
38  * the children of this composite to be obscured. The <code>EMBEDDED</code> style
39  * is for use by other widget toolkits and should normally never be used.
40  * </p><p>
41  * This class may be subclassed by custom control implementors
42  * who are building controls that are constructed from aggregates
43  * of other controls.
44  * </p>
45  *
46  * @see Canvas
47  */

48
49 public class Composite extends Scrollable {
50     Layout layout;
51     int font;
52     WINDOWPOS [] lpwp;
53     Control [] tabList;
54     int layoutCount, backgroundMode;
55
56 /**
57  * Prevents uninitialized instances from being created outside the package.
58  */

59 Composite () {
60 }
61
62 /**
63  * Constructs a new instance of this class given its parent
64  * and a style value describing its behavior and appearance.
65  * <p>
66  * The style value is either one of the style constants defined in
67  * class <code>SWT</code> which is applicable to instances of this
68  * class, or must be built by <em>bitwise OR</em>'ing together
69  * (that is, using the <code>int</code> "|" operator) two or more
70  * of those <code>SWT</code> style constants. The class description
71  * lists the style constants that are applicable to the class.
72  * Style bits are also inherited from superclasses.
73  * </p>
74  *
75  * @param parent a widget which will be the parent of the new instance (cannot be null)
76  * @param style the style of widget to construct
77  *
78  * @exception IllegalArgumentException <ul>
79  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
80  * </ul>
81  * @exception SWTException <ul>
82  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
83  * </ul>
84  *
85  * @see SWT#NO_BACKGROUND
86  * @see SWT#NO_FOCUS
87  * @see SWT#NO_MERGE_PAINTS
88  * @see SWT#NO_REDRAW_RESIZE
89  * @see SWT#NO_RADIO_GROUP
90  * @see Widget#getStyle
91  */

92 public Composite (Composite parent, int style) {
93     super (parent, style);
94 }
95
96 Control [] _getChildren () {
97     int count = 0;
98     int hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
99     if (hwndChild == 0) return new Control [0];
100     while (hwndChild != 0) {
101         count++;
102         hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
103     }
104     Control [] children = new Control [count];
105     int index = 0;
106     hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
107     while (hwndChild != 0) {
108         Control control = display.getControl (hwndChild);
109         if (control != null && control != this) {
110             children [index++] = control;
111         }
112         hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
113     }
114     if (count == index) return children;
115     Control [] newChildren = new Control [index];
116     System.arraycopy (children, 0, newChildren, 0, index);
117     return newChildren;
118 }
119
120 Control [] _getTabList () {
121     if (tabList == null) return tabList;
122     int count = 0;
123     for (int i=0; i<tabList.length; i++) {
124         if (!tabList [i].isDisposed ()) count++;
125     }
126     if (count == tabList.length) return tabList;
127     Control [] newList = new Control [count];
128     int index = 0;
129     for (int i=0; i<tabList.length; i++) {
130         if (!tabList [i].isDisposed ()) {
131             newList [index++] = tabList [i];
132         }
133     }
134     tabList = newList;
135     return tabList;
136 }
137
138 /**
139  * Clears any data that has been cached by a Layout for all widgets that
140  * are in the parent hierarchy of the changed control up to and including the
141  * receiver. If an ancestor does not have a layout, it is skipped.
142  *
143  * @param changed an array of controls that changed state and require a recalculation of size
144  *
145  * @exception IllegalArgumentException <ul>
146  * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li>
147  * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li>
148  * </ul>
149  * @exception SWTException <ul>
150  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
151  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
152  * </ul>
153  *
154  * @since 3.1
155  */

156 public void changed (Control[] changed) {
157     checkWidget ();
158     if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
159     for (int i=0; i<changed.length; i++) {
160         Control control = changed [i];
161         if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
162         if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
163         boolean ancestor = false;
164         Composite composite = control.parent;
165         while (composite != null) {
166             ancestor = composite == this;
167             if (ancestor) break;
168             composite = composite.parent;
169         }
170         if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
171     }
172     for (int i=0; i<changed.length; i++) {
173         Control child = changed [i];
174         Composite composite = child.parent;
175         while (child != this) {
176             if (composite.layout == null || !composite.layout.flushCache (child)) {
177                 composite.state |= LAYOUT_CHANGED;
178             }
179             child = composite;
180             composite = child.parent;
181         }
182     }
183 }
184
185 void checkBuffered () {
186     if (OS.IsWinCE || (state & CANVAS) == 0) {
187         super.checkBuffered ();
188     }
189 }
190
191 protected void checkSubclass () {
192     /* Do nothing - Subclassing is allowed */
193 }
194
195 Control [] computeTabList () {
196     Control result [] = super.computeTabList ();
197     if (result.length == 0) return result;
198     Control [] list = tabList != null ? _getTabList () : _getChildren ();
199     for (int i=0; i<list.length; i++) {
200         Control child = list [i];
201         Control [] childList = child.computeTabList ();
202         if (childList.length != 0) {
203             Control [] newResult = new Control [result.length + childList.length];
204             System.arraycopy (result, 0, newResult, 0, result.length);
205             System.arraycopy (childList, 0, newResult, result.length, childList.length);
206             result = newResult;
207         }
208     }
209     return result;
210 }
211
212 public Point computeSize (int wHint, int hHint, boolean changed) {
213     checkWidget ();
214     Point size;
215     if (layout != null) {
216         if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
217             changed |= (state & LAYOUT_CHANGED) != 0;
218             state &= ~LAYOUT_CHANGED;
219             size = layout.computeSize (this, wHint, hHint, changed);
220         } else {
221             size = new Point (wHint, hHint);
222         }
223     } else {
224         size = minimumSize (wHint, hHint, changed);
225     }
226     if (size.x == 0) size.x = DEFAULT_WIDTH;
227     if (size.y == 0) size.y = DEFAULT_HEIGHT;
228     if (wHint != SWT.DEFAULT) size.x = wHint;
229     if (hHint != SWT.DEFAULT) size.y = hHint;
230     Rectangle trim = computeTrim (0, 0, size.x, size.y);
231     return new Point (trim.width, trim.height);
232 }
233
234 void createHandle () {
235     super.createHandle ();
236     state |= CANVAS;
237     if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
238         state |= THEME_BACKGROUND;
239     }
240 }
241
242 Composite findDeferredControl () {
243     return layoutCount > 0 ? this : parent.findDeferredControl ();
244 }
245
246 Menu [] findMenus (Control control) {
247     if (control == this) return new Menu [0];
248     Menu result [] = super.findMenus (control);
249     Control [] children = _getChildren ();
250     for (int i=0; i<children.length; i++) {
251         Control child = children [i];
252         Menu [] menuList = child.findMenus (control);
253         if (menuList.length != 0) {
254             Menu [] newResult = new Menu [result.length + menuList.length];
255             System.arraycopy (result, 0, newResult, 0, result.length);
256             System.arraycopy (menuList, 0, newResult, result.length, menuList.length);
257             result = newResult;
258         }
259     }
260     return result;
261 }
262
263 void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) {
264     super.fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
265     Control [] children = _getChildren ();
266     for (int i=0; i<children.length; i++) {
267         children [i].fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
268     }
269 }
270
271 void fixTabList (Control control) {
272     if (tabList == null) return;
273     int count = 0;
274     for (int i=0; i<tabList.length; i++) {
275         if (tabList [i] == control) count++;
276     }
277     if (count == 0) return;
278     Control [] newList = null;
279     int length = tabList.length - count;
280     if (length != 0) {
281         newList = new Control [length];
282         int index = 0;
283         for (int i=0; i<tabList.length; i++) {
284             if (tabList [i] != control) {
285                 newList [index++] = tabList [i];
286             }
287         }
288     }
289     tabList = newList;
290 }
291
292 /**
293  * Returns the receiver's background drawing mode. This
294  * will be one of the following constants defined in class
295  * <code>SWT</code>:
296  * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>,
297  * <code>INHERTIT_FORCE</code>.
298  *
299  * @return the background mode
300  *
301  * @exception SWTException <ul>
302  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
303  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
304  * </ul>
305  *
306  * @see SWT
307  *
308  * @since 3.2
309  */

310 public int getBackgroundMode () {
311     checkWidget ();
312     return backgroundMode;
313 }
314
315 /**
316  * Returns a (possibly empty) array containing the receiver's children.
317  * Children are returned in the order that they are drawn. The topmost
318  * control appears at the beginning of the array. Subsequent controls
319  * draw beneath this control and appear later in the array.
320  * <p>
321  * Note: This is not the actual structure used by the receiver
322  * to maintain its list of children, so modifying the array will
323  * not affect the receiver.
324  * </p>
325  *
326  * @return an array of children
327  *
328  * @see Control#moveAbove
329  * @see Control#moveBelow
330  *
331  * @exception SWTException <ul>
332  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
333  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
334  * </ul>
335  */

336 public Control [] getChildren () {
337     checkWidget ();
338     return _getChildren ();
339 }
340
341 int getChildrenCount () {
342     /*
343     * NOTE: The current implementation will count
344     * non-registered children.
345     */

346     int count = 0;
347     int hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
348     while (hwndChild != 0) {
349         count++;
350         hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
351     }
352     return count;
353 }
354
355 /**
356  * Returns layout which is associated with the receiver, or
357  * null if one has not been set.
358  *
359  * @return the receiver's layout or null
360  *
361  * @exception SWTException <ul>
362  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
363  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
364  * </ul>
365  */

366 public Layout getLayout () {
367     checkWidget ();
368     return layout;
369 }
370
371 /**
372  * Gets the (possibly empty) tabbing order for the control.
373  *
374  * @return tabList the ordered list of controls representing the tab order
375  *
376  * @exception SWTException <ul>
377  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
378  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
379  * </ul>
380  *
381  * @see #setTabList
382  */

383 public Control [] getTabList () {
384     checkWidget ();
385     Control [] tabList = _getTabList ();
386     if (tabList == null) {
387         int count = 0;
388         Control [] list =_getChildren ();
389         for (int i=0; i<list.length; i++) {
390             if (list [i].isTabGroup ()) count++;
391         }
392         tabList = new Control [count];
393         int index = 0;
394         for (int i=0; i<list.length; i++) {
395             if (list [i].isTabGroup ()) {
396                 tabList [index++] = list [i];
397             }
398         }
399     }
400     return tabList;
401 }
402
403 boolean hooksKeys () {
404     return hooks (SWT.KeyDown) || hooks (SWT.KeyUp);
405 }
406
407 /**
408  * Returns <code>true</code> if the receiver has deferred
409  * the performing of layout, and <code>false</code> otherwise.
410  *
411  * @return the receiver's deferred layout state
412  *
413  * @exception SWTException <ul>
414  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
415  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
416  * </ul>
417  *
418  * @see #setLayoutDeferred(boolean)
419  * @see #isLayoutDeferred()
420  *
421  * @since 3.1
422  */

423 public boolean getLayoutDeferred () {
424     checkWidget ();
425     return layoutCount > 0 ;
426 }
427
428 /**
429  * Returns <code>true</code> if the receiver or any ancestor
430  * up to and including the receiver's nearest ancestor shell
431  * has deferred the performing of layouts. Otherwise, <code>false</code>
432  * is returned.
433  *
434  * @return the receiver's deferred layout state
435  *
436  * @exception SWTException <ul>
437  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
438  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
439  * </ul>
440  *
441  * @see #setLayoutDeferred(boolean)
442  * @see #getLayoutDeferred()
443  *
444  * @since 3.1
445  */

446 public boolean isLayoutDeferred () {
447     checkWidget ();
448     return findDeferredControl () != null;
449 }
450
451 /**
452  * If the receiver has a layout, asks the layout to <em>lay out</em>
453  * (that is, set the size and location of) the receiver's children.
454  * If the receiver does not have a layout, do nothing.
455  * <p>
456  * This is equivalent to calling <code>layout(true)</code>.
457  * </p>
458  * <p>
459  * Note: Layout is different from painting. If a child is
460  * moved or resized such that an area in the parent is
461  * exposed, then the parent will paint. If no child is
462  * affected, the parent will not paint.
463  * </p>
464  *
465  * @exception SWTException <ul>
466  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
467  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
468  * </ul>
469  */

470 public void layout () {
471     checkWidget ();
472     layout (true);
473 }
474
475 /**
476  * If the receiver has a layout, asks the layout to <em>lay out</em>
477  * (that is, set the size and location of) the receiver's children.
478  * If the argument is <code>true</code> the layout must not rely
479  * on any information it has cached about the immediate children. If it
480  * is <code>false</code> the layout may (potentially) optimize the
481  * work it is doing by assuming that none of the receiver's
482  * children has changed state since the last layout.
483  * If the receiver does not have a layout, do nothing.
484  * <p>
485  * If a child is resized as a result of a call to layout, the
486  * resize event will invoke the layout of the child. The layout
487  * will cascade down through all child widgets in the receiver's widget
488  * tree until a child is encountered that does not resize. Note that
489  * a layout due to a resize will not flush any cached information
490  * (same as <code>layout(false)</code>).
491  * </p>
492  * <p>
493  * Note: Layout is different from painting. If a child is
494  * moved or resized such that an area in the parent is
495  * exposed, then the parent will paint. If no child is
496  * affected, the parent will not paint.
497  * </p>
498  *
499  * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise
500  *
501  * @exception SWTException <ul>
502  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
503  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
504  * </ul>
505  */

506 public void layout (boolean changed) {
507     checkWidget ();
508     if (layout == null) return;
509     layout (changed, false);
510 }
511
512 /**
513  * If the receiver has a layout, asks the layout to <em>lay out</em>
514  * (that is, set the size and location of) the receiver's children.
515  * If the changed argument is <code>true</code> the layout must not rely
516  * on any information it has cached about its children. If it
517  * is <code>false</code> the layout may (potentially) optimize the
518  * work it is doing by assuming that none of the receiver's
519  * children has changed state since the last layout.
520  * If the all argument is <code>true</code> the layout will cascade down
521  * through all child widgets in the receiver's widget tree, regardless of
522  * whether the child has changed size. The changed argument is applied to
523  * all layouts. If the all argument is <code>false</code>, the layout will
524  * <em>not</em> cascade down through all child widgets in the receiver's widget
525  * tree. However, if a child is resized as a result of a call to layout, the
526  * resize event will invoke the layout of the child. Note that
527  * a layout due to a resize will not flush any cached information
528  * (same as <code>layout(false)</code>).
529  * </p>
530  * <p>
531  * Note: Layout is different from painting. If a child is
532  * moved or resized such that an area in the parent is
533  * exposed, then the parent will paint. If no child is
534  * affected, the parent will not paint.
535  * </p>
536  *
537  * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise
538  * @param all <code>true</code> if all children in the receiver's widget tree should be laid out, and <code>false</code> otherwise
539  *
540  * @exception SWTException <ul>
541  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
542  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
543  * </ul>
544  *
545  * @since 3.1
546  */

547 public void layout (boolean changed, boolean all) {
548     checkWidget ();
549     if (layout == null && !all) return;
550     markLayout (changed, all);
551     updateLayout (true, all);
552 }
553
554 /**
555  * Forces a lay out (that is, sets the size and location) of all widgets that
556  * are in the parent hierarchy of the changed control up to and including the
557  * receiver. The layouts in the hierarchy must not rely on any information
558  * cached about the changed control or any of its ancestors. The layout may
559  * (potentially) optimize the work it is doing by assuming that none of the
560  * peers of the changed control have changed state since the last layout.
561  * If an ancestor does not have a layout, skip it.
562  * <p>
563  * Note: Layout is different from painting. If a child is
564  * moved or resized such that an area in the parent is
565  * exposed, then the parent will paint. If no child is
566  * affected, the parent will not paint.
567  * </p>
568  *
569  * @param changed a control that has had a state change which requires a recalculation of its size
570  *
571  * @exception IllegalArgumentException <ul>
572  * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li>
573  * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li>
574  * </ul>
575  * @exception SWTException <ul>
576  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
577  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
578  * </ul>
579  *
580  * @since 3.1
581  */

582 public void layout (Control [] changed) {
583     checkWidget ();
584     if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
585     for (int i=0; i<changed.length; i++) {
586         Control control = changed [i];
587         if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
588         if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
589         boolean ancestor = false;
590         Composite composite = control.parent;
591         while (composite != null) {
592             ancestor = composite == this;
593             if (ancestor) break;
594             composite = composite.parent;
595         }
596         if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
597     }
598     int updateCount = 0;
599     Composite [] update = new Composite [16];
600     for (int i=0; i<changed.length; i++) {
601         Control child = changed [i];
602         Composite composite = child.parent;
603         while (child != this) {
604             if (composite.layout != null) {
605                 composite.state |= LAYOUT_NEEDED;
606                 if (!composite.layout.flushCache (child)) {
607                     composite.state |= LAYOUT_CHANGED;
608                 }
609             }
610             if (updateCount == update.length) {
611                 Composite [] newUpdate = new Composite [update.length + 16];
612                 System.arraycopy (update, 0, newUpdate, 0, update.length);
613                 update = newUpdate;
614             }
615             child = update [updateCount++] = composite;
616             composite = child.parent;
617         }
618     }
619     for (int i=updateCount-1; i>=0; i--) {
620         update [i].updateLayout (true, false);
621     }
622 }
623
624 void markLayout (boolean changed, boolean all) {
625     if (layout != null) {
626         state |= LAYOUT_NEEDED;
627         if (changed) state |= LAYOUT_CHANGED;
628     }
629     if (all) {
630         Control [] children = _getChildren ();
631         for (int i=0; i<children.length; i++) {
632             children [i].markLayout (changed, all);
633         }
634     }
635 }
636
637 Point minimumSize (int wHint, int hHint, boolean changed) {
638     Control [] children = _getChildren ();
639     int width = 0, height = 0;
640     for (int i=0; i<children.length; i++) {
641         Rectangle rect = children [i].getBounds ();
642         width = Math.max (width, rect.x + rect.width);
643         height = Math.max (height, rect.y + rect.height);
644     }
645     return new Point (width, height);
646 }
647
648 boolean redrawChildren () {
649     if (!super.redrawChildren ()) return false;
650     Control [] children = _getChildren ();
651     for (int i=0; i<children.length; i++) {
652         children [i].redrawChildren ();
653     }
654     return true;
655 }
656
657 void releaseChildren (boolean destroy) {
658     Control [] children = _getChildren ();
659     for (int i=0; i<children.length; i++) {
660         Control child = children [i];
661         if (child != null && !child.isDisposed ()) {
662             child.release (false);
663         }
664     }
665     super.releaseChildren (destroy);
666 }
667
668 void releaseWidget () {
669     super.releaseWidget ();
670     if ((state & CANVAS) != 0 && (style & SWT.EMBEDDED) != 0) {
671         int hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
672         if (hwndChild != 0) {
673             int threadId = OS.GetWindowThreadProcessId (hwndChild, null);
674             if (threadId != OS.GetCurrentThreadId ()) {
675                 OS.ShowWindow (hwndChild, OS.SW_HIDE);
676                 OS.SetParent (hwndChild, 0);
677             }
678         }
679     }
680     layout = null;
681     tabList = null;
682     lpwp = null;
683 }
684
685 void removeControl (Control control) {
686     fixTabList (control);
687     resizeChildren ();
688 }
689
690 void resizeChildren () {
691     if (lpwp == null) return;
692     do {
693         WINDOWPOS [] currentLpwp = lpwp;
694         lpwp = null;
695         if (!resizeChildren (true, currentLpwp)) {
696             resizeChildren (false, currentLpwp);
697         }
698     } while (lpwp != null);
699 }
700
701 boolean resizeChildren (boolean defer, WINDOWPOS [] pwp) {
702     if (pwp == null) return true;
703     int hdwp = 0;
704     if (defer) {
705         hdwp = OS.BeginDeferWindowPos (pwp.length);
706         if (hdwp == 0) return false;
707     }
708     for (int i=0; i<pwp.length; i++) {
709         WINDOWPOS wp = pwp [i];
710         if (wp != null) {
711             /*
712             * This code is intentionally commented. All widgets that
713             * are created by SWT have WS_CLIPSIBLINGS to ensure that
714             * application code does not draw outside of the control.
715             */

716 // int count = parent.getChildrenCount ();
717
// if (count > 1) {
718
// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
719
// if ((bits & OS.WS_CLIPSIBLINGS) == 0) wp.flags |= OS.SWP_NOCOPYBITS;
720
// }
721
if (defer) {
722                 hdwp = DeferWindowPos (hdwp, wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
723                 if (hdwp == 0) return false;
724             } else {
725                 SetWindowPos (wp.hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
726             }
727         }
728     }
729     if (defer) return OS.EndDeferWindowPos (hdwp);
730     return true;
731 }
732
733 void resizeEmbeddedHandle(int embeddedHandle, int width, int height) {
734     if (embeddedHandle == 0) return;
735     int [] processID = new int [1];
736     int threadId = OS.GetWindowThreadProcessId (embeddedHandle, processID);
737     if (threadId != OS.GetCurrentThreadId ()) {
738         if (processID [0] == OS.GetCurrentProcessId ()) {
739             if (display.msgHook == 0) {
740                 if (!OS.IsWinCE) {
741                     display.getMsgCallback = new Callback (display, "getMsgProc", 3);
742                     display.getMsgProc = display.getMsgCallback.getAddress ();
743                     if (display.getMsgProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
744                     display.msgHook = OS.SetWindowsHookEx (OS.WH_GETMESSAGE, display.getMsgProc, OS.GetLibraryHandle(), threadId);
745                     OS.PostThreadMessage (threadId, OS.WM_NULL, 0, 0);
746                 }
747             }
748         }
749         int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE | OS.SWP_ASYNCWINDOWPOS;
750         OS.SetWindowPos (embeddedHandle, 0, 0, 0, width, height, flags);
751     }
752 }
753
754 void sendResize () {
755     setResizeChildren (false);
756     sendEvent (SWT.Resize);
757     if (isDisposed ()) return;
758     if (layout != null) {
759         markLayout (false, false);
760         updateLayout (false, false);
761     }
762     setResizeChildren (true);
763 }
764
765 /**
766  * Sets the background drawing mode to the argument which should
767  * be one of the following constants defined in class <code>SWT</code>:
768  * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>,
769  * <code>INHERIT_FORCE</code>.
770  *
771  * @param mode the new background mode
772  *
773  * @exception SWTException <ul>
774  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
775  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
776  * </ul>
777  *
778  * @see SWT
779  *
780  * @since 3.2
781  */

782 public void setBackgroundMode (int mode) {
783     checkWidget ();
784     backgroundMode = mode;
785     Control [] children = _getChildren ();
786     for (int i = 0; i < children.length; i++) {
787         children [i].updateBackgroundMode ();
788     }
789 }
790
791 boolean setFixedFocus () {
792     checkWidget ();
793     Control [] children = _getChildren ();
794     for (int i=0; i<children.length; i++) {
795         Control child = children [i];
796         if (child.setRadioFocus ()) return true;
797     }
798     for (int i=0; i<children.length; i++) {
799         Control child = children [i];
800         if (child.setFixedFocus ()) return true;
801     }
802     return super.setFixedFocus ();
803 }
804
805 public boolean setFocus () {
806     checkWidget ();
807     Control [] children = _getChildren ();
808     for (int i=0; i<children.length; i++) {
809         Control child = children [i];
810         if (child.setRadioFocus ()) return true;
811     }
812     for (int i=0; i<children.length; i++) {
813         Control child = children [i];
814         if (child.setFocus ()) return true;
815     }
816     return super.setFocus ();
817 }
818
819 /**
820  * Sets the layout which is associated with the receiver to be
821  * the argument which may be null.
822  *
823  * @param layout the receiver's new layout or null
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 public void setLayout (Layout layout) {
831     checkWidget ();
832     this.layout = layout;
833 }
834
835 /**
836  * If the argument is <code>true</code>, causes subsequent layout
837  * operations in the receiver or any of its children to be ignored.
838  * No layout of any kind can occur in the receiver or any of its
839  * children until the flag is set to false.
840  * Layout operations that occurred while the flag was
841  * <code>true</code> are remembered and when the flag is set to
842  * <code>false</code>, the layout operations are performed in an
843  * optimized manner. Nested calls to this method are stacked.
844  *
845  * @param defer the new defer state
846  *
847  * @exception SWTException <ul>
848  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
849  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
850  * </ul>
851  *
852  * @see #layout(boolean)
853  * @see #layout(Control[])
854  *
855  * @since 3.1
856  */

857 public void setLayoutDeferred (boolean defer) {
858     if (!defer) {
859         if (--layoutCount == 0) {
860             if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) {
861                 updateLayout (true, true);
862             }
863         }
864     } else {
865         layoutCount++;
866     }
867 }
868 /**
869  * Sets the tabbing order for the specified controls to
870  * match the order that they occur in the argument list.
871  *
872  * @param tabList the ordered list of controls representing the tab order or null
873  *
874  * @exception IllegalArgumentException <ul>
875  * <li>ERROR_INVALID_ARGUMENT - if a widget in the tabList is null or has been disposed</li>
876  * <li>ERROR_INVALID_PARENT - if widget in the tabList is not in the same widget tree</li>
877  * </ul>
878  * @exception SWTException <ul>
879  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
880  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
881  * </ul>
882  */

883 public void setTabList (Control [] tabList) {
884     checkWidget ();
885     if (tabList != null) {
886         for (int i=0; i<tabList.length; i++) {
887             Control control = tabList [i];
888             if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
889             if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
890             if (control.parent != this) error (SWT.ERROR_INVALID_PARENT);
891         }
892         Control [] newList = new Control [tabList.length];
893         System.arraycopy (tabList, 0, newList, 0, tabList.length);
894         tabList = newList;
895     }
896     this.tabList = tabList;
897 }
898
899 void setResizeChildren (boolean resize) {
900     if (resize) {
901         resizeChildren ();
902     } else {
903         int count = getChildrenCount ();
904         if (count > 1 && lpwp == null) {
905             lpwp = new WINDOWPOS [count];
906         }
907     }
908 }
909
910 boolean setTabGroupFocus () {
911     if (isTabItem ()) return setTabItemFocus ();
912     boolean takeFocus = (style & SWT.NO_FOCUS) == 0;
913     if ((state & CANVAS) != 0) {
914         takeFocus = hooksKeys ();
915         if ((style & SWT.EMBEDDED) != 0) takeFocus = true;
916     }
917     if (takeFocus && setTabItemFocus ()) return true;
918     Control [] children = _getChildren ();
919     for (int i=0; i<children.length; i++) {
920         Control child = children [i];
921         if (child.isTabItem () && child.setRadioFocus ()) return true;
922     }
923     for (int i=0; i<children.length; i++) {
924         Control child = children [i];
925         if (child.isTabItem () && child.setTabItemFocus ()) return true;
926     }
927     return false;
928 }
929
930 String JavaDoc toolTipText (NMTTDISPINFO hdr) {
931     Shell shell = getShell ();
932     if ((hdr.uFlags & OS.TTF_IDISHWND) == 0) {
933         String JavaDoc string = null;
934         ToolTip toolTip = shell.findToolTip (hdr.idFrom);
935         if (toolTip != null) {
936             string = toolTip.message;
937             if (string == null || string.length () == 0) string = " ";
938         }
939         return string;
940     }
941     shell.setToolTipTitle (hdr.hwndFrom, null, 0);
942     OS.SendMessage (hdr.hwndFrom, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
943     Control control = display.getControl (hdr.idFrom);
944     return control != null ? control.toolTipText : null;
945 }
946
947 boolean translateMnemonic (Event event, Control control) {
948     if (super.translateMnemonic (event, control)) return true;
949     if (control != null) {
950         Control [] children = _getChildren ();
951         for (int i=0; i<children.length; i++) {
952             Control child = children [i];
953             if (child.translateMnemonic (event, control)) return true;
954         }
955     }
956     return false;
957 }
958
959 boolean translateTraversal (MSG msg) {
960     if ((state & CANVAS) != 0 ) {
961         if ((style & SWT.EMBEDDED) != 0) return false;
962         switch (msg.wParam) {
963             case OS.VK_UP:
964             case OS.VK_LEFT:
965             case OS.VK_DOWN:
966             case OS.VK_RIGHT:
967             case OS.VK_PRIOR:
968             case OS.VK_NEXT:
969                 OS.SendMessage (msg.hwnd, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
970                 break;
971         }
972     }
973     return super.translateTraversal (msg);
974 }
975
976 void updateBackgroundColor () {
977     super.updateBackgroundColor ();
978     Control [] children = _getChildren ();
979     for (int i=0; i<children.length; i++) {
980         if ((children [i].state & PARENT_BACKGROUND) != 0) {
981             children [i].updateBackgroundColor ();
982         }
983     }
984 }
985
986 void updateBackgroundImage () {
987     super.updateBackgroundImage ();
988     Control [] children = _getChildren ();
989     for (int i=0; i<children.length; i++) {
990         if ((children [i].state & PARENT_BACKGROUND) != 0) {
991             children [i].updateBackgroundImage ();
992         }
993     }
994 }
995
996 void updateBackgroundMode () {
997     super.updateBackgroundMode ();
998     Control [] children = _getChildren ();
999     for (int i = 0; i < children.length; i++) {
1000        children [i].updateBackgroundMode ();
1001    }
1002}
1003
1004void updateFont (Font oldFont, Font newFont) {
1005    super.updateFont (oldFont, newFont);
1006    Control [] children = _getChildren ();
1007    for (int i=0; i<children.length; i++) {
1008        Control control = children [i];
1009        if (!control.isDisposed ()) {
1010            control.updateFont (oldFont, newFont);
1011        }
1012    }
1013}
1014
1015void updateLayout (boolean resize, boolean all) {
1016    Composite parent = findDeferredControl ();
1017    if (parent != null) {
1018        parent.state |= LAYOUT_CHILD;
1019        return;
1020    }
1021    if ((state & LAYOUT_NEEDED) != 0) {
1022        boolean changed = (state & LAYOUT_CHANGED) != 0;
1023        state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED);
1024        if (resize) setResizeChildren (false);
1025        layout.layout (this, changed);
1026        if (resize) setResizeChildren (true);
1027    }
1028    if (all) {
1029        state &= ~LAYOUT_CHILD;
1030        Control [] children = _getChildren ();
1031        for (int i=0; i<children.length; i++) {
1032            children [i].updateLayout (resize, all);
1033        }
1034    }
1035}
1036
1037int widgetStyle () {
1038    /* Force clipping of children by setting WS_CLIPCHILDREN */
1039    return super.widgetStyle () | OS.WS_CLIPCHILDREN;
1040}
1041
1042LRESULT WM_ERASEBKGND (int wParam, int lParam) {
1043    LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
1044    if (result != null) return result;
1045    if ((state & CANVAS) != 0) {
1046        /* Return zero to indicate that the background was not erased */
1047        if ((style & SWT.NO_BACKGROUND) != 0) return LRESULT.ZERO;
1048    }
1049    return result;
1050}
1051
1052LRESULT WM_GETDLGCODE (int wParam, int lParam) {
1053    LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
1054    if (result != null) return result;
1055    if ((state & CANVAS) != 0) {
1056        int flags = 0;
1057        if (hooksKeys ()) {
1058            flags |= OS.DLGC_WANTALLKEYS | OS.DLGC_WANTARROWS | OS.DLGC_WANTTAB;
1059        }
1060        if ((style & SWT.NO_FOCUS) != 0) flags |= OS.DLGC_STATIC;
1061        if (OS.GetWindow (handle, OS.GW_CHILD) != 0) flags |= OS.DLGC_STATIC;
1062        if (flags != 0) return new LRESULT (flags);
1063    }
1064    return result;
1065}
1066
1067LRESULT WM_GETFONT (int wParam, int lParam) {
1068    LRESULT result = super.WM_GETFONT (wParam, lParam);
1069    if (result != null) return result;
1070    int code = callWindowProc (handle, OS.WM_GETFONT, wParam, lParam);
1071    if (code != 0) return new LRESULT (code);
1072    if (font == 0) font = defaultFont ();
1073    return new LRESULT (font);
1074}
1075
1076LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
1077    LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
1078    if (result == LRESULT.ZERO) return result;
1079
1080    /* Set focus for a canvas with no children */
1081    if ((state & CANVAS) != 0) {
1082        if ((style & SWT.NO_FOCUS) == 0 && hooksKeys ()) {
1083            if (OS.GetWindow (handle, OS.GW_CHILD) == 0) setFocus ();
1084        }
1085    }
1086    return result;
1087}
1088
1089LRESULT WM_NCPAINT (int wParam, int lParam) {
1090    LRESULT result = super.WM_NCPAINT (wParam, lParam);
1091    if (result != null) return result;
1092    if ((state & CANVAS) != 0) {
1093        result = wmNCPaint (handle, wParam, lParam);
1094    }
1095    return result;
1096}
1097
1098LRESULT WM_PARENTNOTIFY (int wParam, int lParam) {
1099    if ((state & CANVAS) != 0 && (style & SWT.EMBEDDED) != 0) {
1100        if ((wParam & 0xFFFF) == OS.WM_CREATE) {
1101            RECT rect = new RECT ();
1102            OS.GetClientRect (handle, rect);
1103            resizeEmbeddedHandle (lParam, rect.right - rect.left, rect.bottom - rect.top);
1104        }
1105    }
1106    return super.WM_PARENTNOTIFY (wParam, lParam);
1107}
1108
1109LRESULT WM_PAINT (int wParam, int lParam) {
1110    if ((state & CANVAS) == 0 || (state & FOREIGN_HANDLE) != 0) {
1111        return super.WM_PAINT (wParam, lParam);
1112    }
1113
1114    /* Set the clipping bits */
1115    int oldBits = 0, newBits = 0;
1116    if (!OS.IsWinCE) {
1117        oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1118        newBits = oldBits | OS.WS_CLIPSIBLINGS | OS.WS_CLIPCHILDREN;
1119        if (newBits != oldBits) OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
1120    }
1121
1122    /* Paint the control and the background */
1123    PAINTSTRUCT ps = new PAINTSTRUCT ();
1124    if (hooks (SWT.Paint)) {
1125
1126        /* Use the buffered paint when possible */
1127        boolean bufferedPaint = false;
1128        if ((style & SWT.DOUBLE_BUFFERED) != 0) {
1129            if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1130                if ((style & (SWT.NO_MERGE_PAINTS | SWT.RIGHT_TO_LEFT)) == 0) {
1131                    bufferedPaint = true;
1132                }
1133            }
1134        }
1135        if (bufferedPaint) {
1136            int hDC = OS.BeginPaint (handle, ps);
1137            int width = ps.right - ps.left;
1138            int height = ps.bottom - ps.top;
1139            if (width != 0 && height != 0) {
1140                int [] phdc = new int [1];
1141                int flags = OS.BPBF_COMPATIBLEBITMAP;
1142                RECT prcTarget = new RECT ();
1143                OS.SetRect (prcTarget, ps.left, ps.top, ps.right, ps.bottom);
1144                int hBufferedPaint = OS.BeginBufferedPaint (hDC, prcTarget, flags, null, phdc);
1145                GCData data = new GCData ();
1146                if ((OS.GetLayout (hDC) & OS.LAYOUT_RTL) != 0) {
1147                    data.style = SWT.RIGHT_TO_LEFT | SWT.MIRRORED;
1148                } else {
1149                    data.style = SWT.LEFT_TO_RIGHT;
1150                }
1151                data.device = display;
1152                data.foreground = getForegroundPixel ();
1153                Control control = findBackgroundControl ();
1154                if (control == null) control = this;
1155                data.background = control.getBackgroundPixel ();
1156                data.hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1157                data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1158                if ((style & SWT.NO_BACKGROUND) != 0) {
1159                    /* This code is intentionally commented because it may be slow to copy bits from the screen */
1160                    //paintGC.copyArea (image, ps.left, ps.top);
1161
} else {
1162                    RECT rect = new RECT ();
1163                    OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1164                    drawBackground (phdc [0], rect);
1165                }
1166                GC gc = GC.win32_new (phdc [0], data);
1167                Event event = new Event ();
1168                event.gc = gc;
1169                event.x = ps.left;
1170                event.y = ps.top;
1171                event.width = width;
1172                event.height = height;
1173                sendEvent (SWT.Paint, event);
1174                gc.dispose ();
1175                OS.EndBufferedPaint (hBufferedPaint, true);
1176            }
1177            OS.EndPaint (handle, ps);
1178        } else {
1179            
1180            /* Create the paint GC */
1181            GCData data = new GCData ();
1182            data.ps = ps;
1183            data.hwnd = handle;
1184            GC gc = GC.win32_new (this, data);
1185
1186            /* Get the system region for the paint HDC */
1187            int sysRgn = 0;
1188            if ((style & (SWT.NO_MERGE_PAINTS | SWT.DOUBLE_BUFFERED)) != 0) {
1189                sysRgn = OS.CreateRectRgn (0, 0, 0, 0);
1190                if (OS.GetRandomRgn (gc.handle, sysRgn, OS.SYSRGN) == 1) {
1191                    if (OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
1192                        if ((OS.GetLayout (gc.handle) & OS.LAYOUT_RTL) != 0) {
1193                            int nBytes = OS.GetRegionData (sysRgn, 0, null);
1194                            int [] lpRgnData = new int [nBytes / 4];
1195                            OS.GetRegionData (sysRgn, nBytes, lpRgnData);
1196                            int newSysRgn = OS.ExtCreateRegion (new float [] {-1, 0, 0, 1, 0, 0}, nBytes, lpRgnData);
1197                            OS.DeleteObject (sysRgn);
1198                            sysRgn = newSysRgn;
1199                        }
1200                    }
1201                    if (OS.IsWinNT) {
1202                        POINT pt = new POINT();
1203                        OS.MapWindowPoints (0, handle, pt, 1);
1204                        OS.OffsetRgn (sysRgn, pt.x, pt.y);
1205                    }
1206                }
1207            }
1208            
1209            /* Send the paint event */
1210            int width = ps.right - ps.left;
1211            int height = ps.bottom - ps.top;
1212            if (width != 0 && height != 0) {
1213                GC paintGC = null;
1214                Image image = null;
1215                if ((style & SWT.DOUBLE_BUFFERED) != 0) {
1216                    image = new Image (display, width, height);
1217                    paintGC = gc;
1218                    gc = new GC (image, paintGC.getStyle() & SWT.RIGHT_TO_LEFT);
1219                    GCData gcData = gc.getGCData ();
1220                    gcData.uiState = data.uiState;
1221                    gc.setForeground (getForeground ());
1222                    gc.setBackground (getBackground ());
1223                    gc.setFont (getFont ());
1224                    OS.OffsetRgn (sysRgn, -ps.left, -ps.top);
1225                    OS.SelectClipRgn (gc.handle, sysRgn);
1226                    OS.OffsetRgn (sysRgn, ps.left, ps.top);
1227                    OS.SetMetaRgn (gc.handle);
1228                    OS.SetWindowOrgEx (gc.handle, ps.left, ps.top, null);
1229                    OS.SetBrushOrgEx (gc.handle, ps.left, ps.top, null);
1230                    if ((style & SWT.NO_BACKGROUND) != 0) {
1231                        /* This code is intentionally commented because it may be slow to copy bits from the screen */
1232                        //paintGC.copyArea (image, ps.left, ps.top);
1233
} else {
1234                        RECT rect = new RECT ();
1235                        OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1236                        drawBackground (gc.handle, rect);
1237                    }
1238                }
1239                Event event = new Event ();
1240                event.gc = gc;
1241                RECT rect = null;
1242                if ((style & SWT.NO_MERGE_PAINTS) != 0 && OS.GetRgnBox (sysRgn, rect = new RECT ()) == OS.COMPLEXREGION) {
1243                    int nBytes = OS.GetRegionData (sysRgn, 0, null);
1244                    int [] lpRgnData = new int [nBytes / 4];
1245                    OS.GetRegionData (sysRgn, nBytes, lpRgnData);
1246                    int count = lpRgnData [2];
1247                    for (int i=0; i<count; i++) {
1248                        int offset = 8 + (i << 2);
1249                        OS.SetRect (rect, lpRgnData [offset], lpRgnData [offset + 1], lpRgnData [offset + 2], lpRgnData [offset + 3]);
1250                        if ((style & (SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND)) == 0) {
1251                            drawBackground (gc.handle, rect);
1252                        }
1253                        event.x = rect.left;
1254                        event.y = rect.top;
1255                        event.width = rect.right - rect.left;
1256                        event.height = rect.bottom - rect.top;
1257                        event.count = count - 1 - i;
1258                        sendEvent (SWT.Paint, event);
1259                    }
1260                } else {
1261                    if ((style & (SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND)) == 0) {
1262                        if (rect == null) rect = new RECT ();
1263                        OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1264                        drawBackground (gc.handle, rect);
1265                    }
1266                    event.x = ps.left;
1267                    event.y = ps.top;
1268                    event.width = width;
1269                    event.height = height;
1270                    sendEvent (SWT.Paint, event);
1271                }
1272                // widget could be disposed at this point
1273
event.gc = null;
1274                if ((style & SWT.DOUBLE_BUFFERED) != 0) {
1275                    gc.dispose();
1276                    if (!isDisposed ()) paintGC.drawImage (image, ps.left, ps.top);
1277                    image.dispose ();
1278                    gc = paintGC;
1279                }
1280            }
1281            if (sysRgn != 0) OS.DeleteObject (sysRgn);
1282            
1283            /* Dispose the paint GC */
1284            gc.dispose ();
1285        }
1286    } else {
1287        int hDC = OS.BeginPaint (handle, ps);
1288        if ((style & SWT.NO_BACKGROUND) == 0) {
1289            RECT rect = new RECT ();
1290            OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
1291            drawBackground (hDC, rect);
1292        }
1293        OS.EndPaint (handle, ps);
1294    }
1295
1296    /* Restore the clipping bits */
1297    if (!OS.IsWinCE && !isDisposed ()) {
1298        if (newBits != oldBits) {
1299            /*
1300            * It is possible (but unlikely), that application
1301            * code could have disposed the widget in the paint
1302            * event. If this happens, don't attempt to restore
1303            * the style.
1304            */

1305            if (!isDisposed ()) {
1306                OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits);
1307            }
1308        }
1309    }
1310    return LRESULT.ZERO;
1311}
1312
1313LRESULT WM_PRINTCLIENT (int wParam, int lParam) {
1314    LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
1315    if (result != null) return result;
1316    if ((state & CANVAS) != 0) {
1317        forceResize ();
1318        int nSavedDC = OS.SaveDC (wParam);
1319        RECT rect = new RECT ();
1320        OS.GetClientRect (handle, rect);
1321        if ((style & SWT.NO_BACKGROUND) == 0) {
1322            drawBackground (wParam, rect);
1323        }
1324        if (hooks (SWT.Paint) || filters (SWT.Paint)) {
1325            GCData data = new GCData ();
1326            data.device = display;
1327            data.foreground = getForegroundPixel ();
1328            Control control = findBackgroundControl ();
1329            if (control == null) control = this;
1330            data.background = control.getBackgroundPixel ();
1331            data.hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1332            data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1333            GC gc = GC.win32_new (wParam, data);
1334            Event event = new Event ();
1335            event.gc = gc;
1336            event.x = rect.left;
1337            event.y = rect.top;
1338            event.width = rect.right - rect.left;
1339            event.height = rect.bottom - rect.top;
1340            sendEvent (SWT.Paint, event);
1341            event.gc = null;
1342            gc.dispose ();
1343        }
1344        OS.RestoreDC (wParam, nSavedDC);
1345    }
1346    return result;
1347}
1348
1349LRESULT WM_SETFONT (int wParam, int lParam) {
1350    if (lParam != 0) OS.InvalidateRect (handle, null, true);
1351    return super.WM_SETFONT (font = wParam, lParam);
1352}
1353
1354LRESULT WM_SIZE (int wParam, int lParam) {
1355
1356    /* Begin deferred window positioning */
1357    setResizeChildren (false);
1358    
1359    /* Resize and Layout */
1360    LRESULT result = super.WM_SIZE (wParam, lParam);
1361    /*
1362    * It is possible (but unlikely), that application
1363    * code could have disposed the widget in the resize
1364    * event. If this happens, end the processing of the
1365    * Windows message by returning the result of the
1366    * WM_SIZE message.
1367    */

1368    if (isDisposed ()) return result;
1369    if (layout != null) {
1370        markLayout (false, false);
1371        updateLayout (false, false);
1372    }
1373
1374    /* End deferred window positioning */
1375    setResizeChildren (true);
1376    
1377    /* Damage the widget to cause a repaint */
1378    if (OS.IsWindowVisible (handle)) {
1379        if ((state & CANVAS) != 0) {
1380            if ((style & SWT.NO_REDRAW_RESIZE) == 0) {
1381                if (hooks (SWT.Paint)) {
1382                    OS.InvalidateRect (handle, null, true);
1383                }
1384            }
1385        }
1386        if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
1387            if (findThemeControl () != null) redrawChildren ();
1388        }
1389    }
1390
1391    /* Resize the embedded window */
1392    if ((state & CANVAS) != 0 && (style & SWT.EMBEDDED) != 0) {
1393        resizeEmbeddedHandle (OS.GetWindow (handle, OS.GW_CHILD), lParam & 0xFFFF, lParam >> 16);
1394    }
1395    return result;
1396}
1397
1398LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
1399    LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
1400    if (result != null) return result;
1401    int hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
1402    while (hwndChild != 0) {
1403        OS.SendMessage (hwndChild, OS.WM_SYSCOLORCHANGE, 0, 0);
1404        hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
1405    }
1406    return result;
1407}
1408
1409LRESULT WM_SYSCOMMAND (int wParam, int lParam) {
1410    LRESULT result = super.WM_SYSCOMMAND (wParam, lParam);
1411    if (result != null) return result;
1412        
1413    /*
1414    * Check to see if the command is a system command or
1415    * a user menu item that was added to the system menu.
1416    */

1417    if ((wParam & 0xF000) == 0) return result;
1418
1419    /*
1420    * Bug in Windows. When a vertical or horizontal scroll bar is
1421    * hidden or shown while the opposite scroll bar is being scrolled
1422    * by the user (with WM_HSCROLL code SB_LINEDOWN), the scroll bar
1423    * does not redraw properly. The fix is to detect this case and
1424    * redraw the non-client area.
1425    */

1426    if (!OS.IsWinCE) {
1427        int cmd = wParam & 0xFFF0;
1428        switch (cmd) {
1429            case OS.SC_HSCROLL:
1430            case OS.SC_VSCROLL:
1431                boolean showHBar = horizontalBar != null && horizontalBar.getVisible ();
1432                boolean showVBar = verticalBar != null && verticalBar.getVisible ();
1433                int code = callWindowProc (handle, OS.WM_SYSCOMMAND, wParam, lParam);
1434                if ((showHBar != (horizontalBar != null && horizontalBar.getVisible ())) ||
1435                    (showVBar != (verticalBar != null && verticalBar.getVisible ()))) {
1436                        int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_UPDATENOW;
1437                        OS.RedrawWindow (handle, null, 0, flags);
1438                    }
1439                if (code == 0) return LRESULT.ZERO;
1440                return new LRESULT (code);
1441        }
1442    }
1443    /* Return the result */
1444    return result;
1445}
1446
1447LRESULT WM_UPDATEUISTATE (int wParam, int lParam) {
1448    LRESULT result = super.WM_UPDATEUISTATE (wParam, lParam);
1449    if (result != null) return result;
1450    if ((state & CANVAS) != 0) OS.InvalidateRect (handle, null, false);
1451    return result;
1452}
1453
1454LRESULT wmNCPaint (int hwnd, int wParam, int lParam) {
1455    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
1456        int bits1 = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE);
1457        if ((bits1 & OS.WS_EX_CLIENTEDGE) != 0) {
1458            int code = 0;
1459            int bits2 = OS.GetWindowLong (hwnd, OS.GWL_STYLE);
1460            if ((bits2 & (OS.WS_HSCROLL | OS.WS_VSCROLL)) != 0) {
1461                code = callWindowProc (hwnd, OS.WM_NCPAINT, wParam, lParam);
1462            }
1463            int hDC = OS.GetWindowDC (hwnd);
1464            RECT rect = new RECT ();
1465            OS.GetWindowRect (hwnd, rect);
1466            rect.right -= rect.left;
1467            rect.bottom -= rect.top;
1468            rect.left = rect.top = 0;
1469            int border = OS.GetSystemMetrics (OS.SM_CXEDGE);
1470            OS.ExcludeClipRect (hDC, border, border, rect.right - border, rect.bottom - border);
1471            OS.DrawThemeBackground (display.hEditTheme (), hDC, OS.EP_EDITTEXT, OS.ETS_NORMAL, rect, null);
1472            OS.ReleaseDC (hwnd, hDC);
1473            return new LRESULT (code);
1474        }
1475    }
1476    return null;
1477}
1478
1479LRESULT wmNotify (NMHDR hdr, int wParam, int lParam) {
1480    if (!OS.IsWinCE) {
1481        switch (hdr.code) {
1482            /*
1483            * Feature in Windows. When the tool tip control is
1484            * created, the parent of the tool tip is the shell.
1485            * If SetParent () is used to reparent the tool bar
1486            * into a new shell, the tool tip is not reparented
1487            * and pops up underneath the new shell. The fix is
1488            * to make sure the tool tip is a topmost window.
1489            */

1490            case OS.TTN_SHOW:
1491            case OS.TTN_POP: {
1492                /*
1493                * Bug in Windows 98 and NT. Setting the tool tip to be the
1494                * top most window using HWND_TOPMOST can result in a parent
1495                * dialog shell being moved behind its parent if the dialog
1496                * has a sibling that is currently on top. The fix is to
1497                * lock the z-order of the active window.
1498                *
1499                * Feature in Windows. Using SetWindowPos() with HWND_NOTOPMOST
1500                * to clear the topmost state of a window whose parent is already
1501                * topmost clears the topmost state of the parent. The fix is to
1502                * check if the parent is already on top and neither set or clear
1503                * the topmost status of the tool tip.
1504                */

1505                int hwndParent = hdr.hwndFrom;
1506                do {
1507                    hwndParent = OS.GetParent (hwndParent);
1508                    if (hwndParent == 0) break;
1509                    int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
1510                    if ((bits & OS.WS_EX_TOPMOST) != 0) break;
1511                } while (true);
1512                if (hwndParent != 0) break;
1513                display.lockActiveWindow = true;
1514                int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOSIZE;
1515                int hwndInsertAfter = hdr.code == OS.TTN_SHOW ? OS.HWND_TOPMOST : OS.HWND_NOTOPMOST;
1516                SetWindowPos (hdr.hwndFrom, hwndInsertAfter, 0, 0, 0, 0, flags);
1517                display.lockActiveWindow = false;
1518                break;
1519            }
1520            /*
1521            * Bug in Windows 98. For some reason, the tool bar control
1522            * sends both TTN_GETDISPINFOW and TTN_GETDISPINFOA to get
1523            * the tool tip text and the tab folder control sends only
1524            * TTN_GETDISPINFOW. The fix is to handle only TTN_GETDISPINFOW,
1525            * even though it should never be sent on Windows 98.
1526            *
1527            * NOTE: Because the size of NMTTDISPINFO differs between
1528            * Windows 98 and NT, guard against the case where the wrong
1529            * kind of message occurs by inlining the memory moves and
1530            * the UNICODE conversion code.
1531            */

1532            case OS.TTN_GETDISPINFOA:
1533            case OS.TTN_GETDISPINFOW: {
1534                NMTTDISPINFO lpnmtdi;
1535                if (hdr.code == OS.TTN_GETDISPINFOA) {
1536                    lpnmtdi = new NMTTDISPINFOA ();
1537                    OS.MoveMemory ((NMTTDISPINFOA)lpnmtdi, lParam, NMTTDISPINFOA.sizeof);
1538                } else {
1539                    lpnmtdi = new NMTTDISPINFOW ();
1540                    OS.MoveMemory ((NMTTDISPINFOW)lpnmtdi, lParam, NMTTDISPINFOW.sizeof);
1541                }
1542                String JavaDoc string = toolTipText (lpnmtdi);
1543                if (string != null) {
1544                    Shell shell = getShell ();
1545                    string = Display.withCrLf (string);
1546                    int length = string.length ();
1547                    char [] chars = new char [length + 1];
1548                    string.getChars (0, length, chars, 0);
1549                    
1550                    /*
1551                    * Ensure that the orientation of the tool tip matches
1552                    * the orientation of the control.
1553                    */

1554                    int hwnd = hdr.idFrom;
1555                    if (hwnd != 0 && ((lpnmtdi.uFlags & OS.TTF_IDISHWND) != 0)) {
1556                        Control control = display.getControl (hwnd);
1557                        if (control != null) {
1558                            if ((control.getStyle () & SWT.RIGHT_TO_LEFT) != 0) {
1559                                lpnmtdi.uFlags |= OS.TTF_RTLREADING;
1560                            } else {
1561                                lpnmtdi.uFlags &= ~OS.TTF_RTLREADING;
1562                            }
1563                        }
1564                    }
1565                    
1566                    if (hdr.code == OS.TTN_GETDISPINFOA) {
1567                        byte [] bytes = new byte [chars.length * 2];
1568                        OS.WideCharToMultiByte (getCodePage (), 0, chars, chars.length, bytes, bytes.length, null, null);
1569                        shell.setToolTipText (lpnmtdi, bytes);
1570                        OS.MoveMemory (lParam, (NMTTDISPINFOA)lpnmtdi, NMTTDISPINFOA.sizeof);
1571                    } else {
1572                        shell.setToolTipText (lpnmtdi, chars);
1573                        OS.MoveMemory (lParam, (NMTTDISPINFOW)lpnmtdi, NMTTDISPINFOW.sizeof);
1574                    }
1575                    return LRESULT.ZERO;
1576                }
1577                break;
1578            }
1579        }
1580    }
1581    return super.wmNotify (hdr, wParam, lParam);
1582}
1583
1584}
1585
Popular Tags