]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Widget.java
ad1f538449c05c6f869e82f7e4203e27a7e64cbf
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / Widget.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Pierre-Yves B., pyvesdev@gmail.com - Bug 219750: [styled text] Typing ~~ inserts é~~
14  *******************************************************************************/
15 package org.eclipse.swt.widgets;
16
17
18 import org.eclipse.swt.*;
19 import org.eclipse.swt.events.*;
20 import org.eclipse.swt.graphics.*;
21 import org.eclipse.swt.internal.*;
22 import org.eclipse.swt.internal.win32.*;
23
24 /**
25  * This class is the abstract superclass of all user interface objects.
26  * Widgets are created, disposed and issue notification to listeners
27  * when events occur which affect them.
28  * <dl>
29  * <dt><b>Styles:</b></dt>
30  * <dd>(none)</dd>
31  * <dt><b>Events:</b></dt>
32  * <dd>Dispose</dd>
33  * </dl>
34  * <p>
35  * IMPORTANT: This class is intended to be subclassed <em>only</em>
36  * within the SWT implementation. However, it has not been marked
37  * final to allow those outside of the SWT development team to implement
38  * patched versions of the class in order to get around specific
39  * limitations in advance of when those limitations can be addressed
40  * by the team.  Any class built using subclassing to access the internals
41  * of this class will likely fail to compile or run between releases and
42  * may be strongly platform specific. Subclassing should not be attempted
43  * without an intimate and detailed understanding of the workings of the
44  * hierarchy. No support is provided for user-written classes which are
45  * implemented as subclasses of this class.
46  * </p>
47  *
48  * @see #checkSubclass
49  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
50  */
51 public abstract class Widget {
52         int style, state;
53         Display display;
54         EventTable eventTable;
55         Object data;
56
57         /* Global state flags */
58         static final int DISPOSED               = 1<<0;
59         static final int CANVAS                 = 1<<1;
60         static final int KEYED_DATA             = 1<<2;
61         static final int DISABLED               = 1<<3;
62         static final int HIDDEN                 = 1<<4;
63
64         /* A layout was requested on this widget */
65         static final int LAYOUT_NEEDED  = 1<<5;
66
67         /* The preferred size of a child has changed */
68         static final int LAYOUT_CHANGED = 1<<6;
69
70         /* A layout was requested in this widget hierarchy */
71         static final int LAYOUT_CHILD = 1<<7;
72
73         /* Background flags */
74         static final int THEME_BACKGROUND = 1<<8;
75         static final int DRAW_BACKGROUND = 1<<9;
76         static final int PARENT_BACKGROUND = 1<<10;
77
78         /* Dispose and release flags */
79         static final int RELEASED               = 1<<11;
80         static final int DISPOSE_SENT   = 1<<12;
81
82         /* More global widget state flags */
83         static final int TRACK_MOUSE    = 1<<13;
84         static final int FOREIGN_HANDLE = 1<<14;
85         static final int DRAG_DETECT    = 1<<15;
86
87         /* Move and resize state flags */
88         static final int MOVE_OCCURRED          = 1<<16;
89         static final int MOVE_DEFERRED          = 1<<17;
90         static final int RESIZE_OCCURRED        = 1<<18;
91         static final int RESIZE_DEFERRED        = 1<<19;
92
93         /* Ignore WM_CHANGEUISTATE */
94         static final int IGNORE_WM_CHANGEUISTATE = 1<<20;
95
96         /* Notify of the opportunity to skin this widget */
97         static final int SKIN_NEEDED = 1<<21;
98
99         /* Bidi "auto" text direction */
100         static final int HAS_AUTO_DIRECTION = 1<<22;
101
102         /* Default size for widgets */
103         static final int DEFAULT_WIDTH  = 64;
104         static final int DEFAULT_HEIGHT = 64;
105
106         /* Bidi UCC to enforce text direction */
107         static final char LRE = '\u202a';
108         static final char RLE = '\u202b';
109
110         /* Bidi flag and for auto text direction */
111         static final int AUTO_TEXT_DIRECTION = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
112
113         /* Initialize the Common Controls DLL */
114         static {
115                 OS.InitCommonControls ();
116         }
117
118 /**
119  * Prevents uninitialized instances from being created outside the package.
120  */
121 Widget () {
122 }
123
124 /**
125  * Constructs a new instance of this class given its parent
126  * and a style value describing its behavior and appearance.
127  * <p>
128  * The style value is either one of the style constants defined in
129  * class <code>SWT</code> which is applicable to instances of this
130  * class, or must be built by <em>bitwise OR</em>'ing together
131  * (that is, using the <code>int</code> "|" operator) two or more
132  * of those <code>SWT</code> style constants. The class description
133  * lists the style constants that are applicable to the class.
134  * Style bits are also inherited from superclasses.
135  * </p>
136  *
137  * @param parent a widget which will be the parent of the new instance (cannot be null)
138  * @param style the style of widget to construct
139  *
140  * @exception IllegalArgumentException <ul>
141  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
142  *    <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
143  * </ul>
144  * @exception SWTException <ul>
145  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
146  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
147  * </ul>
148  *
149  * @see SWT
150  * @see #checkSubclass
151  * @see #getStyle
152  */
153 public Widget (Widget parent, int style) {
154         checkSubclass ();
155         checkParent (parent);
156         this.style = style;
157         display = parent.display;
158         reskinWidget ();
159 }
160
161 void _addListener (int eventType, Listener listener) {
162         if (eventTable == null) eventTable = new EventTable ();
163         eventTable.hook (eventType, listener);
164 }
165
166 void _removeListener (int eventType, Listener listener) {
167         if (eventTable == null) return;
168         eventTable.unhook (eventType, listener);
169 }
170
171 /**
172  * Adds the listener to the collection of listeners who will
173  * be notified when an event of the given type occurs. When the
174  * event does occur in the widget, the listener is notified by
175  * sending it the <code>handleEvent()</code> message. The event
176  * type is one of the event constants defined in class <code>SWT</code>.
177  *
178  * @param eventType the type of event to listen for
179  * @param listener the listener which should be notified when the event occurs
180  *
181  * @exception IllegalArgumentException <ul>
182  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
183  * </ul>
184  * @exception SWTException <ul>
185  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
186  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
187  * </ul>
188  *
189  * @see Listener
190  * @see SWT
191  * @see #getListeners(int)
192  * @see #removeListener(int, Listener)
193  * @see #notifyListeners
194  */
195 public void addListener (int eventType, Listener listener) {
196         checkWidget();
197         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
198         _addListener (eventType, listener);
199 }
200
201 /**
202  * Adds the listener to the collection of listeners who will
203  * be notified when the widget is disposed. When the widget is
204  * disposed, the listener is notified by sending it the
205  * <code>widgetDisposed()</code> message.
206  *
207  * @param listener the listener which should be notified when the receiver is disposed
208  *
209  * @exception IllegalArgumentException <ul>
210  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
211  * </ul>
212  * @exception SWTException <ul>
213  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
214  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
215  * </ul>
216  *
217  * @see DisposeListener
218  * @see #removeDisposeListener
219  */
220 public void addDisposeListener (DisposeListener listener) {
221         checkWidget();
222         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
223         TypedListener typedListener = new TypedListener (listener);
224         addListener (SWT.Dispose, typedListener);
225 }
226
227 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
228         return 0;
229 }
230
231 /**
232  * Returns a style with exactly one style bit set out of
233  * the specified set of exclusive style bits. All other
234  * possible bits are cleared when the first matching bit
235  * is found. Bits that are not part of the possible set
236  * are untouched.
237  *
238  * @param style the original style bits
239  * @param int0 the 0th possible style bit
240  * @param int1 the 1st possible style bit
241  * @param int2 the 2nd possible style bit
242  * @param int3 the 3rd possible style bit
243  * @param int4 the 4th possible style bit
244  * @param int5 the 5th possible style bit
245  *
246  * @return the new style bits
247  */
248 static int checkBits (int style, int int0, int int1, int int2, int int3, int int4, int int5) {
249         int mask = int0 | int1 | int2 | int3 | int4 | int5;
250         if ((style & mask) == 0) style |= int0;
251         if ((style & int0) != 0) style = (style & ~mask) | int0;
252         if ((style & int1) != 0) style = (style & ~mask) | int1;
253         if ((style & int2) != 0) style = (style & ~mask) | int2;
254         if ((style & int3) != 0) style = (style & ~mask) | int3;
255         if ((style & int4) != 0) style = (style & ~mask) | int4;
256         if ((style & int5) != 0) style = (style & ~mask) | int5;
257         return style;
258 }
259
260 void checkOrientation (Widget parent) {
261         style &= ~SWT.MIRRORED;
262         if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) {
263                 if (parent != null) {
264                         if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) style |= SWT.LEFT_TO_RIGHT;
265                         if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.RIGHT_TO_LEFT;
266                 }
267         }
268         style = checkBits (style, SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
269 }
270
271 void checkOpened () {
272         /* Do nothing */
273 }
274
275 /**
276  * Throws an exception if the specified widget can not be
277  * used as a parent for the receiver.
278  *
279  * @exception IllegalArgumentException <ul>
280  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
281  *    <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li>
282  * </ul>
283  * @exception SWTException <ul>
284  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
285  * </ul>
286  */
287 void checkParent (Widget parent) {
288         if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
289         if (parent.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
290         parent.checkWidget ();
291         parent.checkOpened ();
292 }
293
294 /**
295  * Checks that this class can be subclassed.
296  * <p>
297  * The SWT class library is intended to be subclassed
298  * only at specific, controlled points (most notably,
299  * <code>Composite</code> and <code>Canvas</code> when
300  * implementing new widgets). This method enforces this
301  * rule unless it is overridden.
302  * </p><p>
303  * <em>IMPORTANT:</em> By providing an implementation of this
304  * method that allows a subclass of a class which does not
305  * normally allow subclassing to be created, the implementer
306  * agrees to be fully responsible for the fact that any such
307  * subclass will likely fail between SWT releases and will be
308  * strongly platform specific. No support is provided for
309  * user-written classes which are implemented in this fashion.
310  * </p><p>
311  * The ability to subclass outside of the allowed SWT classes
312  * is intended purely to enable those not on the SWT development
313  * team to implement patches in order to get around specific
314  * limitations in advance of when those limitations can be
315  * addressed by the team. Subclassing should not be attempted
316  * without an intimate and detailed understanding of the hierarchy.
317  * </p>
318  *
319  * @exception SWTException <ul>
320  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
321  * </ul>
322  */
323 protected void checkSubclass () {
324         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
325 }
326
327 /**
328  * Throws an <code>SWTException</code> if the receiver can not
329  * be accessed by the caller. This may include both checks on
330  * the state of the receiver and more generally on the entire
331  * execution context. This method <em>should</em> be called by
332  * widget implementors to enforce the standard SWT invariants.
333  * <p>
334  * Currently, it is an error to invoke any method (other than
335  * <code>isDisposed()</code>) on a widget that has had its
336  * <code>dispose()</code> method called. It is also an error
337  * to call widget methods from any thread that is different
338  * from the thread that created the widget.
339  * </p><p>
340  * In future releases of SWT, there may be more or fewer error
341  * checks and exceptions may be thrown for different reasons.
342  * </p>
343  *
344  * @exception SWTException <ul>
345  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
346  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
347  * </ul>
348  */
349 protected void checkWidget () {
350         Display display = this.display;
351         if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
352         if (display.thread != Thread.currentThread ()) {
353                 /*
354                 * Bug in IBM JVM 1.6.  For some reason, under
355                 * conditions that are yet to be full understood,
356                 * Thread.currentThread() is either returning null
357                 * or a different instance from the one that was
358                 * saved when the Display was created.  This is
359                 * possibly a JIT problem because modifying this
360                 * method to print logging information when the
361                 * error happens seems to fix the problem.  The
362                 * fix is to use operating system calls to verify
363                 * that the current thread is not the Display thread.
364                 *
365                 * NOTE: Despite the fact that Thread.currentThread()
366                 * is used in other places, the failure has not been
367                 * observed in all places where it is called.
368                 */
369                 if (display.threadId != OS.GetCurrentThreadId ()) {
370                         error (SWT.ERROR_THREAD_INVALID_ACCESS);
371                 }
372         }
373         if ((state & DISPOSED) != 0) error (SWT.ERROR_WIDGET_DISPOSED);
374 }
375
376 /**
377  * Destroys the widget in the operating system and releases
378  * the widget's handle.  If the widget does not have a handle,
379  * this method may hide the widget, mark the widget as destroyed
380  * or do nothing, depending on the widget.
381  * <p>
382  * When a widget is destroyed in the operating system, its
383  * descendants are also destroyed by the operating system.
384  * This means that it is only necessary to call <code>destroyWidget</code>
385  * on the root of the widget tree.
386  * </p><p>
387  * This method is called after <code>releaseWidget()</code>.
388  * </p><p>
389  * See also <code>releaseChild()</code>, <code>releaseWidget()</code>
390  * and <code>releaseHandle()</code>.
391  * </p>
392  *
393  * @see #dispose
394  */
395 void destroyWidget () {
396         releaseHandle ();
397 }
398
399 /**
400  * Disposes of the operating system resources associated with
401  * the receiver and all its descendants. After this method has
402  * been invoked, the receiver and all descendants will answer
403  * <code>true</code> when sent the message <code>isDisposed()</code>.
404  * Any internal connections between the widgets in the tree will
405  * have been removed to facilitate garbage collection.
406  * This method does nothing if the widget is already disposed.
407  * <p>
408  * NOTE: This method is not called recursively on the descendants
409  * of the receiver. This means that, widget implementers can not
410  * detect when a widget is being disposed of by re-implementing
411  * this method, but should instead listen for the <code>Dispose</code>
412  * event.
413  * </p>
414  *
415  * @exception SWTException <ul>
416  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
417  * </ul>
418  *
419  * @see #addDisposeListener
420  * @see #removeDisposeListener
421  * @see #checkWidget
422  */
423 public void dispose () {
424         /*
425         * Note:  It is valid to attempt to dispose a widget
426         * more than once.  If this happens, fail silently.
427         */
428         if (isDisposed ()) return;
429         if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
430         release (true);
431 }
432
433 boolean dragDetect (long hwnd, int x, int y, boolean filter, boolean [] detect, boolean [] consume) {
434         if (consume != null) consume [0] = false;
435         if (detect != null) detect [0] = true;
436         POINT pt = new POINT ();
437         pt.x = x;
438         pt.y = y;
439         OS.ClientToScreen (hwnd, pt);
440         return OS.DragDetect (hwnd, pt);
441 }
442
443 /**
444  * Does whatever widget specific cleanup is required, and then
445  * uses the code in <code>SWTError.error</code> to handle the error.
446  *
447  * @param code the descriptive error code
448  *
449  * @see SWT#error(int)
450  */
451 void error (int code) {
452         SWT.error(code);
453 }
454
455 boolean filters (int eventType) {
456         return display.filters (eventType);
457 }
458
459 Widget findItem (long id) {
460         return null;
461 }
462
463 char [] fixMnemonic (String string) {
464         return fixMnemonic (string, false, false);
465 }
466
467 char [] fixMnemonic (String string, boolean spaces) {
468         return fixMnemonic (string, spaces, false);
469 }
470
471 char [] fixMnemonic (String string, boolean spaces, boolean removeAppended) {
472         // fixMnemonic must return a null-terminated array
473         char [] buffer = new char [string.length () + 1];
474         string.getChars (0, string.length (), buffer, 0);
475         int i = 0, j = 0;
476         while (i < buffer.length) {
477                 if (buffer [i] == '&') {
478                         if (i + 1 < buffer.length && buffer [i + 1] == '&') {
479                                 buffer [j++] = spaces ? ' ' : buffer [i];
480                                 i++;
481                         }
482                         i++;
483                 } else if (buffer [i] == '(' && removeAppended && i + 4 == string.length () && buffer [i + 1] == '&' && buffer [i + 3] == ')') {
484                         if (spaces) buffer [j++] = ' ';
485                         i += 4;
486                 } else {
487                         buffer [j++] = buffer [i++];
488                 }
489         }
490         while (j < buffer.length) buffer [j++] = 0;
491         return buffer;
492 }
493
494 /**
495  * Returns the application defined widget data associated
496  * with the receiver, or null if it has not been set. The
497  * <em>widget data</em> is a single, unnamed field that is
498  * stored with every widget.
499  * <p>
500  * Applications may put arbitrary objects in this field. If
501  * the object stored in the widget data needs to be notified
502  * when the widget is disposed of, it is the application's
503  * responsibility to hook the Dispose event on the widget and
504  * do so.
505  * </p>
506  *
507  * @return the widget data
508  *
509  * @exception SWTException <ul>
510  *    <li>ERROR_WIDGET_DISPOSED - when the receiver has been disposed</li>
511  *    <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li>
512  * </ul>
513  *
514  * @see #setData(Object)
515  */
516 public Object getData () {
517         checkWidget();
518         return (state & KEYED_DATA) != 0 ? ((Object []) data) [0] : data;
519 }
520
521 /**
522  * Returns the application defined property of the receiver
523  * with the specified name, or null if it has not been set.
524  * <p>
525  * Applications may have associated arbitrary objects with the
526  * receiver in this fashion. If the objects stored in the
527  * properties need to be notified when the widget is disposed
528  * of, it is the application's responsibility to hook the
529  * Dispose event on the widget and do so.
530  * </p>
531  *
532  * @param       key the name of the property
533  * @return the value of the property or null if it has not been set
534  *
535  * @exception IllegalArgumentException <ul>
536  *    <li>ERROR_NULL_ARGUMENT - if the key is null</li>
537  * </ul>
538  * @exception SWTException <ul>
539  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
540  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
541  * </ul>
542  *
543  * @see #setData(String, Object)
544  */
545 public Object getData (String key) {
546         checkWidget();
547         if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
548         if ((state & KEYED_DATA) != 0) {
549                 Object [] table = (Object []) data;
550                 for (int i=1; i<table.length; i+=2) {
551                         if (key.equals (table [i])) return table [i+1];
552                 }
553         }
554         return null;
555 }
556
557 /**
558  * Returns the <code>Display</code> that is associated with
559  * the receiver.
560  * <p>
561  * A widget's display is either provided when it is created
562  * (for example, top level <code>Shell</code>s) or is the
563  * same as its parent's display.
564  * </p>
565  *
566  * @return the receiver's display
567  *
568  * @exception SWTException <ul>
569  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
570  * </ul>
571  */
572 public Display getDisplay () {
573         Display display = this.display;
574         if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
575         return display;
576 }
577
578 /**
579  * Returns an array of listeners who will be notified when an event
580  * of the given type occurs. The event type is one of the event constants
581  * defined in class <code>SWT</code>.
582  *
583  * @param eventType the type of event to listen for
584  * @return an array of listeners that will be notified when the event occurs
585  *
586  * @exception SWTException <ul>
587  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
588  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
589  * </ul>
590  *
591  * @see Listener
592  * @see SWT
593  * @see #addListener(int, Listener)
594  * @see #removeListener(int, Listener)
595  * @see #notifyListeners
596  *
597  * @since 3.4
598  */
599 public Listener[] getListeners (int eventType) {
600         checkWidget();
601         if (eventTable == null) return new Listener[0];
602         return eventTable.getListeners(eventType);
603 }
604
605 Menu getMenu () {
606         return null;
607 }
608
609 /**
610  * Returns the name of the widget. This is the name of
611  * the class without the package name.
612  *
613  * @return the name of the widget
614  */
615 String getName () {
616         String string = getClass ().getName ();
617         int index = string.lastIndexOf ('.');
618         if (index == -1) return string;
619         return string.substring (index + 1, string.length ());
620 }
621
622 /*
623  * Returns a short printable representation for the contents
624  * of a widget. For example, a button may answer the label
625  * text. This is used by <code>toString</code> to provide a
626  * more meaningful description of the widget.
627  *
628  * @return the contents string for the widget
629  *
630  * @see #toString
631  */
632 String getNameText () {
633         return ""; //$NON-NLS-1$
634 }
635
636 /**
637  * Returns the receiver's style information.
638  * <p>
639  * Note that the value which is returned by this method <em>may
640  * not match</em> the value which was provided to the constructor
641  * when the receiver was created. This can occur when the underlying
642  * operating system does not support a particular combination of
643  * requested styles. For example, if the platform widget used to
644  * implement a particular SWT widget always has scroll bars, the
645  * result of calling this method would always have the
646  * <code>SWT.H_SCROLL</code> and <code>SWT.V_SCROLL</code> bits set.
647  * </p>
648  *
649  * @return the style bits
650  *
651  * @exception SWTException <ul>
652  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
653  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
654  * </ul>
655  */
656 public int getStyle () {
657         checkWidget();
658         return style;
659 }
660
661 /*
662  * Returns <code>true</code> if the specified eventType is
663  * hooked, and <code>false</code> otherwise. Implementations
664  * of SWT can avoid creating objects and sending events
665  * when an event happens in the operating system but
666  * there are no listeners hooked for the event.
667  *
668  * @param eventType the event to be checked
669  *
670  * @return <code>true</code> when the eventType is hooked and <code>false</code> otherwise
671  *
672  * @see #isListening
673  */
674 boolean hooks (int eventType) {
675         if (eventTable == null) return false;
676         return eventTable.hooks (eventType);
677 }
678
679 /**
680  * Returns <code>true</code> if the widget has auto text direction,
681  * and <code>false</code> otherwise.
682  *
683  * @return <code>true</code> when the widget has auto direction and <code>false</code> otherwise
684  *
685  * @see SWT#AUTO_TEXT_DIRECTION
686  *
687  * @since 3.105
688  */
689 public boolean isAutoDirection () {
690         return (state & HAS_AUTO_DIRECTION) != 0;
691 }
692
693 /**
694  * Returns <code>true</code> if the widget has been disposed,
695  * and <code>false</code> otherwise.
696  * <p>
697  * This method gets the dispose state for the widget.
698  * When a widget has been disposed, it is an error to
699  * invoke any other method (except {@link #dispose()}) using the widget.
700  * </p>
701  *
702  * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
703  */
704 public boolean isDisposed () {
705         return (state & DISPOSED) != 0;
706 }
707
708 /**
709  * Returns <code>true</code> if there are any listeners
710  * for the specified event type associated with the receiver,
711  * and <code>false</code> otherwise. The event type is one of
712  * the event constants defined in class <code>SWT</code>.
713  *
714  * @param eventType the type of event
715  * @return true if the event is hooked
716  *
717  * @exception SWTException <ul>
718  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
719  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
720  * </ul>
721  *
722  * @see SWT
723  */
724 public boolean isListening (int eventType) {
725         checkWidget();
726         return hooks (eventType);
727 }
728
729 /*
730  * Returns <code>true</code> when subclassing is
731  * allowed and <code>false</code> otherwise
732  *
733  * @return <code>true</code> when subclassing is allowed and <code>false</code> otherwise
734  */
735 boolean isValidSubclass () {
736         return Display.isValidClass (getClass ());
737 }
738
739 /*
740  * Returns <code>true</code> when the current thread is
741  * the thread that created the widget and <code>false</code>
742  * otherwise.
743  *
744  * @return <code>true</code> when the current thread is the thread that created the widget and <code>false</code> otherwise
745  */
746 boolean isValidThread () {
747         return getDisplay ().isValidThread ();
748 }
749
750 void mapEvent (long hwnd, Event event) {
751 }
752
753 GC new_GC (GCData data) {
754         return null;
755 }
756
757 /**
758  * Notifies all of the receiver's listeners for events
759  * of the given type that one such event has occurred by
760  * invoking their <code>handleEvent()</code> method.  The
761  * event type is one of the event constants defined in class
762  * <code>SWT</code>.
763  *
764  * @param eventType the type of event which has occurred
765  * @param event the event data
766  *
767  * @exception SWTException <ul>
768  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
769  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
770  * </ul>
771  *
772  * @see SWT
773  * @see #addListener
774  * @see #getListeners(int)
775  * @see #removeListener(int, Listener)
776  */
777 public void notifyListeners (int eventType, Event event) {
778         checkWidget();
779         if (event == null) event = new Event ();
780         sendEvent (eventType, event);
781 }
782
783 void postEvent (int eventType) {
784         sendEvent (eventType, null, false);
785 }
786
787 void postEvent (int eventType, Event event) {
788         sendEvent (eventType, event, false);
789 }
790
791 /*
792  * Releases the widget hierarchy and optionally destroys
793  * the receiver.
794  * <p>
795  * Typically, a widget with children will broadcast this
796  * message to all children so that they too can release their
797  * resources.  The <code>releaseHandle</code> method is used
798  * as part of this broadcast to zero the handle fields of the
799  * children without calling <code>destroyWidget</code>.  In
800  * this scenario, the children are actually destroyed later,
801  * when the operating system destroys the widget tree.
802  * </p>
803  *
804  * @param destroy indicates that the receiver should be destroyed
805  *
806  * @see #dispose
807  * @see #releaseHandle
808  * @see #releaseParent
809  * @see #releaseWidget
810 */
811 void release (boolean destroy) {
812         if ((state & DISPOSE_SENT) == 0) {
813                 state |= DISPOSE_SENT;
814                 sendEvent (SWT.Dispose);
815         }
816         if ((state & DISPOSED) == 0) {
817                 releaseChildren (destroy);
818         }
819         if ((state & RELEASED) == 0) {
820                 state |= RELEASED;
821                 if (destroy) {
822                         releaseParent ();
823                         releaseWidget ();
824                         destroyWidget ();
825                 } else {
826                         releaseWidget ();
827                         releaseHandle ();
828                 }
829         }
830 }
831
832 void releaseChildren (boolean destroy) {
833 }
834
835 /*
836  * Releases the widget's handle by zero'ing it out.
837  * Does not destroy or release any operating system
838  * resources.
839  * <p>
840  * This method is called after <code>releaseWidget</code>
841  * or from <code>destroyWidget</code> when a widget is being
842  * destroyed to ensure that the widget is marked as destroyed
843  * in case the act of destroying the widget in the operating
844  * system causes application code to run in callback that
845  * could access the widget.
846  * </p>
847  *
848  * @see #dispose
849  * @see #releaseChildren
850  * @see #releaseParent
851  * @see #releaseWidget
852  */
853 void releaseHandle () {
854         state |= DISPOSED;
855         display = null;
856 }
857
858 /*
859  * Releases the receiver, a child in a widget hierarchy,
860  * from its parent.
861  * <p>
862  * When a widget is destroyed, it may be necessary to remove
863  * it from an internal data structure of the parent. When
864  * a widget has no handle, it may also be necessary for the
865  * parent to hide the widget or otherwise indicate that the
866  * widget has been disposed. For example, disposing a menu
867  * bar requires that the menu bar first be released from the
868  * shell when the menu bar is active.
869  * </p>
870  *
871  * @see #dispose
872  * @see #releaseChildren
873  * @see #releaseWidget
874  * @see #releaseHandle
875  */
876 void releaseParent () {
877 }
878
879 /*
880  * Releases any internal resources back to the operating
881  * system and clears all fields except the widget handle.
882  * <p>
883  * When a widget is destroyed, resources that were acquired
884  * on behalf of the programmer need to be returned to the
885  * operating system.  For example, if the widget made a
886  * copy of an icon, supplied by the programmer, this copy
887  * would be freed in <code>releaseWidget</code>.  Also,
888  * to assist the garbage collector and minimize the amount
889  * of memory that is not reclaimed when the programmer keeps
890  * a reference to a disposed widget, all fields except the
891  * handle are zero'd.  The handle is needed by <code>destroyWidget</code>.
892  * </p>
893  *
894  * @see #dispose
895  * @see #releaseChildren
896  * @see #releaseHandle
897  * @see #releaseParent
898  */
899 void releaseWidget () {
900         eventTable = null;
901         data = null;
902 }
903
904 /**
905  * Removes the listener from the collection of listeners who will
906  * be notified when an event of the given type occurs. The event
907  * type is one of the event constants defined in class <code>SWT</code>.
908  *
909  * @param eventType the type of event to listen for
910  * @param listener the listener which should no longer be notified
911  *
912  * @exception IllegalArgumentException <ul>
913  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
914  * </ul>
915  * @exception SWTException <ul>
916  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
917  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
918  * </ul>
919  *
920  * @see Listener
921  * @see SWT
922  * @see #addListener
923  * @see #getListeners(int)
924  * @see #notifyListeners
925  */
926 public void removeListener (int eventType, Listener listener) {
927         checkWidget();
928         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
929         _removeListener (eventType, listener);
930 }
931
932 /**
933  * Removes the listener from the collection of listeners who will
934  * be notified when an event of the given type occurs.
935  * <p>
936  * <b>IMPORTANT:</b> This method is <em>not</em> part of the SWT
937  * public API. It is marked public only so that it can be shared
938  * within the packages provided by SWT. It should never be
939  * referenced from application code.
940  * </p>
941  *
942  * @param eventType the type of event to listen for
943  * @param listener the listener which should no longer be notified
944  *
945  * @exception IllegalArgumentException <ul>
946  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
947  * </ul>
948  * @exception SWTException <ul>
949  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
950  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
951  * </ul>
952  *
953  * @see Listener
954  * @see #addListener
955  *
956  * @noreference This method is not intended to be referenced by clients.
957  * @nooverride This method is not intended to be re-implemented or extended by clients.
958  */
959 protected void removeListener (int eventType, SWTEventListener listener) {
960         checkWidget();
961         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
962         if (eventTable == null) return;
963         eventTable.unhook (eventType, listener);
964 }
965
966 /**
967  * Removes the listener from the collection of listeners who will
968  * be notified when the widget is disposed.
969  *
970  * @param listener the listener which should no longer be notified
971  *
972  * @exception IllegalArgumentException <ul>
973  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
974  * </ul>
975  * @exception SWTException <ul>
976  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
977  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
978  * </ul>
979  *
980  * @see DisposeListener
981  * @see #addDisposeListener
982  */
983 public void removeDisposeListener (DisposeListener listener) {
984         checkWidget();
985         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
986         if (eventTable == null) return;
987         eventTable.unhook (SWT.Dispose, listener);
988 }
989
990 /**
991  * Marks the widget to be skinned.
992  * <p>
993  * The skin event is sent to the receiver's display when appropriate (usually before the next event
994  * is handled). Widgets are automatically marked for skinning upon creation as well as when its skin
995  * id or class changes. The skin id and/or class can be changed by calling {@link Display#setData(String, Object)}
996  * with the keys {@link SWT#SKIN_ID} and/or {@link SWT#SKIN_CLASS}. Once the skin event is sent to a widget, it
997  * will not be sent again unless <code>reskin(int)</code> is called on the widget or on an ancestor
998  * while specifying the <code>SWT.ALL</code> flag.
999  * </p>
1000  * <p>
1001  * The parameter <code>flags</code> may be either:
1002  * </p>
1003  * <dl>
1004  * <dt><b>{@link SWT#ALL}</b></dt>
1005  * <dd>all children in the receiver's widget tree should be skinned</dd>
1006  * <dt><b>{@link SWT#NONE}</b></dt>
1007  * <dd>only the receiver should be skinned</dd>
1008  * </dl>
1009  * @param flags the flags specifying how to reskin
1010  *
1011  * @exception SWTException
1012  * <ul>
1013  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1014  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1015  * </ul>
1016  * @since 3.6
1017  */
1018 public void reskin (int flags) {
1019         checkWidget ();
1020         reskinWidget ();
1021         if ((flags & SWT.ALL) != 0) reskinChildren (flags);
1022 }
1023
1024 void reskinChildren (int flags) {
1025 }
1026
1027 void reskinWidget() {
1028         if ((state & SKIN_NEEDED) != SKIN_NEEDED) {
1029                 this.state |= SKIN_NEEDED;
1030                 display.addSkinnableWidget(this);
1031         }
1032 }
1033
1034 boolean sendDragEvent (int button, int x, int y) {
1035         Event event = new Event ();
1036         event.button = button;
1037         event.setLocationInPixels(x, y); // In Pixels
1038         setInputState (event, SWT.DragDetect);
1039         postEvent (SWT.DragDetect, event);
1040         if (isDisposed ()) return false;
1041         return event.doit;
1042 }
1043
1044 boolean sendDragEvent (int button, int stateMask, int x, int y) {
1045         Event event = new Event ();
1046         event.button = button;
1047         event.setLocationInPixels(x, y);
1048         event.stateMask = stateMask;
1049         postEvent (SWT.DragDetect, event);
1050         if (isDisposed ()) return false;
1051         return event.doit;
1052 }
1053
1054 void sendEvent (Event event) {
1055         Display display = event.display;
1056         if (!display.filterEvent (event)) {
1057                 if (eventTable != null) display.sendEvent(eventTable, event);
1058         }
1059 }
1060
1061 void sendEvent (int eventType) {
1062         sendEvent (eventType, null, true);
1063 }
1064
1065 void sendEvent (int eventType, Event event) {
1066         sendEvent (eventType, event, true);
1067 }
1068
1069 void sendEvent (int eventType, Event event, boolean send) {
1070         if (eventTable == null && !display.filters (eventType)) {
1071                 return;
1072         }
1073         if (event == null) event = new Event ();
1074         event.type = eventType;
1075         event.display = display;
1076         event.widget = this;
1077         if (event.time == 0) {
1078                 event.time = display.getLastEventTime ();
1079         }
1080         if (send) {
1081                 sendEvent (event);
1082         } else {
1083                 display.postEvent (event);
1084         }
1085 }
1086
1087
1088 void sendSelectionEvent (int type) {
1089         sendSelectionEvent (type, null, false);
1090 }
1091
1092 void sendSelectionEvent (int type, Event event, boolean send) {
1093         if (eventTable == null && !display.filters (type)) {
1094                 return;
1095         }
1096         if (event == null) event = new Event ();
1097         setInputState (event, type);
1098         sendEvent (type, event, send);
1099 }
1100
1101 boolean sendKeyEvent (int type, int msg, long wParam, long lParam) {
1102         Event event = new Event ();
1103         if (!setKeyState (event, type, wParam, lParam)) return true;
1104         return sendKeyEvent (type, msg, wParam, lParam, event);
1105 }
1106
1107 boolean sendKeyEvent (int type, int msg, long wParam, long lParam, Event event) {
1108         sendEvent (type, event);
1109         if (isDisposed ()) return false;
1110         return event.doit;
1111 }
1112
1113 boolean sendMouseEvent (int type, int button, long hwnd, int msg, long wParam, long lParam) {
1114         return sendMouseEvent (type, button, display.getClickCount (type, button, hwnd, lParam), 0, false, hwnd, msg, wParam, lParam);
1115 }
1116
1117 boolean sendMouseEvent (int type, int button, int count, int detail, boolean send, long hwnd, int msg, long wParam, long lParam) {
1118         if (!hooks (type) && !filters (type)) return true;
1119         Event event = new Event ();
1120         event.button = button;
1121         event.detail = detail;
1122         event.count = count;
1123         event.setLocationInPixels(OS.GET_X_LPARAM (lParam), OS.GET_Y_LPARAM (lParam));
1124         setInputState (event, type);
1125         mapEvent (hwnd, event);
1126         if (send) {
1127                 sendEvent (type, event);
1128                 if (isDisposed ()) return false;
1129         } else {
1130                 postEvent (type, event);
1131         }
1132         return event.doit;
1133 }
1134
1135 boolean sendMouseWheelEvent (int type, long hwnd, long wParam, long lParam) {
1136         int delta = OS.GET_WHEEL_DELTA_WPARAM (wParam);
1137         int detail = 0;
1138         if (type == SWT.MouseWheel) {
1139                 int [] linesToScroll = new int [1];
1140                 OS.SystemParametersInfo (OS.SPI_GETWHEELSCROLLLINES, 0, linesToScroll, 0);
1141                 if (linesToScroll [0] == OS.WHEEL_PAGESCROLL) {
1142                         detail = SWT.SCROLL_PAGE;
1143                 } else {
1144                         detail = SWT.SCROLL_LINE;
1145                         delta *= linesToScroll [0];
1146                 }
1147                 /* Check if the delta and the remainder have the same direction (sign) */
1148                 if ((delta ^ display.scrollRemainder) >= 0) delta += display.scrollRemainder;
1149                 display.scrollRemainder = delta % OS.WHEEL_DELTA;
1150         } else {
1151                 /* Check if the delta and the remainder have the same direction (sign) */
1152                 if ((delta ^ display.scrollHRemainder) >= 0) delta += display.scrollHRemainder;
1153                 display.scrollHRemainder = delta % OS.WHEEL_DELTA;
1154
1155                 delta = -delta;
1156         }
1157
1158         if (!hooks (type) && !filters (type)) return true;
1159         int count = delta / OS.WHEEL_DELTA;
1160         POINT pt = new POINT ();
1161         OS.POINTSTOPOINT (pt, lParam);
1162         OS.ScreenToClient (hwnd, pt);
1163         lParam = OS.MAKELPARAM (pt.x, pt.y);
1164         return sendMouseEvent (type, 0, count, detail, true, hwnd, OS.WM_MOUSEWHEEL, wParam, lParam);
1165 }
1166
1167 /**
1168  * Sets the application defined widget data associated
1169  * with the receiver to be the argument. The <em>widget
1170  * data</em> is a single, unnamed field that is stored
1171  * with every widget.
1172  * <p>
1173  * Applications may put arbitrary objects in this field. If
1174  * the object stored in the widget data needs to be notified
1175  * when the widget is disposed of, it is the application's
1176  * responsibility to hook the Dispose event on the widget and
1177  * do so.
1178  * </p>
1179  *
1180  * @param data the widget data
1181  *
1182  * @exception SWTException <ul>
1183  *    <li>ERROR_WIDGET_DISPOSED - when the receiver has been disposed</li>
1184  *    <li>ERROR_THREAD_INVALID_ACCESS - when called from the wrong thread</li>
1185  * </ul>
1186  *
1187  * @see #getData()
1188  */
1189 public void setData (Object data) {
1190         checkWidget();
1191         if ((state & KEYED_DATA) != 0) {
1192                 ((Object []) this.data) [0] = data;
1193         } else {
1194                 this.data = data;
1195         }
1196 }
1197
1198 /**
1199  * Sets the application defined property of the receiver
1200  * with the specified name to the given value.
1201  * <p>
1202  * Applications may associate arbitrary objects with the
1203  * receiver in this fashion. If the objects stored in the
1204  * properties need to be notified when the widget is disposed
1205  * of, it is the application's responsibility to hook the
1206  * Dispose event on the widget and do so.
1207  * </p>
1208  *
1209  * @param key the name of the property
1210  * @param value the new value for the property
1211  *
1212  * @exception IllegalArgumentException <ul>
1213  *    <li>ERROR_NULL_ARGUMENT - if the key is null</li>
1214  * </ul>
1215  * @exception SWTException <ul>
1216  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1217  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1218  * </ul>
1219  *
1220  * @see #getData(String)
1221  */
1222 public void setData (String key, Object value) {
1223         checkWidget();
1224         if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
1225         int index = 1;
1226         Object [] table = null;
1227         if ((state & KEYED_DATA) != 0) {
1228                 table = (Object []) data;
1229                 while (index < table.length) {
1230                         if (key.equals (table [index])) break;
1231                         index += 2;
1232                 }
1233         }
1234         if (value != null) {
1235                 if ((state & KEYED_DATA) != 0) {
1236                         if (index == table.length) {
1237                                 Object [] newTable = new Object [table.length + 2];
1238                                 System.arraycopy (table, 0, newTable, 0, table.length);
1239                                 data = table = newTable;
1240                         }
1241                 } else {
1242                         table = new Object [3];
1243                         table [0] = data;
1244                         data = table;
1245                         state |= KEYED_DATA;
1246                 }
1247                 table [index] = key;
1248                 table [index + 1] = value;
1249         } else {
1250                 if ((state & KEYED_DATA) != 0) {
1251                         if (index != table.length) {
1252                                 int length = table.length - 2;
1253                                 if (length == 1) {
1254                                         data = table [0];
1255                                         state &= ~KEYED_DATA;
1256                                 } else {
1257                                         Object [] newTable = new Object [length];
1258                                         System.arraycopy (table, 0, newTable, 0, index);
1259                                         System.arraycopy (table, index + 2, newTable, index, length - index);
1260                                         data = newTable;
1261                                 }
1262                         }
1263                 }
1264         }
1265         if (key.equals(SWT.SKIN_CLASS) || key.equals(SWT.SKIN_ID)) this.reskin(SWT.ALL);
1266 }
1267
1268 boolean sendFocusEvent (int type) {
1269         sendEvent (type);
1270         // widget could be disposed at this point
1271         return true;
1272 }
1273
1274 boolean setInputState (Event event, int type) {
1275         if (OS.GetKeyState (OS.VK_MENU) < 0) event.stateMask |= SWT.ALT;
1276         if (OS.GetKeyState (OS.VK_SHIFT) < 0) event.stateMask |= SWT.SHIFT;
1277         if (OS.GetKeyState (OS.VK_CONTROL) < 0) event.stateMask |= SWT.CONTROL;
1278         if (OS.GetKeyState (OS.VK_LBUTTON) < 0) event.stateMask |= SWT.BUTTON1;
1279         if (OS.GetKeyState (OS.VK_MBUTTON) < 0) event.stateMask |= SWT.BUTTON2;
1280         if (OS.GetKeyState (OS.VK_RBUTTON) < 0) event.stateMask |= SWT.BUTTON3;
1281         /*
1282         * Bug in Windows.  On some machines that do not have XBUTTONs,
1283         * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
1284         * causing mouse capture to become stuck.  The fix is to test
1285         * for the extra buttons only when they exist.
1286         */
1287         if (display.xMouse) {
1288                 if (OS.GetKeyState (OS.VK_XBUTTON1) < 0) event.stateMask |= SWT.BUTTON4;
1289                 if (OS.GetKeyState (OS.VK_XBUTTON2) < 0) event.stateMask |= SWT.BUTTON5;
1290         }
1291         switch (type) {
1292                 case SWT.MouseDown:
1293                 case SWT.MouseDoubleClick:
1294                         if (event.button == 1) event.stateMask &= ~SWT.BUTTON1;
1295                         if (event.button == 2) event.stateMask &= ~SWT.BUTTON2;
1296                         if (event.button == 3) event.stateMask &= ~SWT.BUTTON3;
1297                         if (event.button == 4) event.stateMask &= ~SWT.BUTTON4;
1298                         if (event.button == 5) event.stateMask &= ~SWT.BUTTON5;
1299                         break;
1300                 case SWT.MouseUp:
1301                         if (event.button == 1) event.stateMask |= SWT.BUTTON1;
1302                         if (event.button == 2) event.stateMask |= SWT.BUTTON2;
1303                         if (event.button == 3) event.stateMask |= SWT.BUTTON3;
1304                         if (event.button == 4) event.stateMask |= SWT.BUTTON4;
1305                         if (event.button == 5) event.stateMask |= SWT.BUTTON5;
1306                         break;
1307                 case SWT.KeyDown:
1308                 case SWT.Traverse:
1309                         if (event.keyCode == SWT.ALT) event.stateMask &= ~SWT.ALT;
1310                         if (event.keyCode == SWT.SHIFT) event.stateMask &= ~SWT.SHIFT;
1311                         if (event.keyCode == SWT.CONTROL) event.stateMask &= ~SWT.CONTROL;
1312                         break;
1313                 case SWT.KeyUp:
1314                         if (event.keyCode == SWT.ALT) event.stateMask |= SWT.ALT;
1315                         if (event.keyCode == SWT.SHIFT) event.stateMask |= SWT.SHIFT;
1316                         if (event.keyCode == SWT.CONTROL) event.stateMask |= SWT.CONTROL;
1317                         break;
1318         }
1319         return true;
1320 }
1321
1322 boolean setKeyState (Event event, int type, long wParam, long lParam) {
1323
1324         /*
1325         * Feature in Windows.  When the user presses Ctrl+Backspace
1326         * or Ctrl+Enter, Windows sends a WM_CHAR with Delete (0x7F)
1327         * and '\n' instead of '\b' and '\r'.  This is the correct
1328         * platform behavior but is not portable.  The fix is to detect
1329         * these cases and convert the character.
1330         */
1331         switch (display.lastAscii) {
1332                 case SWT.DEL:
1333                         if (display.lastKey == SWT.BS) display.lastAscii = SWT.BS;
1334                         break;
1335                 case SWT.LF:
1336                         if (display.lastKey == SWT.CR) display.lastAscii = SWT.CR;
1337                         break;
1338         }
1339
1340         /*
1341         * Feature in Windows.  When the user presses either the Enter
1342         * key or the numeric keypad Enter key, Windows sends a WM_KEYDOWN
1343         * with wParam=VK_RETURN in both cases.  In order to distinguish
1344         * between the keys, the extended key bit is tested. If the bit
1345         * is set, assume that the numeric keypad Enter was pressed.
1346         */
1347         if (display.lastKey == SWT.CR && display.lastAscii == SWT.CR) {
1348                 if ((lParam & 0x1000000) != 0) display.lastKey = SWT.KEYPAD_CR;
1349         }
1350
1351         setLocationMask(event, type, wParam, lParam);
1352
1353         if (display.lastVirtual) {
1354                 /*
1355                 * Feature in Windows.  The virtual key VK_DELETE is not
1356                 * treated as both a virtual key and an ASCII key by Windows.
1357                 * Therefore, we will not receive a WM_CHAR for this key.
1358                 * The fix is to treat VK_DELETE as a special case and map
1359                 * the ASCII value explicitly (Delete is 0x7F).
1360                 */
1361                 if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
1362
1363                 /*
1364                 * Feature in Windows.  When the user presses Ctrl+Pause, the
1365                 * VK_CANCEL key is generated and a WM_CHAR is sent with 0x03,
1366                 * possibly to allow an application to look for Ctrl+C and the
1367                 * the Break key at the same time.  This is unexpected and
1368                 * unwanted.  The fix is to detect the case and set the character
1369                 * to zero.
1370                 */
1371                 if (display.lastKey == OS.VK_CANCEL) display.lastAscii = 0x0;
1372
1373                 event.keyCode = Display.translateKey (display.lastKey);
1374         } else {
1375                 event.keyCode = display.lastKey;
1376         }
1377         if (display.lastAscii != 0 || display.lastNull) {
1378                 event.character = (char) display.lastAscii;
1379         }
1380         if (event.keyCode == 0 && event.character == 0) {
1381                 if (!display.lastNull) return false;
1382         }
1383         return setInputState (event, type);
1384 }
1385
1386 int setLocationMask (Event event, int type, long wParam, long lParam) {
1387         int location = SWT.NONE;
1388         if (display.lastVirtual) {
1389                 switch (display.lastKey) {
1390                         case OS.VK_SHIFT:
1391                                 if (OS.GetKeyState(OS.VK_LSHIFT) < 0) location = SWT.LEFT;
1392                                 if (OS.GetKeyState(OS.VK_RSHIFT) < 0) location = SWT.RIGHT;
1393                                 break;
1394                         case OS.VK_NUMLOCK:
1395                                 location = SWT.KEYPAD;
1396                                 break;
1397                         case OS.VK_CONTROL:
1398                         case OS.VK_MENU:
1399                                 location = (lParam & 0x1000000) == 0 ? SWT.LEFT : SWT.RIGHT;
1400                                 break;
1401                         case OS.VK_INSERT:
1402                         case OS.VK_DELETE:
1403                         case OS.VK_HOME:
1404                         case OS.VK_END:
1405                         case OS.VK_PRIOR:
1406                         case OS.VK_NEXT:
1407                         case OS.VK_UP:
1408                         case OS.VK_DOWN:
1409                         case OS.VK_LEFT:
1410                         case OS.VK_RIGHT:
1411                                 if ((lParam & 0x1000000) == 0) {
1412                                         location = SWT.KEYPAD;
1413                                 }
1414                                 break;
1415                 }
1416                 if (display.numpadKey(display.lastKey) != 0) {
1417                         location = SWT.KEYPAD;
1418                 }
1419         } else {
1420                 if (display.lastKey == SWT.KEYPAD_CR) {
1421                         location = SWT.KEYPAD;
1422                 }
1423         }
1424         event.keyLocation = location;
1425         return location;
1426 }
1427
1428 boolean setTabGroupFocus () {
1429         return setTabItemFocus ();
1430 }
1431
1432 boolean setTabItemFocus () {
1433         return false;
1434 }
1435
1436 boolean showMenu (int x, int y) {
1437         return showMenu (x, y, SWT.MENU_MOUSE);
1438 }
1439
1440 boolean showMenu (int x, int y, int detail) {
1441         Event event = new Event ();
1442         event.setLocationInPixels(x, y);
1443         event.detail = detail;
1444         if (event.detail == SWT.MENU_KEYBOARD) {
1445                 updateMenuLocation (event);
1446         }
1447         sendEvent (SWT.MenuDetect, event);
1448         // widget could be disposed at this point
1449         if (isDisposed ()) return false;
1450         if (!event.doit) return true;
1451         Menu menu = getMenu ();
1452         if (menu != null && !menu.isDisposed ()) {
1453                 Point loc = event.getLocationInPixels(); // In Pixels
1454                 if (x != loc.x || y != loc.y) {
1455                         menu.setLocation (event.getLocation());
1456                 }
1457                 menu.setVisible (true);
1458                 return true;
1459         }
1460         return false;
1461 }
1462
1463 /**
1464  * Returns a string containing a concise, human-readable
1465  * description of the receiver.
1466  *
1467  * @return a string representation of the receiver
1468  */
1469 @Override
1470 public String toString () {
1471         String string = "*Disposed*"; //$NON-NLS-1$
1472         if (!isDisposed ()) {
1473                 string = "*Wrong Thread*"; //$NON-NLS-1$
1474                 if (isValidThread ()) string = getNameText ();
1475         }
1476         return getName () + " {" + string + "}"; //$NON-NLS-1$ //$NON-NLS-2$
1477 }
1478
1479 void updateMenuLocation (Event event) {
1480         /* Do nothing */
1481 }
1482
1483 LRESULT wmCaptureChanged (long hwnd, long wParam, long lParam) {
1484         display.captureChanged = true;
1485         return null;
1486 }
1487
1488 LRESULT wmChar (long hwnd, long wParam, long lParam) {
1489         display.lastAscii = (int)wParam;
1490         display.lastNull = wParam == 0;
1491         if (!sendKeyEvent (SWT.KeyDown, OS.WM_CHAR, wParam, lParam)) {
1492                 return LRESULT.ONE;
1493         }
1494         // widget could be disposed at this point
1495         return null;
1496 }
1497
1498 LRESULT wmContextMenu (long hwnd, long wParam, long lParam) {
1499         if (wParam != hwnd) return null;
1500
1501         /*
1502         * Feature in Windows.  When the user presses  WM_NCRBUTTONUP,
1503         * a WM_CONTEXTMENU message is generated.  This happens when
1504         * the user releases the mouse over a scroll bar.  Normally,
1505         * window displays the default scrolling menu but applications
1506         * can process WM_CONTEXTMENU to display a different menu.
1507         * Typically, an application does not want to supply a special
1508         * scroll menu.  The fix is to look for a WM_CONTEXTMENU that
1509         * originated from a mouse event and display the menu when the
1510         * mouse was released in the client area.
1511         */
1512         int x = 0, y = 0, detail = 0;
1513         if (lParam != -1) {
1514                 POINT pt = new POINT ();
1515                 OS.POINTSTOPOINT (pt, lParam);
1516                 x = pt.x;
1517                 y = pt.y;
1518                 detail = SWT.MENU_MOUSE;
1519                 OS.ScreenToClient (hwnd, pt);
1520                 RECT rect = new RECT ();
1521                 OS.GetClientRect (hwnd, rect);
1522                 if (!OS.PtInRect (rect, pt)) return null;
1523         } else {
1524                 int pos = OS.GetMessagePos ();
1525                 x = OS.GET_X_LPARAM (pos);
1526                 y = OS.GET_Y_LPARAM (pos);
1527                 detail = SWT.MENU_KEYBOARD;
1528         }
1529
1530         /* Show the menu */
1531         return showMenu (x, y, detail) ? LRESULT.ZERO : null;
1532 }
1533
1534 LRESULT wmIMEChar (long hwnd, long wParam, long lParam) {
1535         Display display = this.display;
1536         display.lastKey = 0;
1537         display.lastAscii = (int)wParam;
1538         display.lastVirtual = display.lastNull = display.lastDead = false;
1539         if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
1540                 return LRESULT.ONE;
1541         }
1542         sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
1543         // widget could be disposed at this point
1544         display.lastKey = display.lastAscii = 0;
1545         return LRESULT.ONE;
1546 }
1547
1548 LRESULT wmKeyDown (long hwnd, long wParam, long lParam) {
1549
1550         /* Ignore repeating modifier keys by testing key down state */
1551         switch ((int)wParam) {
1552                 case OS.VK_SHIFT:
1553                 case OS.VK_MENU:
1554                 case OS.VK_CONTROL:
1555                 case OS.VK_CAPITAL:
1556                 case OS.VK_NUMLOCK:
1557                 case OS.VK_SCROLL:
1558                         if ((lParam & 0x40000000) != 0) return null;
1559         }
1560
1561         boolean lastDead = display.lastDead;
1562         /* Clear last key and last ascii because a new key has been typed */
1563         display.lastAscii = display.lastKey = 0;
1564         display.lastVirtual = display.lastNull = display.lastDead = false;
1565
1566         /* Map the virtual key */
1567         int mapKey = OS.MapVirtualKey ((int)wParam, 2);
1568         /*
1569         * Feature in Windows.  For Devanagari and Bengali numbers,
1570         * MapVirtualKey() returns the localized number instead of
1571         * the ASCII equivalent.  For example, MapVirtualKey()
1572         * maps VK_1 on the numbers keyboard to \u0967, which is
1573         * the Devanagari digit '1', but not ASCII.
1574         * The fix is to test for Devanagari and Bengali digits and
1575         * map these explicitly.
1576         *
1577         * NOTE: VK_0 to VK_9 are the same as ASCII.
1578         */
1579         if (('\u09e6' <= mapKey && mapKey <= '\u09ef') || ('\u0966' <= mapKey && mapKey <= '\u096f')) {
1580                 mapKey = (int)wParam;
1581         }
1582
1583         /*
1584         * Bug in Windows 95 and NT.  When the user types an accent key such
1585         * as ^ to get an accented character on a German keyboard, the accent
1586         * key should be ignored and the next key that the user types is the
1587         * accented key.  The fix is to detect the accent key stroke (called
1588         * a dead key) by testing the high bit of the value returned by
1589         * MapVirtualKey().
1590         *
1591         * When the user types an accent key that does not correspond to a
1592         * virtual key, MapVirtualKey() won't set the high bit to indicate
1593         * a dead key.  This happens when an accent key, such as '^' is the
1594         * result of a modifier such as Shift key and MapVirtualKey() always
1595         * returns the unshifted key.  The fix is to peek for a WM_DEADCHAR
1596         * and avoid issuing the event.
1597         */
1598         if ((mapKey & 0x80000000) != 0) return null;
1599
1600         MSG msg = new MSG ();
1601         int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
1602         if (OS.PeekMessage (msg, hwnd, OS.WM_DEADCHAR, OS.WM_DEADCHAR, flags)) {
1603                 display.lastDead = true;
1604                 display.lastVirtual = mapKey == 0;
1605                 display.lastKey = display.lastVirtual ? (int)wParam : mapKey;
1606                 return null;
1607         }
1608
1609         /*
1610          * When hitting accent keys twice in a row, PeekMessage only returns
1611          * a WM_DEADCHAR for the first WM_KEYDOWN. Ignore the second
1612          * WM_KEYDOWN and issue the key down event from inside WM_CHAR.
1613          */
1614         if (lastDead) {
1615                 display.lastVirtual = mapKey == 0;
1616                 display.lastKey = display.lastVirtual ? (int)wParam : mapKey;
1617                 return null;
1618         }
1619
1620         /*
1621         *  Bug in Windows.  Somehow, the widget is becoming disposed after
1622         *  calling PeekMessage().  In rare circumstances, it seems that
1623         *  PeekMessage() can allow SWT listeners to run that might contain
1624         *  application code that disposes the widget.  It is not exactly
1625         *  clear how this can happen.  PeekMessage() is only looking for
1626         *  WM_DEADCHAR.  It is not dispatching any message that it finds
1627         *  or removing any message from the queue.  Cross-thread messages
1628         *  are disabled.  The fix is to check for a disposed widget and
1629         *  return without calling the window proc.
1630         */
1631         if (isDisposed ()) return LRESULT.ONE;
1632
1633         /*
1634         * If we are going to get a WM_CHAR, ensure that last key has
1635         * the correct character value for the key down and key up
1636         * events.  It is not sufficient to ignore the WM_KEYDOWN
1637         * (when we know we are going to get a WM_CHAR) and compute
1638         * the key in WM_CHAR because there is not enough information
1639         * by the time we get the WM_CHAR.  For example, when the user
1640         * types Ctrl+Shift+6 on a US keyboard, we get a WM_CHAR with
1641         * wParam=30.  When the user types Ctrl+Shift+6 on a German
1642         * keyboard, we also get a WM_CHAR with wParam=30.  On the US
1643         * keyboard Shift+6 is ^, on the German keyboard Shift+6 is &.
1644         * There is no way to map wParam=30 in WM_CHAR to the correct
1645         * value.  Also, on international keyboards, the control key
1646         * may be down when the user has not entered a control character.
1647         *
1648         * NOTE: On Windows 98, keypad keys are virtual despite the
1649         * fact that a WM_CHAR is issued.  On Windows 2000 and XP,
1650         * they are not virtual.  Therefore it is necessary to force
1651         * numeric keypad keys to be virtual.
1652         */
1653         display.lastVirtual = mapKey == 0 || display.numpadKey ((int)wParam) != 0;
1654         if (display.lastVirtual) {
1655                 display.lastKey = (int)wParam;
1656                 /*
1657                 * Feature in Windows.  The virtual key VK_DELETE is not
1658                 * treated as both a virtual key and an ASCII key by Windows.
1659                 * Therefore, we will not receive a WM_CHAR for this key.
1660                 * The fix is to treat VK_DELETE as a special case and map
1661                 * the ASCII value explicitly (Delete is 0x7F).
1662                 */
1663                 if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
1664
1665                 /*
1666                 * It is possible to get a WM_CHAR for a virtual key when
1667                 * Num Lock is on.  If the user types Home while Num Lock
1668                 * is down, a WM_CHAR is issued with WPARM=55 (for the
1669                 * character 7).  If we are going to get a WM_CHAR we need
1670                 * to ensure that the last key has the correct value.  Note
1671                 * that Ctrl+Home does not issue a WM_CHAR when Num Lock is
1672                 * down.
1673                 */
1674                 if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
1675                         /*
1676                         * Feature in Windows.  Calling to ToAscii() or ToUnicode(), clears
1677                         * the accented state such that the next WM_CHAR loses the accent.
1678                         * This makes is critical that the accent key is detected.  Also,
1679                         * these functions clear the character that is entered using the
1680                         * special Windows keypad sequence when NumLock is down (ie. typing
1681                         * ALT+0231 should gives 'c' with a cedilla when NumLock is down).
1682                         */
1683                         if (display.asciiKey (display.lastKey) != 0) return null;
1684                         display.lastAscii = display.numpadKey (display.lastKey);
1685                 }
1686         } else {
1687                 /*
1688                 * Convert LastKey to lower case because Windows non-virtual
1689                 * keys that are also ASCII keys, such as like VK_A, are have
1690                 * upper case values in WM_KEYDOWN despite the fact that the
1691                 * Shift was not pressed.
1692                 */
1693                 display.lastKey = (int)OS.CharLower ((short) mapKey);
1694
1695                 /*
1696                 * Feature in Windows. The virtual key VK_CANCEL is treated
1697                 * as both a virtual key and ASCII key by Windows.  This
1698                 * means that a WM_CHAR with WPARAM=3 will be issued for
1699                 * this key.  In order to distinguish between this key and
1700                 * Ctrl+C, mark the key as virtual.
1701                 */
1702                 if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
1703
1704                 /*
1705                 * Some key combinations map to Windows ASCII keys depending
1706                 * on the keyboard.  For example, Ctrl+Alt+Q maps to @ on a
1707                 * German keyboard.  If the current key combination is special,
1708                 * the correct character is placed in wParam for processing in
1709                 * WM_CHAR.  If this is the case, issue the key down event from
1710                 * inside WM_CHAR.
1711                 */
1712                 int asciiKey = display.asciiKey ((int)wParam);
1713                 if (asciiKey != 0) {
1714                         /*
1715                         * When the user types Ctrl+Space, ToAscii () maps this to
1716                         * Space.  Normally, ToAscii () maps a key to a different
1717                         * key if both a WM_KEYDOWN and a WM_CHAR will be issued.
1718                         * To avoid the extra SWT.KeyDown, look for a space and
1719                         * issue the event from WM_CHAR.
1720                         */
1721                         if (asciiKey == ' ') return null;
1722                         if (asciiKey != (int)wParam) return null;
1723                         /*
1724                         * Feature in Windows. The virtual key VK_CANCEL is treated
1725                         * as both a virtual key and ASCII key by Windows.  This
1726                         * means that a WM_CHAR with WPARAM=3 will be issued for
1727                         * this key. To avoid the extra SWT.KeyDown, look for
1728                         * VK_CANCEL and issue the event from WM_CHAR.
1729                         */
1730                         if (wParam == OS.VK_CANCEL) return null;
1731                 }
1732
1733                 /*
1734                 * If the control key is not down at this point, then
1735                 * the key that was pressed was an accent key or a regular
1736                 * key such as 'A' or Shift+A.  In that case, issue the
1737                 * key event from WM_CHAR.
1738                 */
1739                 if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return null;
1740
1741                 /*
1742                 * Get the shifted state or convert to lower case if necessary.
1743                 * If the user types Ctrl+A, LastAscii should be 'a', not 'A'.
1744                 * If the user types Ctrl+Shift+A, LastAscii should be 'A'.
1745                 * If the user types Ctrl+Shift+6, the value of LastAscii will
1746                 * depend on the international keyboard.
1747                 */
1748                 if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
1749                         display.lastAscii = display.shiftedKey ((int)wParam);
1750                         if (display.lastAscii == 0) display.lastAscii = mapKey;
1751                 } else {
1752                         display.lastAscii = (int)OS.CharLower ((short) mapKey);
1753                 }
1754
1755                 /* Note that Ctrl+'@' is ASCII NUL and is delivered in WM_CHAR */
1756                 if (display.lastAscii == '@') return null;
1757                 display.lastAscii = display.controlKey (display.lastAscii);
1758         }
1759         if (!sendKeyEvent (SWT.KeyDown, OS.WM_KEYDOWN, wParam, lParam)) {
1760                 return LRESULT.ONE;
1761         }
1762         // widget could be disposed at this point
1763         return null;
1764 }
1765
1766 LRESULT wmKeyUp (long hwnd, long wParam, long lParam) {
1767         Display display = this.display;
1768
1769         /*
1770         * If the key up is not hooked, reset last key
1771         * and last ascii in case the key down is hooked.
1772         */
1773         if (!hooks (SWT.KeyUp) && !display.filters (SWT.KeyUp)) {
1774                 display.lastKey = display.lastAscii = 0;
1775                 display.lastVirtual = display.lastNull = display.lastDead = false;
1776                 return null;
1777         }
1778
1779         /* Map the virtual key. */
1780         int mapKey = OS.MapVirtualKey ((int)wParam, 2);
1781
1782         /*
1783         * Bug in Windows 95 and NT.  When the user types an accent key such
1784         * as ^ to get an accented character on a German keyboard, the accent
1785         * key should be ignored and the next key that the user types is the
1786         * accented key. The fix is to detect the accent key stroke (called
1787         * a dead key) by testing the high bit of the value returned by
1788         * MapVirtualKey ().
1789         */
1790         if ((mapKey & 0x80000000) != 0) return null;
1791
1792         if (display.lastDead) return null;
1793
1794         /*
1795         * NOTE: On Windows 98, keypad keys are virtual despite the
1796         * fact that a WM_CHAR is issued.  On Windows 2000 and XP,
1797         * they are not virtual.  Therefore it is necessary to force
1798         * numeric keypad keys to be virtual.
1799         */
1800         display.lastVirtual = mapKey == 0 || display.numpadKey ((int)wParam) != 0;
1801         if (display.lastVirtual) {
1802                 display.lastKey = (int)wParam;
1803         } else {
1804                 /*
1805                 * Feature in Windows. The virtual key VK_CANCEL is treated
1806                 * as both a virtual key and ASCII key by Windows.  This
1807                 * means that a WM_CHAR with WPARAM=3 will be issued for
1808                 * this key.  In order to distinguish between this key and
1809                 * Ctrl+C, mark the key as virtual.
1810                 */
1811                 if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
1812                 if (display.lastKey == 0) {
1813                         display.lastAscii = 0;
1814                         display.lastNull = display.lastDead = false;
1815                         return null;
1816                 }
1817         }
1818         LRESULT result = null;
1819         if (!sendKeyEvent (SWT.KeyUp, OS.WM_KEYUP, wParam, lParam)) {
1820                 result = LRESULT.ONE;
1821         }
1822         // widget could be disposed at this point
1823         display.lastKey = display.lastAscii = 0;
1824         display.lastVirtual = display.lastNull = display.lastDead = false;
1825         return result;
1826 }
1827
1828 LRESULT wmKillFocus (long hwnd, long wParam, long lParam) {
1829         display.scrollRemainder = display.scrollHRemainder = 0;
1830         long code = callWindowProc (hwnd, OS.WM_KILLFOCUS, wParam, lParam);
1831         sendFocusEvent (SWT.FocusOut);
1832         // widget could be disposed at this point
1833
1834         /*
1835         * It is possible (but unlikely), that application
1836         * code could have disposed the widget in the focus
1837         * or deactivate events.  If this happens, end the
1838         * processing of the Windows message by returning
1839         * zero as the result of the window proc.
1840         */
1841         if (isDisposed ()) return LRESULT.ZERO;
1842         if (code == 0) return LRESULT.ZERO;
1843         return new LRESULT (code);
1844 }
1845
1846 LRESULT wmLButtonDblClk (long hwnd, long wParam, long lParam) {
1847         /*
1848         * Feature in Windows. Windows sends the following
1849         * messages when the user double clicks the mouse:
1850         *
1851         *       WM_LBUTTONDOWN          - mouse down
1852         *       WM_LBUTTONUP            - mouse up
1853         *       WM_LBUTTONDBLCLK        - double click
1854         *       WM_LBUTTONUP            - mouse up
1855         *
1856         * Applications that expect matching mouse down/up
1857         * pairs will not see the second mouse down.  The
1858         * fix is to send a mouse down event.
1859         */
1860         LRESULT result = null;
1861         Display display = this.display;
1862         display.captureChanged = false;
1863         sendMouseEvent (SWT.MouseDown, 1, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);
1864         if (sendMouseEvent (SWT.MouseDoubleClick, 1, hwnd, OS.WM_LBUTTONDBLCLK, wParam, lParam)) {
1865                 result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONDBLCLK, wParam, lParam));
1866         } else {
1867                 result = LRESULT.ZERO;
1868         }
1869         if (!display.captureChanged && !isDisposed ()) {
1870                 if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
1871         }
1872         return result;
1873 }
1874
1875 LRESULT wmLButtonDown (long hwnd, long wParam, long lParam) {
1876         Display display = this.display;
1877         LRESULT result = null;
1878         int x = OS.GET_X_LPARAM (lParam);
1879         int y = OS.GET_Y_LPARAM (lParam);
1880         boolean [] consume = null, detect = null;
1881         boolean dragging = false, mouseDown = true;
1882         int count = display.getClickCount (SWT.MouseDown, 1, hwnd, lParam);
1883         if (count == 1 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
1884                 /*
1885                 * Feature in Windows.  It's possible that the drag
1886                 * operation will not be started while the mouse is
1887                 * down, meaning that the mouse should be captured.
1888                 * This can happen when the user types the ESC key
1889                 * to cancel the drag.  The fix is to query the state
1890                 * of the mouse and capture the mouse accordingly.
1891                 */
1892                 detect = new boolean [1];
1893                 consume = new boolean [1];
1894                 dragging = dragDetect (hwnd, x, y, true, detect, consume);
1895                 if (isDisposed ()) return LRESULT.ZERO;
1896                 mouseDown = OS.GetKeyState (OS.VK_LBUTTON) < 0;
1897         }
1898         display.captureChanged = false;
1899         boolean dispatch = sendMouseEvent (SWT.MouseDown, 1, count, 0, false, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);
1900         if (dispatch && (consume == null || !consume [0])) {
1901                 result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONDOWN, wParam, lParam));
1902         } else {
1903                 result = LRESULT.ZERO;
1904         }
1905         if (mouseDown) {
1906                 if (!display.captureChanged && !isDisposed ()) {
1907                         if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
1908                 }
1909         }
1910         if (dragging) {
1911                 sendDragEvent (1, x, y);
1912         } else {
1913                 if (detect != null && detect [0]) {
1914                         /*
1915                         * Feature in Windows.  DragDetect() captures the mouse
1916                         * and tracks its movement until the user releases the
1917                         * left mouse button, presses the ESC key, or moves the
1918                         * mouse outside the drag rectangle.  If the user moves
1919                         * the mouse outside of the drag rectangle, DragDetect()
1920                         * returns true and a drag and drop operation can be
1921                         * started.  When the left mouse button is released or
1922                         * the ESC key is pressed, these events are consumed by
1923                         * DragDetect() so that application code that matches
1924                         * mouse down/up pairs or looks for the ESC key will not
1925                         * function properly.  The fix is to send the missing
1926                         * events when the drag has not started.
1927                         *
1928                         * NOTE: For now, don't send a fake WM_KEYDOWN/WM_KEYUP
1929                         * events for the ESC key.  This would require computing
1930                         * wParam (the key) and lParam (the repeat count, scan code,
1931                         * extended-key flag, context code, previous key-state flag,
1932                         * and transition-state flag) which is non-trivial.
1933                         */
1934                         if (OS.GetKeyState (OS.VK_ESCAPE) >= 0) {
1935                                 OS.SendMessage (hwnd, OS.WM_LBUTTONUP, wParam, lParam);
1936                         }
1937                 }
1938         }
1939         return result;
1940 }
1941
1942 LRESULT wmLButtonUp (long hwnd, long wParam, long lParam) {
1943         Display display = this.display;
1944         LRESULT result = null;
1945         if (sendMouseEvent (SWT.MouseUp, 1, hwnd, OS.WM_LBUTTONUP, wParam, lParam)) {
1946                 result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONUP, wParam, lParam));
1947         } else {
1948                 result = LRESULT.ZERO;
1949         }
1950         /*
1951         * Bug in Windows.  On some machines that do not have XBUTTONs,
1952         * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
1953         * causing mouse capture to become stuck.  The fix is to test
1954         * for the extra buttons only when they exist.
1955         */
1956         int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
1957         if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
1958         if ((wParam & mask) == 0) {
1959                 if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
1960         }
1961         return result;
1962 }
1963
1964 LRESULT wmMButtonDblClk (long hwnd, long wParam, long lParam) {
1965         /*
1966         * Feature in Windows. Windows sends the following
1967         * messages when the user double clicks the mouse:
1968         *
1969         *       WM_MBUTTONDOWN          - mouse down
1970         *       WM_MBUTTONUP            - mouse up
1971         *       WM_MLBUTTONDBLCLK       - double click
1972         *       WM_MBUTTONUP            - mouse up
1973         *
1974         * Applications that expect matching mouse down/up
1975         * pairs will not see the second mouse down.  The
1976         * fix is to send a mouse down event.
1977         */
1978         LRESULT result = null;
1979         Display display = this.display;
1980         display.captureChanged = false;
1981         sendMouseEvent (SWT.MouseDown, 2, hwnd, OS.WM_MBUTTONDOWN, wParam, lParam);
1982         if (sendMouseEvent (SWT.MouseDoubleClick, 2, hwnd, OS.WM_MBUTTONDBLCLK, wParam, lParam)) {
1983                 result = new LRESULT (callWindowProc (hwnd, OS.WM_MBUTTONDBLCLK, wParam, lParam));
1984         } else {
1985                 result = LRESULT.ZERO;
1986         }
1987         if (!display.captureChanged && !isDisposed ()) {
1988                 if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
1989         }
1990         return result;
1991 }
1992
1993 LRESULT wmMButtonDown (long hwnd, long wParam, long lParam) {
1994         LRESULT result = null;
1995         Display display = this.display;
1996         display.captureChanged = false;
1997         if (sendMouseEvent (SWT.MouseDown, 2, hwnd, OS.WM_MBUTTONDOWN, wParam, lParam)) {
1998                 result = new LRESULT (callWindowProc (hwnd, OS.WM_MBUTTONDOWN, wParam, lParam));
1999         } else {
2000                 result = LRESULT.ZERO;
2001         }
2002         if (!display.captureChanged && !isDisposed ()) {
2003                 if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2004         }
2005         return result;
2006 }
2007
2008 LRESULT wmMButtonUp (long hwnd, long wParam, long lParam) {
2009         Display display = this.display;
2010         LRESULT result = null;
2011         if (sendMouseEvent (SWT.MouseUp, 2, hwnd, OS.WM_MBUTTONUP, wParam, lParam)) {
2012                 result = new LRESULT (callWindowProc (hwnd, OS.WM_MBUTTONUP, wParam, lParam));
2013         } else {
2014                 result = LRESULT.ZERO;
2015         }
2016         /*
2017         * Bug in Windows.  On some machines that do not have XBUTTONs,
2018         * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
2019         * causing mouse capture to become stuck.  The fix is to test
2020         * for the extra buttons only when they exist.
2021         */
2022         int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
2023         if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
2024         if ((wParam & mask) == 0) {
2025                 if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
2026         }
2027         return result;
2028 }
2029
2030 LRESULT wmMouseHover (long hwnd, long wParam, long lParam) {
2031         if (!sendMouseEvent (SWT.MouseHover, 0, hwnd, OS.WM_MOUSEHOVER, wParam, lParam)) {
2032                 return LRESULT.ZERO;
2033         }
2034         return null;
2035 }
2036
2037 LRESULT wmMouseLeave (long hwnd, long wParam, long lParam) {
2038         if (!hooks (SWT.MouseExit) && !filters (SWT.MouseExit)) return null;
2039         int pos = OS.GetMessagePos ();
2040         POINT pt = new POINT ();
2041         OS.POINTSTOPOINT (pt, pos);
2042         OS.ScreenToClient (hwnd, pt);
2043         lParam = OS.MAKELPARAM (pt.x, pt.y);
2044         if (!sendMouseEvent (SWT.MouseExit, 0, hwnd, OS.WM_MOUSELEAVE, wParam, lParam)) {
2045                 return LRESULT.ZERO;
2046         }
2047         return null;
2048 }
2049
2050 LRESULT wmMouseMove (long hwnd, long wParam, long lParam) {
2051         LRESULT result = null;
2052         Display display = this.display;
2053         int pos = OS.GetMessagePos ();
2054         if (pos != display.lastMouse || display.captureChanged) {
2055                 boolean trackMouse = (state & TRACK_MOUSE) != 0;
2056                 boolean mouseEnter = hooks (SWT.MouseEnter) || display.filters (SWT.MouseEnter);
2057                 boolean mouseExit = hooks (SWT.MouseExit) || display.filters (SWT.MouseExit);
2058                 boolean mouseHover = hooks (SWT.MouseHover) || display.filters (SWT.MouseHover);
2059                 if (trackMouse || mouseEnter || mouseExit || mouseHover) {
2060                         TRACKMOUSEEVENT lpEventTrack = new TRACKMOUSEEVENT ();
2061                         lpEventTrack.cbSize = TRACKMOUSEEVENT.sizeof;
2062                         lpEventTrack.dwFlags = OS.TME_QUERY;
2063                         lpEventTrack.hwndTrack = hwnd;
2064                         OS.TrackMouseEvent (lpEventTrack);
2065                         if (lpEventTrack.dwFlags == 0) {
2066                                 lpEventTrack.dwFlags = OS.TME_LEAVE | OS.TME_HOVER;
2067                                 lpEventTrack.hwndTrack = hwnd;
2068                                 OS.TrackMouseEvent (lpEventTrack);
2069                                 if (mouseEnter) {
2070                                         /*
2071                                         * Force all outstanding WM_MOUSELEAVE messages to be dispatched before
2072                                         * issuing a mouse enter.  This causes mouse exit events to be processed
2073                                         * before mouse enter events.  Note that WM_MOUSELEAVE is posted to the
2074                                         * event queue by TrackMouseEvent().
2075                                         */
2076                                         MSG msg = new MSG ();
2077                                         int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
2078                                         while (OS.PeekMessage (msg, 0, OS.WM_MOUSELEAVE, OS.WM_MOUSELEAVE, flags)) {
2079                                                 OS.TranslateMessage (msg);
2080                                                 OS.DispatchMessage (msg);
2081                                         }
2082                                         sendMouseEvent (SWT.MouseEnter, 0, hwnd, OS.WM_MOUSEMOVE, wParam, lParam);
2083                                 }
2084                         } else {
2085                                 lpEventTrack.dwFlags = OS.TME_HOVER;
2086                                 OS.TrackMouseEvent (lpEventTrack);
2087                         }
2088                 }
2089                 if (pos != display.lastMouse) {
2090                         display.lastMouse = pos;
2091                         if (!sendMouseEvent (SWT.MouseMove, 0, hwnd, OS.WM_MOUSEMOVE, wParam, lParam)) {
2092                                 result = LRESULT.ZERO;
2093                         }
2094                 }
2095         }
2096         display.captureChanged = false;
2097         return result;
2098 }
2099
2100 LRESULT wmMouseWheel (long hwnd, long wParam, long lParam) {
2101         return sendMouseWheelEvent(SWT.MouseWheel, hwnd, wParam, lParam) ? null : LRESULT.ZERO;
2102 }
2103
2104 LRESULT wmMouseHWheel (long hwnd, long wParam, long lParam) {
2105         return sendMouseWheelEvent(SWT.MouseHorizontalWheel, hwnd, wParam, lParam) ? null : LRESULT.ZERO;
2106 }
2107
2108 LRESULT wmNCPaint (long hwnd, long wParam, long lParam) {
2109         return null;
2110 }
2111
2112 LRESULT wmPaint (long hwnd, long wParam, long lParam) {
2113
2114         /* Exit early - don't draw the background */
2115         if (!hooks (SWT.Paint) && !filters (SWT.Paint)) {
2116                 return null;
2117         }
2118
2119         /* Issue a paint event */
2120         long rgn = OS.CreateRectRgn (0, 0, 0, 0);
2121         OS.GetUpdateRgn (hwnd, rgn, false);
2122         long result = callWindowProc (hwnd, OS.WM_PAINT, wParam, lParam);
2123         GCData data = new GCData ();
2124         data.hwnd = hwnd;
2125         GC gc = new_GC (data);
2126         if (gc != null) {
2127                 OS.HideCaret (hwnd);
2128                 RECT rect = new RECT();
2129                 OS.GetRgnBox (rgn, rect);
2130                 int width = rect.right - rect.left;
2131                 int height = rect.bottom - rect.top;
2132                 if (width != 0 && height != 0) {
2133                         long hDC = gc.handle;
2134                         OS.SelectClipRgn (hDC, rgn);
2135                         OS.SetMetaRgn (hDC);
2136                         Event event = new Event ();
2137                         event.gc = gc;
2138                         event.setBoundsInPixels(new Rectangle(rect.left, rect.top, width, height));
2139                         sendEvent (SWT.Paint, event);
2140                         // widget could be disposed at this point
2141                         event.gc = null;
2142                 }
2143                 gc.dispose ();
2144                 OS.ShowCaret (hwnd);
2145         }
2146         OS.DeleteObject (rgn);
2147         if (result == 0) return LRESULT.ZERO;
2148         return new LRESULT (result);
2149 }
2150
2151 LRESULT wmPrint (long hwnd, long wParam, long lParam) {
2152         /*
2153         * Bug in Windows.  When WM_PRINT is used to print the contents
2154         * of a control that has WS_EX_CLIENTEDGE, the old 3D border is
2155         * drawn instead of the theme border.  The fix is to call the
2156         * default window proc and then draw the theme border on top.
2157         */
2158         if ((lParam & OS.PRF_NONCLIENT) != 0) {
2159                 if (OS.IsAppThemed ()) {
2160                         int bits = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE);
2161                         if ((bits & OS.WS_EX_CLIENTEDGE) != 0) {
2162                                 long code = callWindowProc (hwnd, OS.WM_PRINT, wParam, lParam);
2163                                 RECT rect = new RECT ();
2164                                 OS.GetWindowRect (hwnd, rect);
2165                                 rect.right -= rect.left;
2166                                 rect.bottom -= rect.top;
2167                                 rect.left = rect.top = 0;
2168                                 int border = OS.GetSystemMetrics (OS.SM_CXEDGE);
2169                                 OS.ExcludeClipRect (wParam, border, border, rect.right - border, rect.bottom - border);
2170                                 OS.DrawThemeBackground (display.hEditTheme (), wParam, OS.EP_EDITTEXT, OS.ETS_NORMAL, rect, null);
2171                                 return new LRESULT (code);
2172                         }
2173                 }
2174         }
2175         return null;
2176 }
2177
2178 LRESULT wmRButtonDblClk (long hwnd, long wParam, long lParam) {
2179         /*
2180         * Feature in Windows. Windows sends the following
2181         * messages when the user double clicks the mouse:
2182         *
2183         *       WM_RBUTTONDOWN          - mouse down
2184         *       WM_RBUTTONUP            - mouse up
2185         *       WM_RBUTTONDBLCLK        - double click
2186         *       WM_LBUTTONUP            - mouse up
2187         *
2188         * Applications that expect matching mouse down/up
2189         * pairs will not see the second mouse down.  The
2190         * fix is to send a mouse down event.
2191         */
2192         LRESULT result = null;
2193         Display display = this.display;
2194         display.captureChanged = false;
2195         sendMouseEvent (SWT.MouseDown, 3, hwnd, OS.WM_RBUTTONDOWN, wParam, lParam);
2196         if (sendMouseEvent (SWT.MouseDoubleClick, 3, hwnd, OS.WM_RBUTTONDBLCLK, wParam, lParam)) {
2197                 result = new LRESULT (callWindowProc (hwnd, OS.WM_RBUTTONDBLCLK, wParam, lParam));
2198         } else {
2199                 result = LRESULT.ZERO;
2200         }
2201         if (!display.captureChanged && !isDisposed ()) {
2202                 if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2203         }
2204         return result;
2205 }
2206
2207 LRESULT wmRButtonDown (long hwnd, long wParam, long lParam) {
2208         LRESULT result = null;
2209         Display display = this.display;
2210         display.captureChanged = false;
2211         if (sendMouseEvent (SWT.MouseDown, 3, hwnd, OS.WM_RBUTTONDOWN, wParam, lParam)) {
2212                 result = new LRESULT (callWindowProc (hwnd, OS.WM_RBUTTONDOWN, wParam, lParam));
2213         } else {
2214                 result = LRESULT.ZERO;
2215         }
2216         if (!display.captureChanged && !isDisposed ()) {
2217                 if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2218         }
2219         return result;
2220 }
2221
2222 LRESULT wmRButtonUp (long hwnd, long wParam, long lParam) {
2223         Display display = this.display;
2224         LRESULT result = null;
2225         if (sendMouseEvent (SWT.MouseUp, 3, hwnd, OS.WM_RBUTTONUP, wParam, lParam)) {
2226                 result = new LRESULT (callWindowProc (hwnd, OS.WM_RBUTTONUP, wParam, lParam));
2227         } else {
2228                 /* Call the DefWindowProc() to support WM_CONTEXTMENU */
2229                 OS.DefWindowProc (hwnd, OS.WM_RBUTTONUP, wParam, lParam);
2230                 result = LRESULT.ZERO;
2231         }
2232         /*
2233         * Bug in Windows.  On some machines that do not have XBUTTONs,
2234         * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
2235         * causing mouse capture to become stuck.  The fix is to test
2236         * for the extra buttons only when they exist.
2237         */
2238         int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
2239         if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
2240         if ((wParam & mask) == 0) {
2241                 if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
2242         }
2243         return result;
2244 }
2245
2246 LRESULT wmSetFocus (long hwnd, long wParam, long lParam) {
2247         long code = callWindowProc (hwnd, OS.WM_SETFOCUS, wParam, lParam);
2248         sendFocusEvent (SWT.FocusIn);
2249         // widget could be disposed at this point
2250
2251         /*
2252         * It is possible (but unlikely), that application
2253         * code could have disposed the widget in the focus
2254         * or activate events.  If this happens, end the
2255         * processing of the Windows message by returning
2256         * zero as the result of the window proc.
2257         */
2258         if (isDisposed ()) return LRESULT.ZERO;
2259         if (code == 0) return LRESULT.ZERO;
2260         return new LRESULT (code);
2261 }
2262
2263 LRESULT wmSysChar (long hwnd, long wParam, long lParam) {
2264         Display display = this.display;
2265         display.lastAscii = (int)wParam;
2266         display.lastNull = wParam == 0;
2267
2268         /* Do not issue a key down if a menu bar mnemonic was invoked */
2269         if (!hooks (SWT.KeyDown) && !display.filters (SWT.KeyDown)) {
2270                 return null;
2271         }
2272
2273         /* Call the window proc to determine whether it is a system key or mnemonic */
2274         boolean oldKeyHit = display.mnemonicKeyHit;
2275         display.mnemonicKeyHit = true;
2276         long result = callWindowProc (hwnd, OS.WM_SYSCHAR, wParam, lParam);
2277         boolean consumed = false;
2278         if (!display.mnemonicKeyHit) {
2279                 consumed = !sendKeyEvent (SWT.KeyDown, OS.WM_SYSCHAR, wParam, lParam);
2280                 // widget could be disposed at this point
2281         }
2282         consumed |= display.mnemonicKeyHit;
2283         display.mnemonicKeyHit = oldKeyHit;
2284         return consumed ? LRESULT.ONE : new LRESULT (result);
2285 }
2286
2287 LRESULT wmSysKeyDown (long hwnd, long wParam, long lParam) {
2288         /*
2289         * Feature in Windows.  When WM_SYSKEYDOWN is sent,
2290         * the user pressed ALT+<key> or F10 to get to the
2291         * menu bar.  In order to issue events for F10 but
2292         * ignore other key presses when the ALT is not down,
2293         * make sure that either F10 was pressed or that ALT
2294         * is pressed.
2295         */
2296         if (wParam != OS.VK_F10) {
2297                 /* Make sure WM_SYSKEYDOWN was sent by ALT-<aKey>. */
2298                 if ((lParam & 0x20000000) == 0) return null;
2299         }
2300
2301         /* Ignore well known system keys */
2302         switch ((int)wParam) {
2303                 case OS.VK_F4: {
2304                         long hwndShell = hwnd;
2305                         while (OS.GetParent (hwndShell) != 0) {
2306                                 if (OS.GetWindow (hwndShell, OS.GW_OWNER) != 0) break;
2307                                 hwndShell = OS.GetParent (hwndShell);
2308                         }
2309                         int bits = OS.GetWindowLong (hwndShell, OS.GWL_STYLE);
2310                         if ((bits & OS.WS_SYSMENU) != 0) return null;
2311                 }
2312         }
2313
2314         /* Ignore repeating modifier keys by testing key down state */
2315         switch ((int)wParam) {
2316                 case OS.VK_SHIFT:
2317                 case OS.VK_MENU:
2318                 case OS.VK_CONTROL:
2319                 case OS.VK_CAPITAL:
2320                 case OS.VK_NUMLOCK:
2321                 case OS.VK_SCROLL:
2322                         if ((lParam & 0x40000000) != 0) return null;
2323         }
2324
2325         /* Clear last key and last ascii because a new key has been typed */
2326         display.lastAscii = display.lastKey = 0;
2327         display.lastVirtual = display.lastNull = display.lastDead = false;
2328
2329         /* If are going to get a WM_SYSCHAR, ignore this message. */
2330         int mapKey = OS.MapVirtualKey ((int)wParam, 2);
2331
2332         display.lastVirtual = mapKey == 0 || display.numpadKey ((int)wParam) != 0;
2333         if (display.lastVirtual) {
2334                 display.lastKey = (int)wParam;
2335                 /*
2336                 * Feature in Windows.  The virtual key VK_DELETE is not
2337                 * treated as both a virtual key and an ASCII key by Windows.
2338                 * Therefore, we will not receive a WM_SYSCHAR for this key.
2339                 * The fix is to treat VK_DELETE as a special case and map
2340                 * the ASCII value explicitly (Delete is 0x7F).
2341                 */
2342                 if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
2343
2344                 /* When a keypad key is typed, a WM_SYSCHAR is not issued */
2345                 if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
2346                         /*
2347                         * A WM_SYSCHAR will be issued for '*', '+', '-', '.' and '/'
2348                         * on the numeric keypad.  Avoid issuing the key event twice
2349                         * by checking for these keys.  Note that calling to ToAscii()
2350                         * or ToUnicode(), clear the character that is entered using
2351                         * the special Windows keypad sequence when NumLock is down
2352                         * (ie. typing ALT+0231 should gives 'c' with a cedilla when
2353                         * NumLock is down).  Do not call either of these from here.
2354                         */
2355                         switch (display.lastKey) {
2356                                 case OS.VK_MULTIPLY:
2357                                 case OS.VK_ADD:
2358                                 case OS.VK_SUBTRACT:
2359                                 case OS.VK_DECIMAL:
2360                                 case OS.VK_DIVIDE: return null;
2361                         }
2362                         display.lastAscii = display.numpadKey (display.lastKey);
2363                 }
2364         } else {
2365                 /*
2366                 * Convert LastKey to lower case because Windows non-virtual
2367                 * keys that are also ASCII keys, such as like VK_A, are have
2368                 * upper case values in WM_SYSKEYDOWN despite the fact that the
2369                 * Shift was not pressed.
2370                 */
2371                 display.lastKey = (int)OS.CharLower ((short) mapKey);
2372                 return null;
2373         }
2374
2375         if (!sendKeyEvent (SWT.KeyDown, OS.WM_SYSKEYDOWN, wParam, lParam)) {
2376                 return LRESULT.ONE;
2377         }
2378         // widget could be disposed at this point
2379         return null;
2380 }
2381
2382 LRESULT wmSysKeyUp (long hwnd, long wParam, long lParam) {
2383         return wmKeyUp (hwnd, wParam, lParam);
2384 }
2385
2386 LRESULT wmXButtonDblClk (long hwnd, long wParam, long lParam) {
2387         /*
2388         * Feature in Windows. Windows sends the following
2389         * messages when the user double clicks the mouse:
2390         *
2391         *       WM_XBUTTONDOWN          - mouse down
2392         *       WM_XBUTTONUP            - mouse up
2393         *       WM_XLBUTTONDBLCLK       - double click
2394         *       WM_XBUTTONUP            - mouse up
2395         *
2396         * Applications that expect matching mouse down/up
2397         * pairs will not see the second mouse down.  The
2398         * fix is to send a mouse down event.
2399         */
2400         LRESULT result = null;
2401         Display display = this.display;
2402         display.captureChanged = false;
2403         int button = OS.HIWORD (wParam) == OS.XBUTTON1 ? 4 : 5;
2404         sendMouseEvent (SWT.MouseDown, button, hwnd, OS.WM_XBUTTONDOWN, wParam, lParam);
2405         if (sendMouseEvent (SWT.MouseDoubleClick, button, hwnd, OS.WM_XBUTTONDBLCLK, wParam, lParam)) {
2406                 result = new LRESULT (callWindowProc (hwnd, OS.WM_XBUTTONDBLCLK, wParam, lParam));
2407         } else {
2408                 result = LRESULT.ZERO;
2409         }
2410         if (!display.captureChanged && !isDisposed ()) {
2411                 if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2412         }
2413         return result;
2414 }
2415
2416 LRESULT wmXButtonDown (long hwnd, long wParam, long lParam) {
2417         LRESULT result = null;
2418         Display display = this.display;
2419         display.captureChanged = false;
2420         display.xMouse = true;
2421         int button = OS.HIWORD (wParam) == OS.XBUTTON1 ? 4 : 5;
2422         if (sendMouseEvent (SWT.MouseDown, button, hwnd, OS.WM_XBUTTONDOWN, wParam, lParam)) {
2423                 result = new LRESULT (callWindowProc (hwnd, OS.WM_XBUTTONDOWN, wParam, lParam));
2424         } else {
2425                 result = LRESULT.ZERO;
2426         }
2427         if (!display.captureChanged && !isDisposed ()) {
2428                 if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
2429         }
2430         return result;
2431 }
2432
2433 LRESULT wmXButtonUp (long hwnd, long wParam, long lParam) {
2434         Display display = this.display;
2435         LRESULT result = null;
2436         int button = OS.HIWORD (wParam) == OS.XBUTTON1 ? 4 : 5;
2437         if (sendMouseEvent (SWT.MouseUp, button, hwnd, OS.WM_XBUTTONUP, wParam, lParam)) {
2438                 result = new LRESULT (callWindowProc (hwnd, OS.WM_XBUTTONUP, wParam, lParam));
2439         } else {
2440                 result = LRESULT.ZERO;
2441         }
2442         /*
2443         * Bug in Windows.  On some machines that do not have XBUTTONs,
2444         * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
2445         * causing mouse capture to become stuck.  The fix is to test
2446         * for the extra buttons only when they exist.
2447         */
2448         int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
2449         if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
2450         if ((wParam & mask) == 0) {
2451                 if (OS.GetCapture () == hwnd) OS.ReleaseCapture ();
2452         }
2453         return result;
2454 }
2455 }