KickJava   Java API By Example, From Geeks To Geeks.

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


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 import org.eclipse.swt.events.*;
19
20 /**
21  * This class is the abstract superclass of all user interface objects.
22  * Widgets are created, disposed and issue notification to listeners
23  * when events occur which affect them.
24  * <dl>
25  * <dt><b>Styles:</b></dt>
26  * <dd>(none)</dd>
27  * <dt><b>Events:</b></dt>
28  * <dd>Dispose</dd>
29  * </dl>
30  * <p>
31  * IMPORTANT: This class is intended to be subclassed <em>only</em>
32  * within the SWT implementation. However, it has not been marked
33  * final to allow those outside of the SWT development team to implement
34  * patched versions of the class in order to get around specific
35  * limitations in advance of when those limitations can be addressed
36  * by the team. Any class built using subclassing to access the internals
37  * of this class will likely fail to compile or run between releases and
38  * may be strongly platform specific. Subclassing should not be attempted
39  * without an intimate and detailed understanding of the workings of the
40  * hierarchy. No support is provided for user-written classes which are
41  * implemented as subclasses of this class.
42  * </p>
43  *
44  * @see #checkSubclass
45  */

46
47 public abstract class Widget {
48     int style, state;
49     Display display;
50     EventTable eventTable;
51     Object JavaDoc data;
52
53     /* Global state flags */
54     static final int DISPOSED = 1<<0;
55     static final int CANVAS = 1<<1;
56     static final int KEYED_DATA = 1<<2;
57     static final int DISABLED = 1<<3;
58     static final int HIDDEN = 1<<4;
59     
60     /* A layout was requested on this widget */
61     static final int LAYOUT_NEEDED = 1<<5;
62     
63     /* The preferred size of a child has changed */
64     static final int LAYOUT_CHANGED = 1<<6;
65     
66     /* A layout was requested in this widget hierarchy */
67     static final int LAYOUT_CHILD = 1<<7;
68
69     /* Background flags */
70     static final int THEME_BACKGROUND = 1<<8;
71     static final int DRAW_BACKGROUND = 1<<9;
72     static final int PARENT_BACKGROUND = 1<<10;
73     
74     /* Dispose and release flags */
75     static final int RELEASED = 1<<11;
76     static final int DISPOSE_SENT = 1<<12;
77     
78     /* More global widget state flags */
79     static final int TRACK_MOUSE = 1<<13;
80     static final int FOREIGN_HANDLE = 1<<14;
81     static final int DRAG_DETECT = 1<<15;
82
83     /* Default size for widgets */
84     static final int DEFAULT_WIDTH = 64;
85     static final int DEFAULT_HEIGHT = 64;
86
87     /* Check and initialize the Common Controls DLL */
88     static final int MAJOR = 5, MINOR = 80;
89     static {
90         if (!OS.IsWinCE) {
91             if (OS.COMCTL32_VERSION < OS.VERSION (MAJOR, MINOR)) {
92                 System.out.println ("***WARNING: SWT requires comctl32.dll version " + MAJOR + "." + MINOR + " or greater"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
93
System.out.println ("***WARNING: Detected: " + OS.COMCTL32_MAJOR + "." + OS.COMCTL32_MINOR); //$NON-NLS-1$ //$NON-NLS-2$
94
}
95         }
96         OS.InitCommonControls ();
97     }
98     
99 /**
100  * Prevents uninitialized instances from being created outside the package.
101  */

102 Widget () {
103 }
104
105 /**
106  * Constructs a new instance of this class given its parent
107  * and a style value describing its behavior and appearance.
108  * <p>
109  * The style value is either one of the style constants defined in
110  * class <code>SWT</code> which is applicable to instances of this
111  * class, or must be built by <em>bitwise OR</em>'ing together
112  * (that is, using the <code>int</code> "|" operator) two or more
113  * of those <code>SWT</code> style constants. The class description
114  * lists the style constants that are applicable to the class.
115  * Style bits are also inherited from superclasses.
116  * </p>
117  *
118  * @param parent a widget which will be the parent of the new instance (cannot be null)
119  * @param style the style of widget to construct
120  *
121  * @exception IllegalArgumentException <ul>
122  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
123  * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
124  * </ul>
125  * @exception SWTException <ul>
126  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
127  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
128  * </ul>
129  *
130  * @see SWT
131  * @see #checkSubclass
132  * @see #getStyle
133  */

134 public Widget (Widget parent, int style) {
135     checkSubclass ();
136     checkParent (parent);
137     this.style = style;
138     display = parent.display;
139 }
140
141 void _addListener (int eventType, Listener listener) {
142     if (eventTable == null) eventTable = new EventTable ();
143     eventTable.hook (eventType, listener);
144 }
145
146 /**
147  * Adds the listener to the collection of listeners who will
148  * be notified when an event of the given type occurs. When the
149  * event does occur in the widget, the listener is notified by
150  * sending it the <code>handleEvent()</code> message. The event
151  * type is one of the event constants defined in class <code>SWT</code>.
152  *
153  * @param eventType the type of event to listen for
154  * @param listener the listener which should be notified when the event occurs
155  *
156  * @exception IllegalArgumentException <ul>
157  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
158  * </ul>
159  * @exception SWTException <ul>
160  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
161  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
162  * </ul>
163  *
164  * @see Listener
165  * @see SWT
166  * @see #removeListener(int, Listener)
167  * @see #notifyListeners
168  */

169 public void addListener (int eventType, Listener listener) {
170     checkWidget();
171     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
172     _addListener (eventType, listener);
173 }
174
175 /**
176  * Adds the listener to the collection of listeners who will
177  * be notified when the widget is disposed. When the widget is
178  * disposed, the listener is notified by sending it the
179  * <code>widgetDisposed()</code> message.
180  *
181  * @param listener the listener which should be notified when the receiver is disposed
182  *
183  * @exception IllegalArgumentException <ul>
184  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
185  * </ul>
186  * @exception SWTException <ul>
187  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
188  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
189  * </ul>
190  *
191  * @see DisposeListener
192  * @see #removeDisposeListener
193  */

194 public void addDisposeListener (DisposeListener listener) {
195     checkWidget();
196     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
197     TypedListener typedListener = new TypedListener (listener);
198     addListener (SWT.Dispose, typedListener);
199 }
200
201 int callWindowProc (int hwnd, int msg, int wParam, int lParam) {
202     return 0;
203 }
204
205 /**
206  * Returns a style with exactly one style bit set out of
207  * the specified set of exclusive style bits. All other
208  * possible bits are cleared when the first matching bit
209  * is found. Bits that are not part of the possible set
210  * are untouched.
211  *
212  * @param style the original style bits
213  * @param int0 the 0th possible style bit
214  * @param int1 the 1st possible style bit
215  * @param int2 the 2nd possible style bit
216  * @param int3 the 3rd possible style bit
217  * @param int4 the 4th possible style bit
218  * @param int5 the 5th possible style bit
219  *
220  * @return the new style bits
221  */

222 static int checkBits (int style, int int0, int int1, int int2, int int3, int int4, int int5) {
223     int mask = int0 | int1 | int2 | int3 | int4 | int5;
224     if ((style & mask) == 0) style |= int0;
225     if ((style & int0) != 0) style = (style & ~mask) | int0;
226     if ((style & int1) != 0) style = (style & ~mask) | int1;
227     if ((style & int2) != 0) style = (style & ~mask) | int2;
228     if ((style & int3) != 0) style = (style & ~mask) | int3;
229     if ((style & int4) != 0) style = (style & ~mask) | int4;
230     if ((style & int5) != 0) style = (style & ~mask) | int5;
231     return style;
232 }
233
234 void checkOrientation (Widget parent) {
235     style &= ~SWT.MIRRORED;
236     if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) {
237         if (parent != null) {
238             if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) style |= SWT.LEFT_TO_RIGHT;
239             if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.RIGHT_TO_LEFT;
240         }
241     }
242     style = checkBits (style, SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
243 }
244
245 void checkOpened () {
246     /* Do nothing */
247 }
248
249 /**
250  * Throws an exception if the specified widget can not be
251  * used as a parent for the receiver.
252  *
253  * @exception IllegalArgumentException <ul>
254  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
255  * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
256  * </ul>
257  * @exception SWTException <ul>
258  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
259  * </ul>
260  */

261 void checkParent (Widget parent) {
262     if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
263     if (parent.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
264     parent.checkWidget ();
265     parent.checkOpened ();
266 }
267
268 /**
269  * Checks that this class can be subclassed.
270  * <p>
271  * The SWT class library is intended to be subclassed
272  * only at specific, controlled points (most notably,
273  * <code>Composite</code> and <code>Canvas</code> when
274  * implementing new widgets). This method enforces this
275  * rule unless it is overridden.
276  * </p><p>
277  * <em>IMPORTANT:</em> By providing an implementation of this
278  * method that allows a subclass of a class which does not
279  * normally allow subclassing to be created, the implementer
280  * agrees to be fully responsible for the fact that any such
281  * subclass will likely fail between SWT releases and will be
282  * strongly platform specific. No support is provided for
283  * user-written classes which are implemented in this fashion.
284  * </p><p>
285  * The ability to subclass outside of the allowed SWT classes
286  * is intended purely to enable those not on the SWT development
287  * team to implement patches in order to get around specific
288  * limitations in advance of when those limitations can be
289  * addressed by the team. Subclassing should not be attempted
290  * without an intimate and detailed understanding of the hierarchy.
291  * </p>
292  *
293  * @exception SWTException <ul>
294  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
295  * </ul>
296  */

297 protected void checkSubclass () {
298     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
299 }
300
301 /**
302  * Throws an <code>SWTException</code> if the receiver can not
303  * be accessed by the caller. This may include both checks on
304  * the state of the receiver and more generally on the entire
305  * execution context. This method <em>should</em> be called by
306  * widget implementors to enforce the standard SWT invariants.
307  * <p>
308  * Currently, it is an error to invoke any method (other than
309  * <code>isDisposed()</code>) on a widget that has had its
310  * <code>dispose()</code> method called. It is also an error
311  * to call widget methods from any thread that is different
312  * from the thread that created the widget.
313  * </p><p>
314  * In future releases of SWT, there may be more or fewer error
315  * checks and exceptions may be thrown for different reasons.
316  * </p>
317  *
318  * @exception SWTException <ul>
319  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
320  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
321  * </ul>
322  */

323 protected void checkWidget () {
324     Display display = this.display;
325     if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
326     if (display.thread != Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
327     if ((state & DISPOSED) != 0) error (SWT.ERROR_WIDGET_DISPOSED);
328 }
329
330 /**
331  * Destroys the widget in the operating system and releases
332  * the widget's handle. If the widget does not have a handle,
333  * this method may hide the widget, mark the widget as destroyed
334  * or do nothing, depending on the widget.
335  * <p>
336  * When a widget is destroyed in the operating system, its
337  * descendants are also destroyed by the operating system.
338  * This means that it is only necessary to call <code>destroyWidget</code>
339  * on the root of the widget tree.
340  * </p><p>
341  * This method is called after <code>releaseWidget()</code>.
342  * </p><p>
343  * See also <code>releaseChild()</code>, <code>releaseWidget()</code>
344  * and <code>releaseHandle()</code>.
345  * </p>
346  *
347  * @see #dispose
348  */

349 void destroyWidget () {
350     releaseHandle ();
351 }
352
353 int DeferWindowPos(int hWinPosInfo, int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags){
354     if (OS.IsWinCE) {
355         /*
356         * Feature in Windows. On Windows CE, DeferWindowPos always causes
357         * a WM_SIZE message, even when the new size is the same as the old
358         * size. The fix is to detect that the size has not changed and set
359         * SWP_NOSIZE.
360         */

361         if ((uFlags & OS.SWP_NOSIZE) == 0) {
362             RECT lpRect = new RECT ();
363             OS.GetWindowRect (hWnd, lpRect);
364             if (cy == lpRect.bottom - lpRect.top && cx == lpRect.right - lpRect.left) {
365                 /*
366                 * Feature in Windows. On Windows CE, DeferWindowPos when called
367                 * with SWP_DRAWFRAME always causes a WM_SIZE message, even
368                 * when SWP_NOSIZE is set and when the new size is the same as the
369                 * old size. The fix is to clear SWP_DRAWFRAME when the size is
370                 * the same.
371                 */

372                 uFlags &= ~OS.SWP_DRAWFRAME;
373                 uFlags |= OS.SWP_NOSIZE;
374             }
375         }
376     }
377     return OS.DeferWindowPos (hWinPosInfo, hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
378 }
379
380 /**
381  * Disposes of the operating system resources associated with
382  * the receiver and all its descendants. After this method has
383  * been invoked, the receiver and all descendants will answer
384  * <code>true</code> when sent the message <code>isDisposed()</code>.
385  * Any internal connections between the widgets in the tree will
386  * have been removed to facilitate garbage collection.
387  * <p>
388  * NOTE: This method is not called recursively on the descendants
389  * of the receiver. This means that, widget implementers can not
390  * detect when a widget is being disposed of by re-implementing
391  * this method, but should instead listen for the <code>Dispose</code>
392  * event.
393  * </p>
394  *
395  * @exception SWTException <ul>
396  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
397  * </ul>
398  *
399  * @see #addDisposeListener
400  * @see #removeDisposeListener
401  * @see #checkWidget
402  */

403 public void dispose () {
404     /*
405     * Note: It is valid to attempt to dispose a widget
406     * more than once. If this happens, fail silently.
407     */

408     if (isDisposed ()) return;
409     if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
410     release (true);
411 }
412
413 boolean dragDetect (int hwnd, int x, int y, boolean filter, boolean [] detect, boolean [] consume) {
414     if (consume != null) consume [0] = false;
415     if (detect != null) detect [0] = true;
416     POINT pt = new POINT ();
417     pt.x = x;
418     pt.y = y;
419     OS.ClientToScreen (hwnd, pt);
420     return OS.DragDetect (hwnd, pt);
421 }
422
423 /**
424  * Does whatever widget specific cleanup is required, and then
425  * uses the code in <code>SWTError.error</code> to handle the error.
426  *
427  * @param code the descriptive error code
428  *
429  * @see SWT#error(int)
430  */

431 void error (int code) {
432     SWT.error(code);
433 }
434
435 boolean filters (int eventType) {
436     return display.filters (eventType);
437 }
438
439 Widget findItem (int id) {
440     return null;
441 }
442
443 char [] fixMnemonic (String JavaDoc string) {
444     char [] buffer = new char [string.length ()];
445     string.getChars (0, string.length (), buffer, 0);
446     int i = 0, j = 0;
447     while (i < buffer.length) {
448         if (buffer [i] == '&') {
449             if (i + 1 < buffer.length && buffer [i + 1] == '&') {
450                 buffer [j++] = ' ';
451                 i++;
452             }
453             i++;
454         } else {
455             buffer [j++] = buffer [i++];
456         }
457     }
458     while (j < buffer.length) buffer [j++] = 0;
459     return buffer;
460 }
461
462 /**
463  * Returns the application defined widget data associated
464  * with the receiver, or null if it has not been set. The
465  * <em>widget data</em> is a single, unnamed field that is
466  * stored with every widget.
467  * <p>
468  * Applications may put arbitrary objects in this field. If
469  * the object stored in the widget data needs to be notified
470  * when the widget is disposed of, it is the application's
471  * responsibility to hook the Dispose event on the widget and
472  * do so.
473  * </p>
474  *
475  * @return the widget data
476  *
477  * @exception SWTException <ul>
478  * <li>ERROR_WIDGET_DISPOSED - when the receiver has been disposed</li>
479  * <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li>
480  * </ul>
481  *
482  * @see #setData(Object)
483  */

484 public Object JavaDoc getData () {
485     checkWidget();
486     return (state & KEYED_DATA) != 0 ? ((Object JavaDoc []) data) [0] : data;
487 }
488
489 /**
490  * Returns the application defined property of the receiver
491  * with the specified name, or null if it has not been set.
492  * <p>
493  * Applications may have associated arbitrary objects with the
494  * receiver in this fashion. If the objects stored in the
495  * properties need to be notified when the widget is disposed
496  * of, it is the application's responsibility to hook the
497  * Dispose event on the widget and do so.
498  * </p>
499  *
500  * @param key the name of the property
501  * @return the value of the property or null if it has not been set
502  *
503  * @exception IllegalArgumentException <ul>
504  * <li>ERROR_NULL_ARGUMENT - if the key is null</li>
505  * </ul>
506  * @exception SWTException <ul>
507  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
508  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
509  * </ul>
510  *
511  * @see #setData(String, Object)
512  */

513 public Object JavaDoc getData (String JavaDoc key) {
514     checkWidget();
515     if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
516     if ((state & KEYED_DATA) != 0) {
517         Object JavaDoc [] table = (Object JavaDoc []) data;
518         for (int i=1; i<table.length; i+=2) {
519             if (key.equals (table [i])) return table [i+1];
520         }
521     }
522     return null;
523 }
524
525 /**
526  * Returns the <code>Display</code> that is associated with
527  * the receiver.
528  * <p>
529  * A widget's display is either provided when it is created
530  * (for example, top level <code>Shell</code>s) or is the
531  * same as its parent's display.
532  * </p>
533  *
534  * @return the receiver's display
535  *
536  * @exception SWTException <ul>
537  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
538  * </ul>
539  */

540 public Display getDisplay () {
541     Display display = this.display;
542     if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
543     return display;
544 }
545
546 Menu getMenu () {
547     return null;
548 }
549
550 /**
551  * Returns the name of the widget. This is the name of
552  * the class without the package name.
553  *
554  * @return the name of the widget
555  */

556 String JavaDoc getName () {
557     String JavaDoc string = getClass ().getName ();
558     int index = string.lastIndexOf ('.');
559     if (index == -1) return string;
560     return string.substring (index + 1, string.length ());
561 }
562
563 /*
564  * Returns a short printable representation for the contents
565  * of a widget. For example, a button may answer the label
566  * text. This is used by <code>toString</code> to provide a
567  * more meaningful description of the widget.
568  *
569  * @return the contents string for the widget
570  *
571  * @see #toString
572  */

573 String JavaDoc getNameText () {
574     return ""; //$NON-NLS-1$
575
}
576
577 /**
578  * Returns the receiver's style information.
579  * <p>
580  * Note that the value which is returned by this method <em>may
581  * not match</em> the value which was provided to the constructor
582  * when the receiver was created. This can occur when the underlying
583  * operating system does not support a particular combination of
584  * requested styles. For example, if the platform widget used to
585  * implement a particular SWT widget always has scroll bars, the
586  * result of calling this method would always have the
587  * <code>SWT.H_SCROLL</code> and <code>SWT.V_SCROLL</code> bits set.
588  * </p>
589  *
590  * @return the style bits
591  *
592  * @exception SWTException <ul>
593  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
594  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
595  * </ul>
596  */

597 public int getStyle () {
598     checkWidget();
599     return style;
600 }
601
602 /*
603  * Returns <code>true</code> if the specified eventType is
604  * hooked, and <code>false</code> otherwise. Implementations
605  * of SWT can avoid creating objects and sending events
606  * when an event happens in the operating system but
607  * there are no listeners hooked for the event.
608  *
609  * @param eventType the event to be checked
610  *
611  * @return <code>true</code> when the eventType is hooked and <code>false</code> otherwise
612  *
613  * @see #isListening
614  */

615 boolean hooks (int eventType) {
616     if (eventTable == null) return false;
617     return eventTable.hooks (eventType);
618 }
619
620 /**
621  * Returns <code>true</code> if the widget has been disposed,
622  * and <code>false</code> otherwise.
623  * <p>
624  * This method gets the dispose state for the widget.
625  * When a widget has been disposed, it is an error to
626  * invoke any other method using the widget.
627  * </p>
628  *
629  * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
630  */

631 public boolean isDisposed () {
632     return (state & DISPOSED) != 0;
633 }
634
635 /**
636  * Returns <code>true</code> if there are any listeners
637  * for the specified event type associated with the receiver,
638  * and <code>false</code> otherwise. The event type is one of
639  * the event constants defined in class <code>SWT</code>.
640  *
641  * @param eventType the type of event
642  * @return true if the event is hooked
643  *
644  * @exception SWTException <ul>
645  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
646  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
647  * </ul>
648  *
649  * @see SWT
650  */

651 public boolean isListening (int eventType) {
652     checkWidget();
653     return hooks (eventType);
654 }
655
656 /*
657  * Returns <code>true</code> when subclassing is
658  * allowed and <code>false</code> otherwise
659  *
660  * @return <code>true</code> when subclassing is allowed and <code>false</code> otherwise
661  */

662 boolean isValidSubclass () {
663     return Display.isValidClass (getClass ());
664 }
665
666 /*
667  * Returns <code>true</code> when the current thread is
668  * the thread that created the widget and <code>false</code>
669  * otherwise.
670  *
671  * @return <code>true</code> when the current thread is the thread that created the widget and <code>false</code> otherwise
672  */

673 boolean isValidThread () {
674     return getDisplay ().isValidThread ();
675 }
676
677 void mapEvent (int hwnd, Event event) {
678 }
679
680 GC new_GC (GCData data) {
681     return null;
682 }
683
684 /**
685  * Notifies all of the receiver's listeners for events
686  * of the given type that one such event has occurred by
687  * invoking their <code>handleEvent()</code> method. The
688  * event type is one of the event constants defined in class
689  * <code>SWT</code>.
690  *
691  * @param eventType the type of event which has occurred
692  * @param event the event data
693  *
694  * @exception SWTException <ul>
695  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
696  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
697  * </ul>
698  *
699  * @see SWT
700  * @see #addListener
701  * @see #removeListener(int, Listener)
702  */

703 public void notifyListeners (int eventType, Event event) {
704     checkWidget();
705     if (event == null) event = new Event ();
706     sendEvent (eventType, event);
707 }
708
709 void postEvent (int eventType) {
710     sendEvent (eventType, null, false);
711 }
712
713 void postEvent (int eventType, Event event) {
714     sendEvent (eventType, event, false);
715 }
716
717 /*
718  * Releases the widget hierarchy and optionally destroys
719  * the receiver.
720  * <p>
721  * Typically, a widget with children will broadcast this
722  * message to all children so that they too can release their
723  * resources. The <code>releaseHandle</code> method is used
724  * as part of this broadcast to zero the handle fields of the
725  * children without calling <code>destroyWidget</code>. In
726  * this scenario, the children are actually destroyed later,
727  * when the operating system destroys the widget tree.
728  * </p>
729  *
730  * @param destroy indicates that the receiver should be destroyed
731  *
732  * @see #dispose
733  * @see #releaseHandle
734  * @see #releaseParent
735  * @see #releaseWidget
736 */

737 void release (boolean destroy) {
738     if ((state & DISPOSE_SENT) == 0) {
739         state |= DISPOSE_SENT;
740         sendEvent (SWT.Dispose);
741     }
742     if ((state & DISPOSED) == 0) {
743         releaseChildren (destroy);
744     }
745     if ((state & RELEASED) == 0) {
746         state |= RELEASED;
747         if (destroy) {
748             releaseParent ();
749             releaseWidget ();
750             destroyWidget ();
751         } else {
752             releaseWidget ();
753             releaseHandle ();
754         }
755     }
756 }
757
758 void releaseChildren (boolean destroy) {
759 }
760
761 /*
762  * Releases the widget's handle by zero'ing it out.
763  * Does not destroy or release any operating system
764  * resources.
765  * <p>
766  * This method is called after <code>releaseWidget</code>
767  * or from <code>destroyWidget</code> when a widget is being
768  * destroyed to ensure that the widget is marked as destroyed
769  * in case the act of destroying the widget in the operating
770  * system causes application code to run in callback that
771  * could access the widget.
772  * </p>
773  *
774  * @see #dispose
775  * @see #releaseChildren
776  * @see #releaseParent
777  * @see #releaseWidget
778  */

779 void releaseHandle () {
780     state |= DISPOSED;
781     display = null;
782 }
783
784 /*
785  * Releases the receiver, a child in a widget hierarchy,
786  * from its parent.
787  * <p>
788  * When a widget is destroyed, it may be necessary to remove
789  * it from an internal data structure of the parent. When
790  * a widget has no handle, it may also be necessary for the
791  * parent to hide the widget or otherwise indicate that the
792  * widget has been disposed. For example, disposing a menu
793  * bar requires that the menu bar first be released from the
794  * shell when the menu bar is active.
795  * </p>
796  *
797  * @see #dispose
798  * @see #releaseChildren
799  * @see #releaseWidget
800  * @see #releaseHandle
801  */

802 void releaseParent () {
803 }
804
805 /*
806  * Releases any internal resources back to the operating
807  * system and clears all fields except the widget handle.
808  * <p>
809  * When a widget is destroyed, resources that were acquired
810  * on behalf of the programmer need to be returned to the
811  * operating system. For example, if the widget made a
812  * copy of an icon, supplied by the programmer, this copy
813  * would be freed in <code>releaseWidget</code>. Also,
814  * to assist the garbage collector and minimize the amount
815  * of memory that is not reclaimed when the programmer keeps
816  * a reference to a disposed widget, all fields except the
817  * handle are zero'd. The handle is needed by <code>destroyWidget</code>.
818  * </p>
819  *
820  * @see #dispose
821  * @see #releaseChildren
822  * @see #releaseHandle
823  * @see #releaseParent
824  */

825 void releaseWidget () {
826     eventTable = null;
827     data = null;
828 }
829
830 /**
831  * Removes the listener from the collection of listeners who will
832  * be notified when an event of the given type occurs. The event
833  * type is one of the event constants defined in class <code>SWT</code>.
834  *
835  * @param eventType the type of event to listen for
836  * @param listener the listener which should no longer be notified when the event occurs
837  *
838  * @exception IllegalArgumentException <ul>
839  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
840  * </ul>
841  * @exception SWTException <ul>
842  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
843  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
844  * </ul>
845  *
846  * @see Listener
847  * @see SWT
848  * @see #addListener
849  * @see #notifyListeners
850  */

851 public void removeListener (int eventType, Listener listener) {
852     checkWidget();
853     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
854     if (eventTable == null) return;
855     eventTable.unhook (eventType, listener);
856 }
857
858 /**
859  * Removes the listener from the collection of listeners who will
860  * be notified when an event of the given type occurs.
861  * <p>
862  * <b>IMPORTANT:</b> This method is <em>not</em> part of the SWT
863  * public API. It is marked public only so that it can be shared
864  * within the packages provided by SWT. It should never be
865  * referenced from application code.
866  * </p>
867  *
868  * @param eventType the type of event to listen for
869  * @param listener the listener which should no longer be notified when the event occurs
870  *
871  * @exception IllegalArgumentException <ul>
872  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
873  * </ul>
874  * @exception SWTException <ul>
875  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
876  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
877  * </ul>
878  *
879  * @see Listener
880  * @see #addListener
881  */

882 protected void removeListener (int eventType, SWTEventListener listener) {
883     checkWidget();
884     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
885     if (eventTable == null) return;
886     eventTable.unhook (eventType, listener);
887 }
888
889 /**
890  * Removes the listener from the collection of listeners who will
891  * be notified when the widget is disposed.
892  *
893  * @param listener the listener which should no longer be notified when the receiver is disposed
894  *
895  * @exception IllegalArgumentException <ul>
896  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
897  * </ul>
898  * @exception SWTException <ul>
899  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
900  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
901  * </ul>
902  *
903  * @see DisposeListener
904  * @see #addDisposeListener
905  */

906 public void removeDisposeListener (DisposeListener listener) {
907     checkWidget();
908     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
909     if (eventTable == null) return;
910     eventTable.unhook (SWT.Dispose, listener);
911 }
912
913 boolean sendDragEvent (int button, int x, int y) {
914     Event event = new Event ();
915     event.button = button;
916     event.x = x;
917     event.y = y;
918     setInputState (event, SWT.DragDetect);
919     postEvent (SWT.DragDetect, event);
920     if (isDisposed ()) return false;
921     return event.doit;
922 }
923
924 boolean sendDragEvent (int button, int stateMask, int x, int y) {
925     Event event = new Event ();
926     event.button = button;
927     event.x = x;
928     event.y = y;
929     event.stateMask = stateMask;
930     postEvent (SWT.DragDetect, event);
931     if (isDisposed ()) return false;
932     return event.doit;
933 }
934
935 void sendEvent (Event event) {
936     Display display = event.display;
937     if (!display.filterEvent (event)) {
938         if (eventTable != null) eventTable.sendEvent (event);
939     }
940 }
941
942 void sendEvent (int eventType) {
943     sendEvent (eventType, null, true);
944 }
945
946 void sendEvent (int eventType, Event event) {
947     sendEvent (eventType, event, true);
948 }
949
950 void sendEvent (int eventType, Event event, boolean send) {
951     if (eventTable == null && !display.filters (eventType)) {
952         return;
953     }
954     if (event == null) event = new Event ();
955     event.type = eventType;
956     event.display = display;
957     event.widget = this;
958     if (event.time == 0) {
959         event.time = display.getLastEventTime ();
960     }
961     if (send) {
962         sendEvent (event);
963     } else {
964         display.postEvent (event);
965     }
966 }
967
968 boolean sendKeyEvent (int type, int msg, int wParam, int lParam) {
969     Event event = new Event ();
970     if (!setKeyState (event, type, wParam, lParam)) return true;
971     return sendKeyEvent (type, msg, wParam, lParam, event);
972 }
973
974 boolean sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) {
975     sendEvent (type, event);
976     if (isDisposed ()) return false;
977     return event.doit;
978 }
979
980 boolean sendMouseEvent (int type, int button, int hwnd, int msg, int wParam, int lParam) {
981     return sendMouseEvent (type, button, display.getClickCount (type, button, hwnd, lParam), 0, false, hwnd, msg, wParam, lParam);
982 }
983
984 boolean sendMouseEvent (int type, int button, int count, int detail, boolean send, int hwnd, int msg, int wParam, int lParam) {
985     if (!hooks (type) && !filters (type)) return true;
986     Event event = new Event ();
987     event.button = button;
988     event.detail = detail;
989     event.count = count;
990     event.x = (short) (lParam & 0xFFFF);
991     event.y = (short) (lParam >> 16);
992     setInputState (event, type);
993     mapEvent (hwnd, event);
994     if (send) {
995         sendEvent (type, event);
996         if (isDisposed ()) return false;
997     } else {
998         postEvent (type, event);
999     }
1000    return event.doit;
1001}
1002
1003/**
1004 * Sets the application defined widget data associated
1005 * with the receiver to be the argument. The <em>widget
1006 * data</em> is a single, unnamed field that is stored
1007 * with every widget.
1008 * <p>
1009 * Applications may put arbitrary objects in this field. If
1010 * the object stored in the widget data needs to be notified
1011 * when the widget is disposed of, it is the application's
1012 * responsibility to hook the Dispose event on the widget and
1013 * do so.
1014 * </p>
1015 *
1016 * @param data the widget data
1017 *
1018 * @exception SWTException <ul>
1019 * <li>ERROR_WIDGET_DISPOSED - when the receiver has been disposed</li>
1020 * <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li>
1021 * </ul>
1022 *
1023 * @see #getData()
1024 */

1025public void setData (Object JavaDoc data) {
1026    checkWidget();
1027    if ((state & KEYED_DATA) != 0) {
1028        ((Object JavaDoc []) this.data) [0] = data;
1029    } else {
1030        this.data = data;
1031    }
1032}
1033
1034/**
1035 * Sets the application defined property of the receiver
1036 * with the specified name to the given value.
1037 * <p>
1038 * Applications may associate arbitrary objects with the
1039 * receiver in this fashion. If the objects stored in the
1040 * properties need to be notified when the widget is disposed
1041 * of, it is the application's responsibility to hook the
1042 * Dispose event on the widget and do so.
1043 * </p>
1044 *
1045 * @param key the name of the property
1046 * @param value the new value for the property
1047 *
1048 * @exception IllegalArgumentException <ul>
1049 * <li>ERROR_NULL_ARGUMENT - if the key is null</li>
1050 * </ul>
1051 * @exception SWTException <ul>
1052 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1053 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1054 * </ul>
1055 *
1056 * @see #getData(String)
1057 */

1058public void setData (String JavaDoc key, Object JavaDoc value) {
1059    checkWidget();
1060    if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
1061    int index = 1;
1062    Object JavaDoc [] table = null;
1063    if ((state & KEYED_DATA) != 0) {
1064        table = (Object JavaDoc []) data;
1065        while (index < table.length) {
1066            if (key.equals (table [index])) break;
1067            index += 2;
1068        }
1069    }
1070    if (value != null) {
1071        if ((state & KEYED_DATA) != 0) {
1072            if (index == table.length) {
1073                Object JavaDoc [] newTable = new Object JavaDoc [table.length + 2];
1074                System.arraycopy (table, 0, newTable, 0, table.length);
1075                data = table = newTable;
1076            }
1077        } else {
1078            table = new Object JavaDoc [3];
1079            table [0] = data;
1080            data = table;
1081            state |= KEYED_DATA;
1082        }
1083        table [index] = key;
1084        table [index + 1] = value;
1085    } else {
1086        if ((state & KEYED_DATA) != 0) {
1087            if (index != table.length) {
1088                int length = table.length - 2;
1089                if (length == 1) {
1090                    data = table [0];
1091                    state &= ~KEYED_DATA;
1092                } else {
1093                    Object JavaDoc [] newTable = new Object JavaDoc [length];
1094                    System.arraycopy (table, 0, newTable, 0, index);
1095                    System.arraycopy (table, index + 2, newTable, index, length - index);
1096                    data = newTable;
1097                }
1098            }
1099        }
1100    }
1101}
1102
1103boolean sendFocusEvent (int type) {
1104    sendEvent (type);
1105    // widget could be disposed at this point
1106
return true;
1107}
1108
1109boolean setInputState (Event event, int type) {
1110    if (OS.GetKeyState (OS.VK_MENU) < 0) event.stateMask |= SWT.ALT;
1111    if (OS.GetKeyState (OS.VK_SHIFT) < 0) event.stateMask |= SWT.SHIFT;
1112    if (OS.GetKeyState (OS.VK_CONTROL) < 0) event.stateMask |= SWT.CONTROL;
1113    if (OS.GetKeyState (OS.VK_LBUTTON) < 0) event.stateMask |= SWT.BUTTON1;
1114    if (OS.GetKeyState (OS.VK_MBUTTON) < 0) event.stateMask |= SWT.BUTTON2;
1115    if (OS.GetKeyState (OS.VK_RBUTTON) < 0) event.stateMask |= SWT.BUTTON3;
1116    if (OS.GetKeyState (OS.VK_XBUTTON1) < 0) event.stateMask |= SWT.BUTTON4;
1117    if (OS.GetKeyState (OS.VK_XBUTTON2) < 0) event.stateMask |= SWT.BUTTON5;
1118    switch (type) {
1119        case SWT.MouseDown:
1120        case SWT.MouseDoubleClick:
1121            if (event.button == 1) event.stateMask &= ~SWT.BUTTON1;
1122            if (event.button == 2) event.stateMask &= ~SWT.BUTTON2;
1123            if (event.button == 3) event.stateMask &= ~SWT.BUTTON3;
1124            if (event.button == 4) event.stateMask &= ~SWT.BUTTON4;
1125            if (event.button == 5) event.stateMask &= ~SWT.BUTTON5;
1126            break;
1127        case SWT.MouseUp:
1128            if (event.button == 1) event.stateMask |= SWT.BUTTON1;
1129            if (event.button == 2) event.stateMask |= SWT.BUTTON2;
1130            if (event.button == 3) event.stateMask |= SWT.BUTTON3;
1131            if (event.button == 4) event.stateMask |= SWT.BUTTON4;
1132            if (event.button == 5) event.stateMask |= SWT.BUTTON5;
1133            break;
1134        case SWT.KeyDown:
1135        case SWT.Traverse:
1136            if (event.keyCode == SWT.ALT) event.stateMask &= ~SWT.ALT;
1137            if (event.keyCode == SWT.SHIFT) event.stateMask &= ~SWT.SHIFT;
1138            if (event.keyCode == SWT.CONTROL) event.stateMask &= ~SWT.CONTROL;
1139            break;
1140        case SWT.KeyUp:
1141            if (event.keyCode == SWT.ALT) event.stateMask |= SWT.ALT;
1142            if (event.keyCode == SWT.SHIFT) event.stateMask |= SWT.SHIFT;
1143            if (event.keyCode == SWT.CONTROL) event.stateMask |= SWT.CONTROL;
1144            break;
1145    }
1146    return true;
1147}
1148
1149boolean setKeyState (Event event, int type, int wParam, int lParam) {
1150    
1151    /*
1152    * Feature in Windows. When the user presses Ctrl+Backspace
1153    * or Ctrl+Enter, Windows sends a WM_CHAR with Delete (0x7F)
1154    * and '\n' instead of '\b' and '\r'. This is the correct
1155    * platform behavior but is not portable. The fix is to detect
1156    * these cases and convert the character.
1157    */

1158    switch (display.lastAscii) {
1159        case SWT.DEL:
1160            if (display.lastKey == SWT.BS) display.lastAscii = SWT.BS;
1161            break;
1162        case SWT.LF:
1163            if (display.lastKey == SWT.CR) display.lastAscii = SWT.CR;
1164            break;
1165    }
1166    
1167    /*
1168    * Feature in Windows. When the user presses either the Enter
1169    * key or the numeric keypad Enter key, Windows sends a WM_KEYDOWN
1170    * with wParam=VK_RETURN in both cases. In order to distinguish
1171    * between the keys, the extended key bit is tested. If the bit
1172    * is set, assume that the numeric keypad Enter was pressed.
1173    */

1174    if (display.lastKey == SWT.CR && display.lastAscii == SWT.CR) {
1175        if ((lParam & 0x1000000) != 0) display.lastKey = SWT.KEYPAD_CR;
1176    }
1177    
1178    if (display.lastVirtual) {
1179        /*
1180        * Feature in Windows. The virtual key VK_DELETE is not
1181        * treated as both a virtual key and an ASCII key by Windows.
1182        * Therefore, we will not receive a WM_CHAR for this key.
1183        * The fix is to treat VK_DELETE as a special case and map
1184        * the ASCII value explicitly (Delete is 0x7F).
1185        */

1186        if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
1187        
1188        /*
1189        * Feature in Windows. When the user presses Ctrl+Pause, the
1190        * VK_CANCEL key is generated and a WM_CHAR is sent with 0x03,
1191        * possibly to allow an application to look for Ctrl+C and the
1192        * the Break key at the same time. This is unexpected and
1193        * unwanted. The fix is to detect the case and set the character
1194        * to zero.
1195        */

1196        if (display.lastKey == OS.VK_CANCEL) display.lastAscii = 0x0;
1197        
1198        event.keyCode = Display.translateKey (display.lastKey);
1199    } else {
1200        event.keyCode = display.lastKey;
1201    }
1202    if (display.lastAscii != 0 || display.lastNull) {
1203        event.character = Display.mbcsToWcs ((char) display.lastAscii);
1204    }
1205    if (event.keyCode == 0 && event.character == 0) {
1206        if (!display.lastNull) return false;
1207    }
1208    return setInputState (event, type);
1209}
1210
1211boolean SetWindowPos (int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags) {
1212    if (OS.IsWinCE) {
1213        /*
1214        * Feature in Windows. On Windows CE, SetWindowPos() always causes
1215        * a WM_SIZE message, even when the new size is the same as the old
1216        * size. The fix is to detect that the size has not changed and set
1217        * SWP_NOSIZE.
1218        */

1219        if ((uFlags & OS.SWP_NOSIZE) == 0) {
1220            RECT lpRect = new RECT ();
1221            OS.GetWindowRect (hWnd, lpRect);
1222            if (cy == lpRect.bottom - lpRect.top && cx == lpRect.right - lpRect.left) {
1223                /*
1224                * Feature in Windows. On Windows CE, SetWindowPos() when called
1225                * with SWP_DRAWFRAME always causes a WM_SIZE message, even
1226                * when SWP_NOSIZE is set and when the new size is the same as the
1227                * old size. The fix is to clear SWP_DRAWFRAME when the size is
1228                * the same.
1229                */

1230                uFlags &= ~OS.SWP_DRAWFRAME;
1231                uFlags |= OS.SWP_NOSIZE;
1232            }
1233        }
1234    }
1235    return OS.SetWindowPos (hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
1236}
1237
1238boolean showMenu (int x, int y) {
1239    Event event = new Event ();
1240    event.x = x;
1241    event.y = y;
1242    sendEvent (SWT.MenuDetect, event);
1243    if (!event.doit) return true;
1244    Menu menu = getMenu ();
1245    if (menu != null && !menu.isDisposed ()) {
1246        if (x != event.x || y != event.y) {
1247            menu.setLocation (event.x, event.y);
1248        }
1249        menu.setVisible (true);
1250        return true;
1251    }
1252    return false;
1253}
1254
1255/**
1256 * Returns a string containing a concise, human-readable
1257 * description of the receiver.
1258 *
1259 * @return a string representation of the receiver
1260 */

1261public String JavaDoc toString () {
1262    String JavaDoc string = "*Disposed*"; //$NON-NLS-1$
1263
if (!isDisposed ()) {
1264        string = "*Wrong Thread*"; //$NON-NLS-1$
1265
if (isValidThread ()) string = getNameText ();
1266    }
1267    return getName () + " {" + string + "}"; //$NON-NLS-1$ //$NON-NLS-2$
1268
}
1269
1270LRESULT wmCaptureChanged (int hwnd, int wParam, int lParam) {
1271    display.captureChanged = true;
1272    return null;
1273}
1274
1275LRESULT wmChar (int hwnd, int wParam, int lParam) {
1276    /*
1277    * Do not report a lead byte as a key pressed.
1278    */

1279    if (!OS.IsUnicode && OS.IsDBLocale) {
1280        byte lead = (byte) (wParam & 0xFF);
1281        if (OS.IsDBCSLeadByte (lead)) return null;
1282    }
1283    display.lastAscii = wParam;
1284    display.lastNull = wParam == 0;
1285    if (!sendKeyEvent (SWT.KeyDown, OS.WM_CHAR, wParam, lParam)) {
1286        return LRESULT.ONE;
1287    }
1288    // widget could be disposed at this point
1289
return null;
1290}
1291
1292LRESULT wmContextMenu (int hwnd, int wParam, int lParam) {
1293    if (wParam != hwnd) return null;
1294    
1295    /*
1296    * Feature in Windows. SHRecognizeGesture() sends an undocumented
1297    * WM_CONTEXTMENU notification when the flag SHRG_NOTIFY_PARENT is
1298    * not set. This causes the context menu to be displayed twice,
1299    * once by the caller of SHRecognizeGesture() and once from this
1300    * method. The fix is to ignore WM_CONTEXTMENU notifications on
1301    * all WinCE platforms.
1302    *
1303    * NOTE: This only happens on WM2003. Previous WinCE versions did
1304    * not support WM_CONTEXTMENU.
1305    */

1306    if (OS.IsWinCE) return null;
1307    
1308    /*
1309    * Feature in Windows. When the user presses WM_NCRBUTTONUP,
1310    * a WM_CONTEXTMENU message is generated. This happens when
1311    * the user releases the mouse over a scroll bar. Normally,
1312    * window displays the default scrolling menu but applications
1313    * can process WM_CONTEXTMENU to display a different menu.
1314    * Typically, an application does not want to supply a special
1315    * scroll menu. The fix is to look for a WM_CONTEXTMENU that
1316    * originated from a mouse event and display the menu when the
1317    * mouse was released in the client area.
1318    */

1319    int x = 0, y = 0;
1320    if (lParam != -1) {
1321        POINT pt = new POINT ();
1322        x = pt.x = (short) (lParam & 0xFFFF);
1323        y = pt.y = (short) (lParam >> 16);
1324        OS.ScreenToClient (hwnd, pt);
1325        RECT rect = new RECT ();
1326        OS.GetClientRect (hwnd, rect);
1327        if (!OS.PtInRect (rect, pt)) return null;
1328    } else {
1329        int pos = OS.GetMessagePos ();
1330        x = (short) (pos & 0xFFFF);
1331        y = (short) (pos >> 16);
1332    }
1333
1334    /* Show the menu */
1335    return showMenu (x, y) ? LRESULT.ZERO : null;
1336}
1337
1338LRESULT wmIMEChar (int hwnd, int wParam, int lParam) {
1339    Display display = this.display;
1340    display.lastKey = 0;
1341    display.lastAscii = wParam;
1342    display.lastVirtual = display.lastNull = display.lastDead = false;
1343    if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
1344        return LRESULT.ONE;
1345    }
1346    sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
1347    // widget could be disposed at this point
1348
display.lastKey = display.lastAscii = 0;
1349    return LRESULT.ONE;
1350}
1351
1352LRESULT wmKeyDown (int hwnd, int wParam, int lParam) {
1353    
1354    /* Ignore repeating modifier keys by testing key down state */
1355    switch (wParam) {
1356        case OS.VK_SHIFT:
1357        case OS.VK_MENU:
1358        case OS.VK_CONTROL:
1359        case OS.VK_CAPITAL:
1360        case OS.VK_NUMLOCK:
1361        case OS.VK_SCROLL:
1362            if ((lParam & 0x40000000) != 0) return null;
1363    }
1364    
1365    /* Clear last key and last ascii because a new key has been typed */
1366    display.lastAscii = display.lastKey = 0;
1367    display.lastVirtual = display.lastNull = display.lastDead = false;
1368    
1369    /*
1370    * Do not report a lead byte as a key pressed.
1371    */

1372    if (!OS.IsUnicode && OS.IsDBLocale) {
1373        byte lead = (byte) (wParam & 0xFF);
1374        if (OS.IsDBCSLeadByte (lead)) return null;
1375    }
1376    
1377    /* Map the virtual key */
1378    /*
1379    * Bug in WinCE. MapVirtualKey() returns incorrect values.
1380    * The fix is to rely on a key mappings table to determine
1381    * whether the key event must be sent now or if a WM_CHAR
1382    * event will follow. The key mappings table maps virtual
1383    * keys to SWT key codes and does not contain mappings for
1384    * Windows virtual keys like VK_A. Virtual keys that are
1385    * both virtual and ASCII are a special case.
1386    */

1387    int mapKey = 0;
1388    if (OS.IsWinCE) {
1389        switch (wParam) {
1390            case OS.VK_BACK: mapKey = SWT.BS; break;
1391            case OS.VK_RETURN: mapKey = SWT.CR; break;
1392            case OS.VK_DELETE: mapKey = SWT.DEL; break;
1393            case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
1394            case OS.VK_TAB: mapKey = SWT.TAB; break;
1395        }
1396    } else {
1397        mapKey = OS.MapVirtualKey (wParam, 2);
1398    }
1399
1400    /*
1401    * Bug in Windows 95 and NT. When the user types an accent key such
1402    * as ^ to get an accented character on a German keyboard, the accent
1403    * key should be ignored and the next key that the user types is the
1404    * accented key. The fix is to detect the accent key stroke (called
1405    * a dead key) by testing the high bit of the value returned by
1406    * MapVirtualKey(). A further problem is that the high bit on
1407    * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
1408    * They should both be bit 32.
1409    *
1410    * When the user types an accent key that does not correspond to a
1411    * virtual key, MapVirtualKey() won't set the high bit to indicate
1412    * a dead key. This happens when an accent key, such as '^' is the
1413    * result of a modifier such as Shift key and MapVirtualKey() always
1414    * returns the unshifted key. The fix is to peek for a WM_DEADCHAR
1415    * and avoid issuing the event.
1416    */

1417    if (OS.IsWinNT) {
1418        if ((mapKey & 0x80000000) != 0) return null;
1419    } else {
1420        if ((mapKey & 0x8000) != 0) return null;
1421    }
1422    MSG msg = new MSG ();
1423    int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
1424    if (OS.PeekMessage (msg, hwnd, OS.WM_DEADCHAR, OS.WM_DEADCHAR, flags)) {
1425        display.lastDead = true;
1426        display.lastVirtual = mapKey == 0;
1427        display.lastKey = display.lastVirtual ? wParam : mapKey;
1428        return null;
1429    }
1430    
1431    /*
1432    * Bug in Windows. Somehow, the widget is becoming disposed after
1433    * calling PeekMessage(). In rare circumstances, it seems that
1434    * PeekMessage() can allow SWT listeners to run that might contain
1435    * application code that disposes the widget. It is not exactly
1436    * clear how this can happen. PeekMessage() is only looking for
1437    * WM_DEADCHAR. It is not dispatching any message that it finds
1438    * or removing any message from the queue. Cross-thread messages
1439    * are disabled. The fix is to check for a disposed widget and
1440    * return without calling the window proc.
1441    */

1442    if (isDisposed ()) return LRESULT.ONE;
1443    
1444    /*
1445    * If we are going to get a WM_CHAR, ensure that last key has
1446    * the correct character value for the key down and key up
1447    * events. It is not sufficient to ignore the WM_KEYDOWN
1448    * (when we know we are going to get a WM_CHAR) and compute
1449    * the key in WM_CHAR because there is not enough information
1450    * by the time we get the WM_CHAR. For example, when the user
1451    * types Ctrl+Shift+6 on a US keyboard, we get a WM_CHAR with
1452    * wParam=30. When the user types Ctrl+Shift+6 on a German
1453    * keyboard, we also get a WM_CHAR with wParam=30. On the US
1454    * keyboard Shift+6 is ^, on the German keyboard Shift+6 is &.
1455    * There is no way to map wParam=30 in WM_CHAR to the correct
1456    * value. Also, on international keyboards, the control key
1457    * may be down when the user has not entered a control character.
1458    *
1459    * NOTE: On Windows 98, keypad keys are virtual despite the
1460    * fact that a WM_CHAR is issued. On Windows 2000 and XP,
1461    * they are not virtual. Therefore it is necessary to force
1462    * numeric keypad keys to be virtual.
1463    */

1464    display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
1465    if (display.lastVirtual) {
1466        display.lastKey = wParam;
1467        /*
1468        * Feature in Windows. The virtual key VK_DELETE is not
1469        * treated as both a virtual key and an ASCII key by Windows.
1470        * Therefore, we will not receive a WM_CHAR for this key.
1471        * The fix is to treat VK_DELETE as a special case and map
1472        * the ASCII value explicitly (Delete is 0x7F).
1473        */

1474        if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
1475
1476        /*
1477        * It is possible to get a WM_CHAR for a virtual key when
1478        * Num Lock is on. If the user types Home while Num Lock
1479        * is down, a WM_CHAR is issued with WPARM=55 (for the
1480        * character 7). If we are going to get a WM_CHAR we need
1481        * to ensure that the last key has the correct value. Note
1482        * that Ctrl+Home does not issue a WM_CHAR when Num Lock is
1483        * down.
1484        */

1485        if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
1486            /*
1487            * Feature in Windows. Calling to ToAscii() or ToUnicode(), clears
1488            * the accented state such that the next WM_CHAR loses the accent.
1489            * This makes is critical that the accent key is detected. Also,
1490            * these functions clear the character that is entered using the
1491            * special Windows keypad sequence when NumLock is down (ie. typing
1492            * ALT+0231 should gives 'c' with a cedilla when NumLock is down).
1493            */

1494            if (display.asciiKey (display.lastKey) != 0) return null;
1495            display.lastAscii = display.numpadKey (display.lastKey);
1496        }
1497    } else {
1498        /*
1499        * Convert LastKey to lower case because Windows non-virtual
1500        * keys that are also ASCII keys, such as like VK_A, are have
1501        * upper case values in WM_KEYDOWN despite the fact that the
1502        * Shift was not pressed.
1503        */

1504        display.lastKey = OS.CharLower ((short) mapKey);
1505
1506        /*
1507        * Feature in Windows. The virtual key VK_CANCEL is treated
1508        * as both a virtual key and ASCII key by Windows. This
1509        * means that a WM_CHAR with WPARAM=3 will be issued for
1510        * this key. In order to distinguish between this key and
1511        * Ctrl+C, mark the key as virtual.
1512        */

1513        if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
1514        
1515        /*
1516        * Some key combinations map to Windows ASCII keys depending
1517        * on the keyboard. For example, Ctrl+Alt+Q maps to @ on a
1518        * German keyboard. If the current key combination is special,
1519        * the correct character is placed in wParam for processing in
1520        * WM_CHAR. If this is the case, issue the key down event from
1521        * inside WM_CHAR.
1522        */

1523        int asciiKey = display.asciiKey (wParam);
1524        if (asciiKey != 0) {
1525            /*
1526            * When the user types Ctrl+Space, ToAscii () maps this to
1527            * Space. Normally, ToAscii () maps a key to a different
1528            * key if both a WM_KEYDOWN and a WM_CHAR will be issued.
1529            * To avoid the extra SWT.KeyDown, look for a space and
1530            * issue the event from WM_CHAR.
1531            */

1532            if (asciiKey == ' ') return null;
1533            if (asciiKey != wParam) return null;
1534            /*
1535            * Feature in Windows. The virtual key VK_CANCEL is treated
1536            * as both a virtual key and ASCII key by Windows. This
1537            * means that a WM_CHAR with WPARAM=3 will be issued for
1538            * this key. To avoid the extra SWT.KeyDown, look for
1539            * VK_CANCEL and issue the event from WM_CHAR.
1540            */

1541            if (wParam == OS.VK_CANCEL) return null;
1542        }
1543        
1544        /*
1545        * If the control key is not down at this point, then
1546        * the key that was pressed was an accent key or a regular
1547        * key such as 'A' or Shift+A. In that case, issue the
1548        * key event from WM_CHAR.
1549        */

1550        if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return null;
1551        
1552        /*
1553        * Get the shifted state or convert to lower case if necessary.
1554        * If the user types Ctrl+A, LastAscii should be 'a', not 'A'.
1555        * If the user types Ctrl+Shift+A, LastAscii should be 'A'.
1556        * If the user types Ctrl+Shift+6, the value of LastAscii will
1557        * depend on the international keyboard.
1558        */

1559        if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
1560            display.lastAscii = display.shiftedKey (wParam);
1561            if (display.lastAscii == 0) display.lastAscii = mapKey;
1562        } else {
1563            display.lastAscii = OS.CharLower ((short) mapKey);
1564        }
1565                
1566        /* Note that Ctrl+'@' is ASCII NUL and is delivered in WM_CHAR */
1567        if (display.lastAscii == '@') return null;
1568        display.lastAscii = display.controlKey (display.lastAscii);
1569    }
1570    if (!sendKeyEvent (SWT.KeyDown, OS.WM_KEYDOWN, wParam, lParam)) {
1571        return LRESULT.ONE;
1572    }
1573    // widget could be disposed at this point
1574
return null;
1575}
1576
1577LRESULT wmKeyUp (int hwnd, int wParam, int lParam) {
1578    Display display = this.display;
1579    
1580    /* Check for hardware keys */
1581    if (OS.IsWinCE) {
1582        if (OS.VK_APP1 <= wParam && wParam <= OS.VK_APP6) {
1583            display.lastKey = display.lastAscii = 0;
1584            display.lastVirtual = display.lastNull = display.lastDead = false;
1585            Event event = new Event ();
1586            event.detail = wParam - OS.VK_APP1 + 1;
1587            /* Check the bit 30 to get the key state */
1588            int type = (lParam & 0x40000000) != 0 ? SWT.HardKeyUp : SWT.HardKeyDown;
1589            if (setInputState (event, type)) sendEvent (type, event);
1590            // widget could be disposed at this point
1591
return null;
1592        }
1593    }
1594    
1595    /*
1596    * If the key up is not hooked, reset last key
1597    * and last ascii in case the key down is hooked.
1598    */

1599    if (!hooks (SWT.KeyUp) && !display.filters (SWT.KeyUp)) {
1600        display.lastKey = display.lastAscii = 0;
1601        display.lastVirtual = display.lastNull = display.lastDead = false;
1602        return null;
1603    }
1604    
1605    /* Map the virtual key. */
1606    /*
1607    * Bug in WinCE. MapVirtualKey() returns incorrect values.
1608    * The fix is to rely on a key mappings table to determine
1609    * whether the key event must be sent now or if a WM_CHAR
1610    * event will follow. The key mappings table maps virtual
1611    * keys to SWT key codes and does not contain mappings for
1612    * Windows virtual keys like VK_A. Virtual keys that are
1613    * both virtual and ASCII are a special case.
1614    */

1615    int mapKey = 0;
1616    if (OS.IsWinCE) {
1617        switch (wParam) {
1618            case OS.VK_BACK: mapKey = SWT.BS; break;
1619            case OS.VK_RETURN: mapKey = SWT.CR; break;
1620            case OS.VK_DELETE: mapKey = SWT.DEL; break;
1621            case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
1622            case OS.VK_TAB: mapKey = SWT.TAB; break;
1623        }
1624    } else {
1625        mapKey = OS.MapVirtualKey (wParam, 2);
1626    }
1627
1628    /*
1629    * Bug in Windows 95 and NT. When the user types an accent key such
1630    * as ^ to get an accented character on a German keyboard, the accent
1631    * key should be ignored and the next key that the user types is the
1632    * accented key. The fix is to detect the accent key stroke (called
1633    * a dead key) by testing the high bit of the value returned by
1634    * MapVirtualKey (). A further problem is that the high bit on
1635    * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
1636    * They should both be bit 32.
1637    */

1638    if (OS.IsWinNT) {
1639        if ((mapKey & 0x80000000) != 0) return null;
1640    } else {
1641        if ((mapKey & 0x8000) != 0) return null;
1642    }
1643    if (display.lastDead) return null;
1644
1645    /*
1646    * NOTE: On Windows 98, keypad keys are virtual despite the
1647    * fact that a WM_CHAR is issued. On Windows 2000 and XP,
1648    * they are not virtual. Therefore it is necessary to force
1649    * numeric keypad keys to be virtual.
1650    */

1651    display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
1652    if (display.lastVirtual) {
1653        display.lastKey = wParam;
1654    } else {
1655        /*
1656        * Feature in Windows. The virtual key VK_CANCEL is treated
1657        * as both a virtual key and ASCII key by Windows. This
1658        * means that a WM_CHAR with WPARAM=3 will be issued for
1659        * this key. In order to distinguish between this key and
1660        * Ctrl+C, mark the key as virtual.
1661        */

1662        if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
1663        if (display.lastKey == 0) {
1664            display.lastAscii = 0;
1665            display.lastNull = display.lastDead = false;
1666            return null;
1667        }
1668    }
1669    LRESULT result = null;
1670    if (!sendKeyEvent (SWT.KeyUp, OS.WM_KEYUP, wParam, lParam)) {
1671        result = LRESULT.ONE;
1672    }
1673    // widget could be disposed at this point
1674
display.lastKey = display.lastAscii = 0;
1675    display.lastVirtual = display.lastNull = display.lastDead = false;
1676    return result;
1677}
1678
1679LRESULT wmKillFocus (int hwnd, int wParam, int lParam) {
1680    int code = callWindowProc (hwnd, OS.WM_KILLFOCUS, wParam, lParam);
1681    sendFocusEvent (SWT.FocusOut);
1682    // widget could be disposed at this point
1683

1684    /*
1685    * It is possible (but unlikely), that application
1686    * code could have disposed the widget in the focus
1687    * or deactivate events. If this happens, end the
1688    * processing of the Windows message by returning
1689    * zero as the result of the window proc.
1690    */

1691    if (isDisposed ()) return LRESULT.ZERO;
1692    if (code == 0) return LRESULT.ZERO;
1693    return new LRESULT (code);
1694}
1695
1696LRESULT wmLButtonDblClk (int hwnd, int wParam, int lParam) {
1697    /*
1698    * Feature in Windows. Windows sends the following
1699    * messages when the user double clicks the mouse:
1700    *
1701    * WM_LBUTTONDOWN - mouse down
1702    * WM_LBUTTONUP - mouse up
1703    * WM_LBUTTONDBLCLK - double click
1704    * WM_LBUTTONUP - mouse up
1705    *
1706    * Applications that expect matching mouse down/up
1707    * pairs will not see the second mouse down. The
1708    * fix is to send a mouse down event.
1709    */

1710    LRESULT result = null;
1711    Display display = this.display;
1712    display.captureChanged = false;
1713    sendMouseEvent (SWT.MouseDown, 1, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);
1714    if (sendMouseEvent (SWT.MouseDoubleClick, 1, hwnd, OS.WM_LBUTTONDBLCLK, wParam, lParam)) {
1715        result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONDBLCLK, wParam, lParam));
1716    } else {
1717        result = LRESULT.ZERO;
1718    }
1719    if (!display.captureChanged && !isDisposed ()) {
1720        if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
1721    }
1722    return result;
1723}
1724
1725LRESULT wmLButtonDown (int hwnd, int wParam, int lParam) {
1726    Display display = this.display;
1727    LRESULT result = null;
1728    int x = (short) (lParam & 0xFFFF);
1729    int y = (short) (lParam >> 16);
1730    boolean [] consume = null, detect = null;
1731    boolean dragging = false, mouseDown = true;
1732    int count = display.getClickCount (SWT.MouseDown, 1, hwnd, lParam);
1733    if (count == 1 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
1734        if (!OS.IsWinCE) {
1735            /*
1736            * Feature in Windows. It's possible that the drag
1737            * operation will not be started while the mouse is
1738            * down, meaning that the mouse should be captured.
1739            * This can happen when the user types the ESC key
1740            * to cancel the drag. The fix is to query the state
1741            * of the mouse and capture the mouse accordingly.
1742            */

1743            detect = new boolean [1];
1744            consume = new boolean [1];
1745            dragging = dragDetect (hwnd, x, y, true, detect, consume);
1746            if (isDisposed ()) return LRESULT.ZERO;
1747            mouseDown = OS.GetKeyState (OS.VK_LBUTTON) < 0;
1748        }
1749    }
1750    display.captureChanged = false;
1751    boolean dispatch = sendMouseEvent (SWT.MouseDown, 1, count, 0, false, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);
1752    if (dispatch && (consume == null || !consume [0])) {
1753        result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONDOWN, wParam, lParam));
1754    } else {
1755        result = LRESULT.ZERO;
1756    }
1757    if (OS.IsPPC) {
1758        /*
1759        * Note: On WinCE PPC, only attempt to recognize the gesture for
1760        * a context menu when the control contains a valid menu or there
1761        * are listeners for the MenuDetect event.
1762        */

1763        Menu menu = getMenu ();
1764        boolean hasMenu = menu != null && !menu.isDisposed ();
1765        if (hasMenu || hooks (SWT.MenuDetect)) {
1766            SHRGINFO shrg = new SHRGINFO ();
1767            shrg.cbSize = SHRGINFO.sizeof;
1768            shrg.hwndClient = hwnd;
1769            shrg.ptDown_x = x;
1770            shrg.ptDown_y = y;
1771            shrg.dwFlags = OS.SHRG_RETURNCMD;
1772            int type = OS.SHRecognizeGesture (shrg);
1773            if (type == OS.GN_CONTEXTMENU) showMenu (x, y);
1774        }
1775    }
1776    if (mouseDown) {
1777        if (!display.captureChanged && !isDisposed ()) {
1778            if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
1779        }
1780    }
1781    if (dragging) {
1782        sendDragEvent (1, x, y);
1783    } else {
1784        if (detect != null && detect [0]) {
1785            /*
1786            * Feature in Windows. DragDetect() captures the mouse
1787            * and tracks its movement until the user releases the
1788            * left mouse button, presses the ESC key, or moves the
1789            * mouse outside the drag rectangle. If the user moves
1790            * the mouse outside of the drag rectangle, DragDetect()
1791            * returns true and a drag and drop operation can be
1792            * started. When the left mouse button is released or
1793            * the ESC key is pressed, these events are consumed by
1794            * DragDetect() so that application code that matches
1795            * mouse down/up pairs or looks for the ESC key will not
1796            * function properly. The fix is to send the missing
1797            * events when the drag has not started.
1798            *
1799            * NOTE: For now, don't send a fake WM_KEYDOWN/WM_KEYUP
1800            * events for the ESC key. This would require computing
1801            * wParam (the key) and lParam (the repeat count, scan code,
1802            * extended-key flag, context code, previous key-state flag,
1803            * and transition-state flag) which is non-trivial.
1804            */

1805            if (OS.GetKeyState (OS.VK_ESCAPE) >= 0) {
1806                OS.SendMessage (hwnd, OS.WM_LBUTTONUP, wParam, lParam);
1807            }
1808        }
1809    }
1810    return result;
1811}
1812
1813LRESULT wmLButtonUp (int hwnd, int wParam, int lParam) {
1814    Display display = this.display;
1815    LRESULT result = null;
1816    if (sendMouseEvent (SWT.MouseUp, 1, hwnd, OS.WM_LBUTTONUP, wParam, lParam)) {
1817        result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONUP, wParam, lParam));
1818    } else {
1819        result = LRESULT.ZERO;
1820    }
1821    /*
1822    * Bug in Windows. On some machines that do not have XBUTTONs,
1823    * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
1824    * causing mouse capture to become stuck. The fix is to test
1825    * for the extra buttons only when they exist.
1826    */

1827    int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
1828    if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
1829    if (((wParam & 0xFFFF) & mask) == 0) {
1830        if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
1831    }
1832    return result;
1833}
1834
1835LRESULT wmMButtonDblClk (int hwnd, int wParam, int lParam) {
1836    /*
1837    * Feature in Windows. Windows sends the following
1838    * messages when the user double clicks the mouse:
1839    *
1840    * WM_MBUTTONDOWN - mouse down
1841    * WM_MBUTTONUP - mouse up
1842    * WM_MLBUTTONDBLCLK - double click
1843    * WM_MBUTTONUP - mouse up
1844    *
1845    * Applications that expect matching mouse down/up
1846    * pairs will not see the second mouse down. The
1847    * fix is to send a mouse down event.
1848    */

1849    LRESULT result = null;
1850    Display display = this.display;
1851    display.captureChanged = false;
1852    sendMouseEvent (SWT.MouseDown, 2, hwnd, OS.WM_MBUTTONDOWN, wParam, lParam);
1853    if (sendMouseEvent (SWT.MouseDoubleClick, 2, hwnd, OS.WM_MBUTTONDBLCLK, wParam, lParam)) {
1854        result = new LRESULT (callWindowProc (hwnd, OS.WM_MBUTTONDBLCLK, wParam, lParam));
1855    } else {
1856        result = LRESULT.ZERO;
1857    }
1858    if (!display.captureChanged && !isDisposed ()) {
1859        if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
1860    }
1861    return result;
1862}
1863
1864LRESULT wmMButtonDown (int hwnd, int wParam, int lParam) {
1865    LRESULT result = null;
1866    Display display = this.display;
1867    display.captureChanged = false;
1868    if (sendMouseEvent (SWT.MouseDown, 2, hwnd, OS.WM_MBUTTONDOWN, wParam, lParam)) {
1869        result = new LRESULT (callWindowProc (hwnd, OS.WM_MBUTTONDOWN, wParam, lParam));
1870    } else {
1871        result = LRESULT.ZERO;
1872    }
1873    if (!display.captureChanged && !isDisposed ()) {
1874        if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
1875    }
1876    return result;
1877}
1878
1879LRESULT wmMButtonUp (int hwnd, int wParam, int lParam) {
1880    Display display = this.display;
1881    LRESULT result = null;
1882    if (sendMouseEvent (SWT.MouseUp, 2, hwnd, OS.WM_MBUTTONUP, wParam, lParam)) {
1883        result = new LRESULT (callWindowProc (hwnd, OS.WM_MBUTTONUP, wParam, lParam));
1884    } else {
1885        result = LRESULT.ZERO;
1886    }
1887    /*
1888    * Bug in Windows. On some machines that do not have XBUTTONs,
1889    * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
1890    * causing mouse capture to become stuck. The fix is to test
1891    * for the extra buttons only when they exist.
1892    */

1893    int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
1894    if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
1895    if (((wParam & 0xFFFF) & mask) == 0) {
1896        if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
1897    }
1898    return result;
1899}
1900
1901LRESULT wmMouseHover (int hwnd, int wParam, int lParam) {
1902    if (!sendMouseEvent (SWT.MouseHover, 0, hwnd, OS.WM_MOUSEHOVER, wParam, lParam)) {
1903        return LRESULT.ZERO;
1904    }
1905    return null;
1906}
1907
1908LRESULT wmMouseLeave (int hwnd, int wParam, int lParam) {
1909    if (!hooks (SWT.MouseExit) && !filters (SWT.MouseExit)) return null;
1910    int pos = OS.GetMessagePos ();
1911    POINT pt = new POINT ();
1912    pt.x = (short) (pos & 0xFFFF);
1913    pt.y = (short) (pos >> 16);
1914    OS.ScreenToClient (hwnd, pt);
1915    lParam = (pt.x & 0xFFFF) | ((pt.y << 16) & 0xFFFF0000);
1916    if (!sendMouseEvent (SWT.MouseExit, 0, hwnd, OS.WM_MOUSELEAVE, wParam, lParam)) {
1917        return LRESULT.ZERO;
1918    }
1919    return null;
1920}
1921
1922LRESULT wmMouseMove (int hwnd, int wParam, int lParam) {
1923    LRESULT result = null;
1924    Display display = this.display;
1925    int pos = OS.GetMessagePos ();
1926    if (pos != display.lastMouse || display.captureChanged) {
1927        if (!OS.IsWinCE) {
1928            boolean trackMouse = (state & TRACK_MOUSE) != 0;
1929            boolean mouseEnter = hooks (SWT.MouseEnter) || display.filters (SWT.MouseEnter);
1930            boolean mouseExit = hooks (SWT.MouseExit) || display.filters (SWT.MouseExit);
1931            boolean mouseHover = hooks (SWT.MouseHover) || display.filters (SWT.MouseHover);
1932            if (trackMouse || mouseEnter || mouseExit || mouseHover) {
1933                TRACKMOUSEEVENT lpEventTrack = new TRACKMOUSEEVENT ();
1934                lpEventTrack.cbSize = TRACKMOUSEEVENT.sizeof;
1935                lpEventTrack.dwFlags = OS.TME_QUERY;
1936                lpEventTrack.hwndTrack = hwnd;
1937                OS.TrackMouseEvent (lpEventTrack);
1938                if (lpEventTrack.dwFlags == 0) {
1939                    lpEventTrack.dwFlags = OS.TME_LEAVE | OS.TME_HOVER;
1940                    lpEventTrack.hwndTrack = hwnd;
1941                    OS.TrackMouseEvent (lpEventTrack);
1942                    if (mouseEnter) {
1943                        /*
1944                        * Force all outstanding WM_MOUSELEAVE messages to be dispatched before
1945                        * issuing a mouse enter. This causes mouse exit events to be processed
1946                        * before mouse enter events. Note that WM_MOUSELEAVE is posted to the
1947                        * event queue by TrackMouseEvent().
1948                        */

1949                        MSG msg = new MSG ();
1950                        int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
1951                        while (OS.PeekMessage (msg, 0, OS.WM_MOUSELEAVE, OS.WM_MOUSELEAVE, flags)) {
1952                            OS.TranslateMessage (msg);
1953                            OS.DispatchMessage (msg);
1954                        }
1955                        sendMouseEvent (SWT.MouseEnter, 0, hwnd, OS.WM_MOUSEMOVE, wParam, lParam);
1956                    }
1957                } else {
1958                    lpEventTrack.dwFlags = OS.TME_HOVER;
1959                    OS.TrackMouseEvent (lpEventTrack);
1960                }
1961            }
1962        }
1963        if (pos != display.lastMouse) {
1964            display.lastMouse = pos;
1965            if (!sendMouseEvent (SWT.MouseMove, 0, hwnd, OS.WM_MOUSEMOVE, wParam, lParam)) {
1966                result = LRESULT.ZERO;
1967            }
1968        }
1969    }
1970    display.captureChanged = false;
1971    return result;
1972}
1973
1974LRESULT wmMouseWheel (int hwnd, int wParam, int lParam) {
1975    if (!hooks (SWT.MouseWheel) && !filters (SWT.MouseWheel)) return null;
1976    int delta = wParam >> 16;
1977    int [] value = new int [1];
1978    int count, detail;
1979    OS.SystemParametersInfo (OS.SPI_GETWHEELSCROLLLINES, 0, value, 0);
1980    if (value [0] == OS.WHEEL_PAGESCROLL) {
1981        detail = SWT.SCROLL_PAGE;
1982        count = delta / OS.WHEEL_DELTA;
1983    } else {
1984        detail = SWT.SCROLL_LINE;
1985        count = value [0] * delta / OS.WHEEL_DELTA;
1986    }
1987    POINT pt = new POINT ();
1988    pt.x = (short) (lParam & 0xFFFF);
1989    pt.y = (short) (lParam >> 16);
1990    OS.ScreenToClient (hwnd, pt);
1991    lParam = (pt.x & 0xFFFF) | ((pt.y << 16) & 0xFFFF0000);
1992    if (!sendMouseEvent (SWT.MouseWheel, 0, count, detail, true, hwnd, OS.WM_MOUSEWHEEL, wParam, lParam)) {
1993        return LRESULT.ZERO;
1994    }
1995    return null;
1996}
1997
1998LRESULT wmPaint (int hwnd, int wParam, int lParam) {
1999
2000    /* Exit early - don't draw the background */
2001    if (!hooks (SWT.Paint) && !filters (SWT.Paint)) {
2002        return null;
2003    }
2004    
2005    /* Issue a paint event */
2006    int result = 0;
2007    if (OS.IsWinCE) {
2008        RECT rect = new RECT ();
2009        OS.GetUpdateRect (hwnd, rect, false);
2010        result = callWindowProc (hwnd, OS.WM_PAINT, wParam, lParam);
2011        /*
2012        * Bug in Windows. When InvalidateRgn(), InvalidateRect()
2013        * or RedrawWindow() with RDW_INVALIDATE is called from
2014        * within WM_PAINT to invalidate a region for a further
2015        * BeginPaint(), the caret is not properly erased causing
2016        * pixel corruption. The fix is to hide and show the
2017        * caret.
2018        */

2019        OS.HideCaret (hwnd);
2020        OS.InvalidateRect (hwnd, rect, false);
2021        OS.ShowCaret (hwnd);
2022        PAINTSTRUCT ps = new PAINTSTRUCT ();
2023        GCData data = new GCData ();
2024        data.ps = ps;
2025        data.hwnd = hwnd;
2026        GC gc = new_GC (data);
2027        if (gc != null) {
2028            int width = ps.right - ps.left;
2029            int height = ps.bottom - ps.top;
2030            if (width != 0 && height != 0) {
2031                Event event = new Event ();
2032                event.gc = gc;
2033                event.x = ps.left;
2034                event.y = ps.top;
2035                event.width = width;
2036                event.height = height;
2037                sendEvent (SWT.Paint, event);
2038                // widget could be disposed at this point
2039
event.gc = null;
2040            }
2041            gc.dispose ();
2042        }
2043    } else {
2044        int rgn = OS.CreateRectRgn (0, 0, 0, 0);
2045        OS.GetUpdateRgn (hwnd, rgn, false);
2046        result = callWindowProc (hwnd, OS.WM_PAINT, wParam, lParam);
2047        GCData data = new GCData ();
2048        data.hwnd = hwnd;
2049        GC gc = new_GC (data);
2050        if (gc != null) {
2051            OS.HideCaret (hwnd);
2052            RECT rect = new RECT();
2053            OS.GetRgnBox (rgn, rect);
2054            int width = rect.right - rect.left;
2055            int height = rect.bottom - rect.top;
2056            if (width != 0 && height != 0) {
2057                int hDC = gc.handle;
2058                OS.SelectClipRgn (hDC, rgn);
2059                OS.SetMetaRgn (hDC);
2060                Event event = new Event ();
2061                event.gc = gc;
2062                event.x = rect.left;
2063                event.y = rect.top;
2064                event.width = width;
2065                event.height = height;
2066                sendEvent (SWT.Paint, event);
2067                // widget could be disposed at this point
2068
event.gc = null;
2069            }
2070            gc.dispose ();
2071            OS.ShowCaret (hwnd);
2072        }
2073        OS.DeleteObject (rgn);
2074    }
2075    if (result == 0) return LRESULT.ZERO;
2076    return new LRESULT (result);
2077}
2078
2079LRESULT wmPrint (int hwnd, int wParam, int lParam) {
2080    /*
2081    * Bug in Windows. When WM_PRINT is used to print the contents
2082    * of a control that has WS_EX_CLIENTEDGE, the old 3D border is
2083    * drawn instead of the theme border. The fix is to call the
2084    * default window proc and then draw the theme border on top.
2085    */

2086    if ((lParam & OS.PRF_NONCLIENT) != 0) {
2087        if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
2088            int bits = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE);
2089            if ((bits & OS.WS_EX_CLIENTEDGE) != 0) {
2090                int code = callWindowProc (hwnd, OS.WM_PRINT, wParam, lParam);
2091                RECT rect = new RECT ();
2092                OS.GetWindowRect (hwnd, rect);
2093                rect.right -= rect.left;
2094                rect.bottom -= rect.top;
2095                rect.left = rect.top = 0;
2096                int border = OS.GetSystemMetrics (OS.SM_CXEDGE);
2097                OS.ExcludeClipRect (wParam, border, border, rect.right - border, rect.bottom - border);
2098                OS.DrawThemeBackground (display.hEditTheme (), wParam, OS.EP_EDITTEXT, OS.ETS_NORMAL, rect, null);
2099                return new LRESULT (code);
2100            }
2101        }
2102    }
2103    return null;
2104}
2105
2106LRESULT wmRButtonDblClk (int hwnd, int wParam, int lParam) {
2107    /*
2108    * Feature in Windows. Windows sends the following
2109    * messages when the user double clicks the mouse:
2110    *
2111    * WM_RBUTTONDOWN - mouse down
2112    * WM_RBUTTONUP - mouse up
2113    * WM_RBUTTONDBLCLK - double click
2114    * WM_LBUTTONUP - mouse up
2115    *
2116    * Applications that expect matching mouse down/up
2117    * pairs will not see the second mouse down. The
2118    * fix is to send a mouse down event.
2119    */

2120    LRESULT result = null;
2121    Display display = this.display;
2122    display.captureChanged = false;
2123    sendMouseEvent (SWT.MouseDown, 3, hwnd, OS.WM_RBUTTONDOWN, wParam, lParam);
2124    if (sendMouseEvent (SWT.MouseDoubleClick, 3, hwnd, OS.WM_RBUTTONDBLCLK, wParam, lParam)) {
2125        result = new LRESULT (callWindowProc (hwnd, OS.WM_RBUTTONDBLCLK, wParam, lParam));
2126    } else {
2127        result = LRESULT.ZERO;
2128    }
2129    if (!display.captureChanged && !isDisposed ()) {
2130        if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2131    }
2132    return result;
2133}
2134
2135LRESULT wmRButtonDown (int hwnd, int wParam, int lParam) {
2136    LRESULT result = null;
2137    Display display = this.display;
2138    display.captureChanged = false;
2139    if (sendMouseEvent (SWT.MouseDown, 3, hwnd, OS.WM_RBUTTONDOWN, wParam, lParam)) {
2140        result = new LRESULT (callWindowProc (hwnd, OS.WM_RBUTTONDOWN, wParam, lParam));
2141    } else {
2142        result = LRESULT.ZERO;
2143    }
2144    if (!display.captureChanged && !isDisposed ()) {
2145        if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2146    }
2147    return result;
2148}
2149
2150LRESULT wmRButtonUp (int hwnd, int wParam, int lParam) {
2151    Display display = this.display;
2152    LRESULT result = null;
2153    if (sendMouseEvent (SWT.MouseUp, 3, hwnd, OS.WM_RBUTTONUP, wParam, lParam)) {
2154        result = new LRESULT (callWindowProc (hwnd, OS.WM_RBUTTONUP, wParam, lParam));
2155    } else {
2156        /* Call the DefWindowProc() to support WM_CONTEXTMENU */
2157        OS.DefWindowProc (hwnd, OS.WM_RBUTTONUP, wParam, lParam);
2158        result = LRESULT.ZERO;
2159    }
2160    /*
2161    * Bug in Windows. On some machines that do not have XBUTTONs,
2162    * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
2163    * causing mouse capture to become stuck. The fix is to test
2164    * for the extra buttons only when they exist.
2165    */

2166    int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
2167    if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
2168    if (((wParam & 0xFFFF) & mask) == 0) {
2169        if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
2170    }
2171    return result;
2172}
2173
2174LRESULT wmSetFocus (int hwnd, int wParam, int lParam) {
2175    int code = callWindowProc (hwnd, OS.WM_SETFOCUS, wParam, lParam);
2176    sendFocusEvent (SWT.FocusIn);
2177    // widget could be disposed at this point
2178

2179    /*
2180    * It is possible (but unlikely), that application
2181    * code could have disposed the widget in the focus
2182    * or activate events. If this happens, end the
2183    * processing of the Windows message by returning
2184    * zero as the result of the window proc.
2185    */

2186    if (isDisposed ()) return LRESULT.ZERO;
2187    if (code == 0) return LRESULT.ZERO;
2188    return new LRESULT (code);
2189}
2190
2191LRESULT wmSysChar (int hwnd, int wParam, int lParam) {
2192    Display display = this.display;
2193    display.lastAscii = wParam;
2194    display.lastNull = wParam == 0;
2195
2196    /* Do not issue a key down if a menu bar mnemonic was invoked */
2197    if (!hooks (SWT.KeyDown) && !display.filters (SWT.KeyDown)) {
2198        return null;
2199    }
2200    
2201    /* Call the window proc to determine whether it is a system key or mnemonic */
2202    boolean oldKeyHit = display.mnemonicKeyHit;
2203    display.mnemonicKeyHit = true;
2204    int result = callWindowProc (hwnd, OS.WM_SYSCHAR, wParam, lParam);
2205    boolean consumed = false;
2206    if (!display.mnemonicKeyHit) {
2207        consumed = !sendKeyEvent (SWT.KeyDown, OS.WM_SYSCHAR, wParam, lParam);
2208        // widget could be disposed at this point
2209
}
2210    consumed |= display.mnemonicKeyHit;
2211    display.mnemonicKeyHit = oldKeyHit;
2212    return consumed ? LRESULT.ONE : new LRESULT (result);
2213}
2214
2215LRESULT wmSysKeyDown (int hwnd, int wParam, int lParam) {
2216    /*
2217    * Feature in Windows. When WM_SYSKEYDOWN is sent,
2218    * the user pressed ALT+<key> or F10 to get to the
2219    * menu bar. In order to issue events for F10 but
2220    * ignore other key presses when the ALT is not down,
2221    * make sure that either F10 was pressed or that ALT
2222    * is pressed.
2223    */

2224    if (wParam != OS.VK_F10) {
2225        /* Make sure WM_SYSKEYDOWN was sent by ALT-<aKey>. */
2226        if ((lParam & 0x20000000) == 0) return null;
2227    }
2228    
2229    /* Ignore well known system keys */
2230    switch (wParam) {
2231        case OS.VK_F4: {
2232            int hwndShell = hwnd;
2233            while (OS.GetParent (hwndShell) != 0) {
2234                if (OS.GetWindow (hwndShell, OS.GW_OWNER) != 0) break;
2235                hwndShell = OS.GetParent (hwndShell);
2236            }
2237            int bits = OS.GetWindowLong (hwndShell, OS.GWL_STYLE);
2238            if ((bits & OS.WS_SYSMENU) != 0) return null;
2239        }
2240    }
2241    
2242    /* Ignore repeating modifier keys by testing key down state */
2243    switch (wParam) {
2244        case OS.VK_SHIFT:
2245        case OS.VK_MENU:
2246        case OS.VK_CONTROL:
2247        case OS.VK_CAPITAL:
2248        case OS.VK_NUMLOCK:
2249        case OS.VK_SCROLL:
2250            if ((lParam & 0x40000000) != 0) return null;
2251    }
2252    
2253    /* Clear last key and last ascii because a new key has been typed */
2254    display.lastAscii = display.lastKey = 0;
2255    display.lastVirtual = display.lastNull = display.lastDead = false;
2256
2257    /* If are going to get a WM_SYSCHAR, ignore this message. */
2258    /*
2259    * Bug in WinCE. MapVirtualKey() returns incorrect values.
2260    * The fix is to rely on a key mappings table to determine
2261    * whether the key event must be sent now or if a WM_CHAR
2262    * event will follow. The key mappings table maps virtual
2263    * keys to SWT key codes and does not contain mappings for
2264    * Windows virtual keys like VK_A. Virtual keys that are
2265    * both virtual and ASCII are a special case.
2266    */

2267    int mapKey = 0;
2268    if (OS.IsWinCE) {
2269        switch (wParam) {
2270            case OS.VK_BACK: mapKey = SWT.BS; break;
2271            case OS.VK_RETURN: mapKey = SWT.CR; break;
2272            case OS.VK_DELETE: mapKey = SWT.DEL; break;
2273            case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
2274            case OS.VK_TAB: mapKey = SWT.TAB; break;
2275        }
2276    } else {
2277        mapKey = OS.MapVirtualKey (wParam, 2);
2278    }
2279    display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
2280    if (display.lastVirtual) {
2281        display.lastKey = wParam;
2282        /*
2283        * Feature in Windows. The virtual key VK_DELETE is not
2284        * treated as both a virtual key and an ASCII key by Windows.
2285        * Therefore, we will not receive a WM_SYSCHAR for this key.
2286        * The fix is to treat VK_DELETE as a special case and map
2287        * the ASCII value explicitly (Delete is 0x7F).
2288        */

2289        if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
2290
2291        /* When a keypad key is typed, a WM_SYSCHAR is not issued */
2292        if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
2293            /*
2294            * A WM_SYSCHAR will be issued for '*', '+', '-', '.' and '/'
2295            * on the numeric keypad. Avoid issuing the key event twice
2296            * by checking for these keys. Note that calling to ToAscii()
2297            * or ToUnicode(), clear the character that is entered using
2298            * the special Windows keypad sequence when NumLock is down
2299            * (ie. typing ALT+0231 should gives 'c' with a cedilla when
2300            * NumLock is down). Do not call either of these from here.
2301            */

2302            switch (display.lastKey) {
2303                case OS.VK_MULTIPLY:
2304                case OS.VK_ADD:
2305                case OS.VK_SUBTRACT:
2306                case OS.VK_DECIMAL:
2307                case OS.VK_DIVIDE: return null;
2308            }
2309            display.lastAscii = display.numpadKey (display.lastKey);
2310        }
2311    } else {
2312        /*
2313        * Convert LastKey to lower case because Windows non-virtual
2314        * keys that are also ASCII keys, such as like VK_A, are have
2315        * upper case values in WM_SYSKEYDOWN despite the fact that the
2316        * Shift was not pressed.
2317        */

2318        display.lastKey = OS.CharLower ((short) mapKey);
2319
2320        /*
2321        * Feature in Windows 98. MapVirtualKey() indicates that
2322        * a WM_SYSCHAR message will occur for Alt+Enter but
2323        * this message never happens. The fix is to issue the
2324        * event from WM_SYSKEYDOWN and map VK_RETURN to '\r'.
2325        */

2326        if (OS.IsWinNT) return null;
2327        if (wParam != OS.VK_RETURN) return null;
2328        display.lastAscii = '\r';
2329    }
2330
2331    if (!sendKeyEvent (SWT.KeyDown, OS.WM_SYSKEYDOWN, wParam, lParam)) {
2332        return LRESULT.ONE;
2333    }
2334    // widget could be disposed at this point
2335
return null;
2336}
2337
2338LRESULT wmSysKeyUp (int hwnd, int wParam, int lParam) {
2339    return wmKeyUp (hwnd, wParam, lParam);
2340}
2341
2342LRESULT wmXButtonDblClk (int hwnd, int wParam, int lParam) {
2343    /*
2344    * Feature in Windows. Windows sends the following
2345    * messages when the user double clicks the mouse:
2346    *
2347    * WM_XBUTTONDOWN - mouse down
2348    * WM_XBUTTONUP - mouse up
2349    * WM_XLBUTTONDBLCLK - double click
2350    * WM_XBUTTONUP - mouse up
2351    *
2352    * Applications that expect matching mouse down/up
2353    * pairs will not see the second mouse down. The
2354    * fix is to send a mouse down event.
2355    */

2356    LRESULT result = null;
2357    Display display = this.display;
2358    display.captureChanged = false;
2359    int button = (wParam >> 16 == OS.XBUTTON1) ? 4 : 5;
2360    sendMouseEvent (SWT.MouseDown, button, hwnd, OS.WM_XBUTTONDOWN, wParam, lParam);
2361    if (sendMouseEvent (SWT.MouseDoubleClick, button, hwnd, OS.WM_XBUTTONDBLCLK, wParam, lParam)) {
2362        result = new LRESULT (callWindowProc (hwnd, OS.WM_XBUTTONDBLCLK, wParam, lParam));
2363    } else {
2364        result = LRESULT.ZERO;
2365    }
2366    if (!display.captureChanged && !isDisposed ()) {
2367        if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2368    }
2369    return result;
2370}
2371
2372LRESULT wmXButtonDown (int hwnd, int wParam, int lParam) {
2373    LRESULT result = null;
2374    Display display = this.display;
2375    display.captureChanged = false;
2376    display.xMouse = true;
2377    int button = (wParam >> 16 == OS.XBUTTON1) ? 4 : 5;
2378    if (sendMouseEvent (SWT.MouseDown, button, hwnd, OS.WM_XBUTTONDOWN, wParam, lParam)) {
2379        result = new LRESULT (callWindowProc (hwnd, OS.WM_XBUTTONDOWN, wParam, lParam));
2380    } else {
2381        result = LRESULT.ZERO;
2382    }
2383    if (!display.captureChanged && !isDisposed ()) {
2384        if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2385    }
2386    return result;
2387}
2388
2389LRESULT wmXButtonUp (int hwnd, int wParam, int lParam) {
2390    Display display = this.display;
2391    LRESULT result = null;
2392    int button = (wParam >> 16 == OS.XBUTTON1) ? 4 : 5;
2393    if (sendMouseEvent (SWT.MouseUp, button, hwnd, OS.WM_XBUTTONUP, wParam, lParam)) {
2394        result = new LRESULT (callWindowProc (hwnd, OS.WM_XBUTTONUP, wParam, lParam));
2395    } else {
2396        result = LRESULT.ZERO;
2397    }
2398    /*
2399    * Bug in Windows. On some machines that do not have XBUTTONs,
2400    * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
2401    * causing mouse capture to become stuck. The fix is to test
2402    * for the extra buttons only when they exist.
2403    */

2404    int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
2405    if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
2406    if (((wParam & 0xFFFF) & mask) == 0) {
2407        if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
2408    }
2409    return result;
2410}
2411}
2412
Popular Tags