]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Display.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / Display.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  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15
16 import java.net.*;
17 import java.util.*;
18 import java.util.function.*;
19
20 import org.eclipse.swt.*;
21 import org.eclipse.swt.graphics.*;
22 import org.eclipse.swt.internal.*;
23 import org.eclipse.swt.internal.ole.win32.*;
24 import org.eclipse.swt.internal.win32.*;
25
26 /**
27  * Instances of this class are responsible for managing the
28  * connection between SWT and the underlying operating
29  * system. Their most important function is to implement
30  * the SWT event loop in terms of the platform event model.
31  * They also provide various methods for accessing information
32  * about the operating system, and have overall control over
33  * the operating system resources which SWT allocates.
34  * <p>
35  * Applications which are built with SWT will <em>almost always</em>
36  * require only a single display. In particular, some platforms
37  * which SWT supports will not allow more than one <em>active</em>
38  * display. In other words, some platforms do not support
39  * creating a new display if one already exists that has not been
40  * sent the <code>dispose()</code> message.
41  * <p>
42  * In SWT, the thread which creates a <code>Display</code>
43  * instance is distinguished as the <em>user-interface thread</em>
44  * for that display.
45  * </p>
46  * The user-interface thread for a particular display has the
47  * following special attributes:
48  * <ul>
49  * <li>
50  * The event loop for that display must be run from the thread.
51  * </li>
52  * <li>
53  * Some SWT API methods (notably, most of the public methods in
54  * <code>Widget</code> and its subclasses), may only be called
55  * from the thread. (To support multi-threaded user-interface
56  * applications, class <code>Display</code> provides inter-thread
57  * communication methods which allow threads other than the
58  * user-interface thread to request that it perform operations
59  * on their behalf.)
60  * </li>
61  * <li>
62  * The thread is not allowed to construct other
63  * <code>Display</code>s until that display has been disposed.
64  * (Note that, this is in addition to the restriction mentioned
65  * above concerning platform support for multiple displays. Thus,
66  * the only way to have multiple simultaneously active displays,
67  * even on platforms which support it, is to have multiple threads.)
68  * </li>
69  * </ul>
70  * <p>
71  * Enforcing these attributes allows SWT to be implemented directly
72  * on the underlying operating system's event model. This has
73  * numerous benefits including smaller footprint, better use of
74  * resources, safer memory management, clearer program logic,
75  * better performance, and fewer overall operating system threads
76  * required. The down side however, is that care must be taken
77  * (only) when constructing multi-threaded applications to use the
78  * inter-thread communication mechanisms which this class provides
79  * when required.
80  * </p><p>
81  * All SWT API methods which may only be called from the user-interface
82  * thread are distinguished in their documentation by indicating that
83  * they throw the "<code>ERROR_THREAD_INVALID_ACCESS</code>"
84  * SWT exception.
85  * </p>
86  * <dl>
87  * <dt><b>Styles:</b></dt>
88  * <dd>(none)</dd>
89  * <dt><b>Events:</b></dt>
90  * <dd>Close, Dispose, OpenDocument, Settings, Skin</dd>
91  * </dl>
92  * <p>
93  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
94  * </p>
95  * @see #syncExec
96  * @see #asyncExec
97  * @see #wake
98  * @see #readAndDispatch
99  * @see #sleep
100  * @see Device#dispose
101  * @see <a href="http://www.eclipse.org/swt/snippets/#display">Display snippets</a>
102  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
103  * @noextend This class is not intended to be subclassed by clients.
104  */
105 public class Display extends Device {
106
107         /**
108          * the handle to the OS message queue
109          * (Warning: This field is platform dependent)
110          * <p>
111          * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
112          * public API. It is marked public only so that it can be shared
113          * within the packages provided by SWT. It is not available on all
114          * platforms and should never be accessed from application code.
115          * </p>
116          *
117          * @noreference This field is not intended to be referenced by clients.
118          */
119         public MSG msg = new MSG ();
120
121         static String APP_NAME = "SWT"; //$NON-NLS-1$
122         static String APP_VERSION = ""; //$NON-NLS-1$
123
124         /* Windows and Events */
125         Event [] eventQueue;
126         Callback windowCallback;
127         long windowProc;
128         int threadId;
129         TCHAR windowClass, windowShadowClass, windowOwnDCClass;
130         static int WindowClassCount;
131         static final String WindowName = "SWT_Window"; //$NON-NLS-1$
132         static final String WindowShadowName = "SWT_WindowShadow"; //$NON-NLS-1$
133         static final String WindowOwnDCName = "SWT_WindowOwnDC"; //$NON-NLS-1$
134         EventTable eventTable, filterTable;
135         boolean useOwnDC;
136         boolean externalEventLoop; // events are dispatched outside SWT, e.g. TrackPopupMenu or DoDragDrop
137
138         /* Widget Table */
139         int freeSlot;
140         int [] indexTable;
141         Control lastControl, lastGetControl;
142         long lastHwnd, lastGetHwnd;
143         Control [] controlTable;
144         static final int GROW_SIZE = 1024;
145         static final int SWT_OBJECT_INDEX = OS.GlobalAddAtom (new TCHAR (0, "SWT_OBJECT_INDEX", true)); //$NON-NLS-1$
146
147         /* Startup info */
148         static STARTUPINFO lpStartupInfo;
149         static {
150                 lpStartupInfo = new STARTUPINFO ();
151                 lpStartupInfo.cb = STARTUPINFO.sizeof;
152                 OS.GetStartupInfo (lpStartupInfo);
153         }
154
155         /* XP Themes */
156         long hButtonTheme, hEditTheme, hExplorerBarTheme, hScrollBarTheme, hTabTheme;
157         static final char [] BUTTON = new char [] {'B', 'U', 'T', 'T', 'O', 'N', 0};
158         static final char [] EDIT = new char [] {'E', 'D', 'I', 'T', 0};
159         static final char [] EXPLORER = new char [] {'E', 'X', 'P', 'L', 'O', 'R', 'E', 'R', 0};
160         static final char [] EXPLORERBAR = new char [] {'E', 'X', 'P', 'L', 'O', 'R', 'E', 'R', 'B', 'A', 'R', 0};
161         static final char [] SCROLLBAR = new char [] {'S', 'C', 'R', 'O', 'L', 'L', 'B', 'A', 'R', 0};
162         static final char [] LISTVIEW = new char [] {'L', 'I', 'S', 'T', 'V', 'I', 'E', 'W', 0};
163         static final char [] TAB = new char [] {'T', 'A', 'B', 0};
164         static final char [] TREEVIEW = new char [] {'T', 'R', 'E', 'E', 'V', 'I', 'E', 'W', 0};
165
166         /* Custom icons */
167         long hIconSearch;
168         long hIconCancel;
169
170         /* Focus */
171         int focusEvent;
172         Control focusControl;
173         boolean fixFocus;
174
175         /* Menus */
176         Menu [] bars, popups;
177         MenuItem [] items;
178
179         /*
180         * The start value for WM_COMMAND id's.
181         * Windows reserves the values 0..100.
182         *
183         * The SmartPhone SWT resource file reserves
184         * the values 101..107.
185         */
186         static final int ID_START = 108;
187
188         /* Filter Hook */
189         Callback msgFilterCallback;
190         long msgFilterProc, filterHook;
191         MSG hookMsg = new MSG ();
192         boolean runDragDrop = true, dragCancelled = false;
193
194         /* Idle Hook */
195         Callback foregroundIdleCallback;
196         long foregroundIdleProc, idleHook;
197
198         /* Message Hook and Embedding */
199         boolean ignoreNextKey;
200         Callback getMsgCallback, embeddedCallback;
201         long getMsgProc, msgHook, embeddedHwnd, embeddedProc;
202         static final String AWT_WINDOW_CLASS = "SunAwtWindow"; //$NON-NLS-1$
203         static final short [] ACCENTS = new short [] {'~', '`', '\'', '^', '"'};
204
205         /* Sync/Async Widget Communication */
206         Synchronizer synchronizer = new Synchronizer (this);
207         Consumer<RuntimeException> runtimeExceptionHandler = DefaultExceptionHandler.RUNTIME_EXCEPTION_HANDLER;
208         Consumer<Error> errorHandler = DefaultExceptionHandler.RUNTIME_ERROR_HANDLER;
209         boolean runMessagesInIdle = false, runMessagesInMessageProc = true;
210         static final String RUN_MESSAGES_IN_IDLE_KEY = "org.eclipse.swt.internal.win32.runMessagesInIdle"; //$NON-NLS-1$
211         static final String RUN_MESSAGES_IN_MESSAGE_PROC_KEY = "org.eclipse.swt.internal.win32.runMessagesInMessageProc"; //$NON-NLS-1$
212         static final String USE_OWNDC_KEY = "org.eclipse.swt.internal.win32.useOwnDC"; //$NON-NLS-1$
213         static final String ACCEL_KEY_HIT = "org.eclipse.swt.internal.win32.accelKeyHit"; //$NON-NLS-1$
214         static final String EXTERNAL_EVENT_LOOP_KEY = "org.eclipse.swt.internal.win32.externalEventLoop"; //$NON-NLS-1$
215         Thread thread;
216
217         /* Display Shutdown */
218         Runnable [] disposeList;
219
220         /* Deferred Layout list */
221         Composite[] layoutDeferred;
222         int layoutDeferredCount;
223
224         /* System Tray */
225         Tray tray;
226         int nextTrayId;
227
228         /* TaskBar */
229         TaskBar taskBar;
230         static final String TASKBAR_EVENT = "/SWTINTERNAL_ID"; //$NON-NLS-1$
231         static final String LAUNCHER_PREFIX = "--launcher.openFile "; //$NON-NLS-1$
232
233         /* Timers */
234         long [] timerIds;
235         Runnable [] timerList;
236         long nextTimerId = SETTINGS_ID + 1;
237
238         /* Settings */
239         static final long SETTINGS_ID = 100;
240         static final int SETTINGS_DELAY = 2000;
241
242         /* Keyboard and Mouse */
243         RECT clickRect;
244         int clickCount, lastTime, lastButton;
245         long lastClickHwnd;
246         int scrollRemainder, scrollHRemainder;
247         int lastKey, lastMouse, lastAscii;
248         boolean lastVirtual, lastNull, lastDead;
249         byte [] keyboard = new byte [256];
250         boolean accelKeyHit, mnemonicKeyHit;
251         boolean lockActiveWindow, captureChanged, xMouse;
252
253         /* Gesture state */
254         double magStartDistance, lastDistance;
255         double rotationAngle;
256         int lastX, lastY;
257
258         /* Touch state */
259         TouchSource [] touchSources;
260
261         /* Tool Tips */
262         int nextToolTipId;
263
264         /* MDI */
265         boolean ignoreRestoreFocus;
266         Control lastHittestControl;
267         int lastHittest;
268
269         /* Message Only Window */
270         Callback messageCallback;
271         long hwndMessage, messageProc;
272
273         /* System Resources */
274         LOGFONT lfSystemFont;
275         Font systemFont;
276         Image errorImage, infoImage, questionImage, warningIcon;
277         Cursor [] cursors = new Cursor [SWT.CURSOR_HAND + 1];
278         Resource [] resources;
279         static final int RESOURCE_SIZE = 1 + 4 + SWT.CURSOR_HAND + 1;
280
281         /* ImageList Cache */
282         ImageList[] imageList, toolImageList, toolHotImageList, toolDisabledImageList;
283
284         /* Custom Colors for ChooseColor */
285         long lpCustColors;
286
287         /* Table */
288         char [] tableBuffer;
289
290         /* Resize and move recursion */
291         int resizeCount;
292         static final int RESIZE_LIMIT = 4;
293
294         /* Display Data */
295         Object data;
296         String [] keys;
297         Object [] values;
298
299         /* Key Mappings */
300         static final int [] [] KeyTable = {
301
302                 /* Keyboard and Mouse Masks */
303                 {OS.VK_MENU,    SWT.ALT},
304                 {OS.VK_SHIFT,   SWT.SHIFT},
305                 {OS.VK_CONTROL, SWT.CONTROL},
306 //              {OS.VK_????,    SWT.COMMAND},
307
308                 /* NOT CURRENTLY USED */
309 //              {OS.VK_LBUTTON, SWT.BUTTON1},
310 //              {OS.VK_MBUTTON, SWT.BUTTON3},
311 //              {OS.VK_RBUTTON, SWT.BUTTON2},
312
313                 /* Non-Numeric Keypad Keys */
314                 {OS.VK_UP,              SWT.ARROW_UP},
315                 {OS.VK_DOWN,    SWT.ARROW_DOWN},
316                 {OS.VK_LEFT,    SWT.ARROW_LEFT},
317                 {OS.VK_RIGHT,   SWT.ARROW_RIGHT},
318                 {OS.VK_PRIOR,   SWT.PAGE_UP},
319                 {OS.VK_NEXT,    SWT.PAGE_DOWN},
320                 {OS.VK_HOME,    SWT.HOME},
321                 {OS.VK_END,             SWT.END},
322                 {OS.VK_INSERT,  SWT.INSERT},
323
324                 /* Virtual and Ascii Keys */
325                 {OS.VK_BACK,    SWT.BS},
326                 {OS.VK_RETURN,  SWT.CR},
327                 {OS.VK_DELETE,  SWT.DEL},
328                 {OS.VK_ESCAPE,  SWT.ESC},
329                 {OS.VK_RETURN,  SWT.LF},
330                 {OS.VK_TAB,             SWT.TAB},
331
332                 /* Functions Keys */
333                 {OS.VK_F1,      SWT.F1},
334                 {OS.VK_F2,      SWT.F2},
335                 {OS.VK_F3,      SWT.F3},
336                 {OS.VK_F4,      SWT.F4},
337                 {OS.VK_F5,      SWT.F5},
338                 {OS.VK_F6,      SWT.F6},
339                 {OS.VK_F7,      SWT.F7},
340                 {OS.VK_F8,      SWT.F8},
341                 {OS.VK_F9,      SWT.F9},
342                 {OS.VK_F10,     SWT.F10},
343                 {OS.VK_F11,     SWT.F11},
344                 {OS.VK_F12,     SWT.F12},
345                 {OS.VK_F13,     SWT.F13},
346                 {OS.VK_F14,     SWT.F14},
347                 {OS.VK_F15,     SWT.F15},
348                 {OS.VK_F16,     SWT.F16},
349                 {OS.VK_F17,     SWT.F17},
350                 {OS.VK_F18,     SWT.F18},
351                 {OS.VK_F19,     SWT.F19},
352                 {OS.VK_F20,     SWT.F20},
353
354                 /* Numeric Keypad Keys */
355                 {OS.VK_MULTIPLY,        SWT.KEYPAD_MULTIPLY},
356                 {OS.VK_ADD,                     SWT.KEYPAD_ADD},
357                 {OS.VK_RETURN,          SWT.KEYPAD_CR},
358                 {OS.VK_SUBTRACT,        SWT.KEYPAD_SUBTRACT},
359                 {OS.VK_DECIMAL,         SWT.KEYPAD_DECIMAL},
360                 {OS.VK_DIVIDE,          SWT.KEYPAD_DIVIDE},
361                 {OS.VK_NUMPAD0,         SWT.KEYPAD_0},
362                 {OS.VK_NUMPAD1,         SWT.KEYPAD_1},
363                 {OS.VK_NUMPAD2,         SWT.KEYPAD_2},
364                 {OS.VK_NUMPAD3,         SWT.KEYPAD_3},
365                 {OS.VK_NUMPAD4,         SWT.KEYPAD_4},
366                 {OS.VK_NUMPAD5,         SWT.KEYPAD_5},
367                 {OS.VK_NUMPAD6,         SWT.KEYPAD_6},
368                 {OS.VK_NUMPAD7,         SWT.KEYPAD_7},
369                 {OS.VK_NUMPAD8,         SWT.KEYPAD_8},
370                 {OS.VK_NUMPAD9,         SWT.KEYPAD_9},
371 //              {OS.VK_????,            SWT.KEYPAD_EQUAL},
372
373                 /* Other keys */
374                 {OS.VK_CAPITAL,         SWT.CAPS_LOCK},
375                 {OS.VK_NUMLOCK,         SWT.NUM_LOCK},
376                 {OS.VK_SCROLL,          SWT.SCROLL_LOCK},
377                 {OS.VK_PAUSE,           SWT.PAUSE},
378                 {OS.VK_CANCEL,          SWT.BREAK},
379                 {OS.VK_SNAPSHOT,        SWT.PRINT_SCREEN},
380 //              {OS.VK_????,            SWT.HELP},
381
382         };
383
384         /* Multiple Displays */
385         static Display Default;
386         static Display [] Displays = new Display [4];
387
388         /* Multiple Monitors */
389         Monitor[] monitors = null;
390         int monitorCount = 0;
391
392         /* Modality */
393         Shell [] modalShells;
394         Dialog modalDialog;
395         static boolean TrimEnabled = false;
396
397         /* Private SWT Window Messages */
398         static final int SWT_GETACCELCOUNT      = OS.WM_APP;
399         static final int SWT_GETACCEL           = OS.WM_APP + 1;
400         static final int SWT_KEYMSG                     = OS.WM_APP + 2;
401         static final int SWT_DESTROY            = OS.WM_APP + 3;
402         static final int SWT_TRAYICONMSG        = OS.WM_APP + 4;
403         static final int SWT_NULL                       = OS.WM_APP + 5;
404         static final int SWT_RUNASYNC           = OS.WM_APP + 6;
405         static int TASKBARCREATED;
406         static int TASKBARBUTTONCREATED;
407         static int SWT_RESTORECARET;
408         static int DI_GETDRAGIMAGE;
409         static int SWT_OPENDOC;
410
411         /* Skinning support */
412         Widget [] skinList = new Widget [GROW_SIZE];
413         int skinCount;
414
415         /* Package Name */
416         static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets."; //$NON-NLS-1$
417         /*
418         * This code is intentionally commented.  In order
419         * to support CLDC, .class cannot be used because
420         * it does not compile on some Java compilers when
421         * they are targeted for CLDC.
422         */
423 //      static {
424 //              String name = Display.class.getName ();
425 //              int index = name.lastIndexOf ('.');
426 //              PACKAGE_PREFIX = name.substring (0, index + 1);
427 //      }
428
429         /*
430         * TEMPORARY CODE.  Install the runnable that
431         * gets the current display. This code will
432         * be removed in the future.
433         */
434         static {
435                 DeviceFinder = () -> {
436                         Device device = getCurrent ();
437                         if (device == null) {
438                                 device = getDefault ();
439                         }
440                         setDevice (device);
441                 };
442         }
443
444 /*
445 * TEMPORARY CODE.
446 */
447 static void setDevice (Device device) {
448         CurrentDevice = device;
449 }
450
451 /**
452  * Constructs a new instance of this class.
453  * <p>
454  * Note: The resulting display is marked as the <em>current</em>
455  * display. If this is the first display which has been
456  * constructed since the application started, it is also
457  * marked as the <em>default</em> display.
458  * </p>
459  *
460  * @exception SWTException <ul>
461  *    <li>ERROR_THREAD_INVALID_ACCESS - if called from a thread that already created an existing display</li>
462  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
463  * </ul>
464  *
465  * @see #getCurrent
466  * @see #getDefault
467  * @see Widget#checkSubclass
468  * @see Shell
469  */
470 public Display () {
471         this (null);
472 }
473
474 /**
475  * Constructs a new instance of this class using the parameter.
476  *
477  * @param data the device data
478  */
479 public Display (DeviceData data) {
480         super (data);
481 }
482
483 Control _getFocusControl () {
484         return findControl (OS.GetFocus ());
485 }
486
487 void addBar (Menu menu) {
488         if (bars == null) bars = new Menu [4];
489         int length = bars.length;
490         for (int i=0; i<length; i++) {
491                 if (bars [i] == menu) return;
492         }
493         int index = 0;
494         while (index < length) {
495                 if (bars [index] == null) break;
496                 index++;
497         }
498         if (index == length) {
499                 Menu [] newBars = new Menu [length + 4];
500                 System.arraycopy (bars, 0, newBars, 0, length);
501                 bars = newBars;
502         }
503         bars [index] = menu;
504 }
505
506 void addControl (long handle, Control control) {
507         if (handle == 0) return;
508         if (freeSlot == -1) {
509                 int length = (freeSlot = indexTable.length) + GROW_SIZE;
510                 int [] newIndexTable = new int [length];
511                 Control [] newControlTable = new Control [length];
512                 System.arraycopy (indexTable, 0, newIndexTable, 0, freeSlot);
513                 System.arraycopy (controlTable, 0, newControlTable, 0, freeSlot);
514                 for (int i=freeSlot; i<length-1; i++) newIndexTable [i] = i + 1;
515                 newIndexTable [length - 1] = -1;
516                 indexTable = newIndexTable;
517                 controlTable = newControlTable;
518         }
519         OS.SetProp (handle, SWT_OBJECT_INDEX, freeSlot + 1);
520         int oldSlot = freeSlot;
521         freeSlot = indexTable [oldSlot];
522         indexTable [oldSlot] = -2;
523         controlTable [oldSlot] = control;
524 }
525
526 void addSkinnableWidget (Widget widget) {
527         if (skinCount >= skinList.length) {
528                 Widget[] newSkinWidgets = new Widget [skinList.length + GROW_SIZE];
529                 System.arraycopy (skinList, 0, newSkinWidgets, 0, skinList.length);
530                 skinList = newSkinWidgets;
531         }
532         skinList [skinCount++] = widget;
533 }
534
535 /**
536  * Adds the listener to the collection of listeners who will
537  * be notified when an event of the given type occurs anywhere
538  * in a widget. The event type is one of the event constants
539  * defined in class <code>SWT</code>. When the event does occur,
540  * the listener is notified by sending it the <code>handleEvent()</code>
541  * message.
542  * <p>
543  * Setting the type of an event to <code>SWT.None</code> from
544  * within the <code>handleEvent()</code> method can be used to
545  * change the event type and stop subsequent Java listeners
546  * from running. Because event filters run before other listeners,
547  * event filters can both block other listeners and set arbitrary
548  * fields within an event. For this reason, event filters are both
549  * powerful and dangerous. They should generally be avoided for
550  * performance, debugging and code maintenance reasons.
551  * </p>
552  *
553  * @param eventType the type of event to listen for
554  * @param listener the listener which should be notified when the event occurs
555  *
556  * @exception IllegalArgumentException <ul>
557  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
558  * </ul>
559  * @exception SWTException <ul>
560  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
561  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
562  * </ul>
563  *
564  * @see Listener
565  * @see SWT
566  * @see #removeFilter
567  * @see #removeListener
568  *
569  * @since 3.0
570  */
571 public void addFilter (int eventType, Listener listener) {
572         checkDevice ();
573         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
574         if (filterTable == null) filterTable = new EventTable ();
575         filterTable.hook (eventType, listener);
576 }
577
578 void addLayoutDeferred (Composite comp) {
579         if (layoutDeferred == null) layoutDeferred = new Composite [64];
580         if (layoutDeferredCount == layoutDeferred.length) {
581                 Composite [] temp = new Composite [layoutDeferred.length + 64];
582                 System.arraycopy (layoutDeferred, 0, temp, 0, layoutDeferred.length);
583                 layoutDeferred = temp;
584         }
585         layoutDeferred[layoutDeferredCount++] = comp;
586 }
587
588 /**
589  * Adds the listener to the collection of listeners who will
590  * be notified when an event of the given type occurs. The event
591  * type is one of the event constants defined in class <code>SWT</code>.
592  * When the event does occur in the display, the listener is notified by
593  * sending it the <code>handleEvent()</code> message.
594  *
595  * @param eventType the type of event to listen for
596  * @param listener the listener which should be notified when the event occurs
597  *
598  * @exception IllegalArgumentException <ul>
599  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
600  * </ul>
601  * @exception SWTException <ul>
602  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
603  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
604  * </ul>
605  *
606  * @see Listener
607  * @see SWT
608  * @see #removeListener
609  *
610  * @since 2.0
611  */
612 public void addListener (int eventType, Listener listener) {
613         checkDevice ();
614         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
615         if (eventTable == null) eventTable = new EventTable ();
616         eventTable.hook (eventType, listener);
617 }
618
619 void addMenuItem (MenuItem item) {
620         if (items == null) items = new MenuItem [64];
621         for (int i=0; i<items.length; i++) {
622                 if (items [i] == null) {
623                         item.id = i + ID_START;
624                         items [i] = item;
625                         return;
626                 }
627         }
628         item.id = items.length + ID_START;
629         MenuItem [] newItems = new MenuItem [items.length + 64];
630         newItems [items.length] = item;
631         System.arraycopy (items, 0, newItems, 0, items.length);
632         items = newItems;
633 }
634
635 void addPopup (Menu menu) {
636         if (popups == null) popups = new Menu [4];
637         int length = popups.length;
638         for (int i=0; i<length; i++) {
639                 if (popups [i] == menu) return;
640         }
641         int index = 0;
642         while (index < length) {
643                 if (popups [index] == null) break;
644                 index++;
645         }
646         if (index == length) {
647                 Menu [] newPopups = new Menu [length + 4];
648                 System.arraycopy (popups, 0, newPopups, 0, length);
649                 popups = newPopups;
650         }
651         popups [index] = menu;
652 }
653
654 int asciiKey (int key) {
655         /* Get the current keyboard. */
656         for (int i=0; i<keyboard.length; i++) keyboard [i] = 0;
657         if (!OS.GetKeyboardState (keyboard)) return 0;
658
659         /* Translate the key to ASCII or UNICODE using the virtual keyboard */
660         char [] result = new char [1];
661         if (OS.ToUnicode (key, key, keyboard, result, 1, 0) == 1) return result [0];
662         return 0;
663 }
664
665 /**
666  * Causes the <code>run()</code> method of the runnable to
667  * be invoked by the user-interface thread at the next
668  * reasonable opportunity. The caller of this method continues
669  * to run in parallel, and is not notified when the
670  * runnable has completed.  Specifying <code>null</code> as the
671  * runnable simply wakes the user-interface thread when run.
672  * <p>
673  * Note that at the time the runnable is invoked, widgets
674  * that have the receiver as their display may have been
675  * disposed. Therefore, it is necessary to check for this
676  * case inside the runnable before accessing the widget.
677  * </p>
678  *
679  * @param runnable code to run on the user-interface thread or <code>null</code>
680  *
681  * @exception SWTException <ul>
682  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
683  * </ul>
684  *
685  * @see #syncExec
686  */
687 public void asyncExec (Runnable runnable) {
688         synchronized (Device.class) {
689                 if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
690                 synchronizer.asyncExec (runnable);
691         }
692 }
693
694 /**
695  * Causes the system hardware to emit a short sound
696  * (if it supports this capability).
697  *
698  * @exception SWTException <ul>
699  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
700  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
701  * </ul>
702  */
703 public void beep () {
704         checkDevice ();
705         OS.MessageBeep (OS.MB_OK);
706 }
707
708 /**
709  * Checks that this class can be subclassed.
710  * <p>
711  * IMPORTANT: See the comment in <code>Widget.checkSubclass()</code>.
712  * </p>
713  *
714  * @exception SWTException <ul>
715  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
716  * </ul>
717  *
718  * @see Widget#checkSubclass
719  */
720 protected void checkSubclass () {
721         if (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
722 }
723
724 @Override
725 protected void checkDevice () {
726         if (thread == null) error (SWT.ERROR_WIDGET_DISPOSED);
727         if (thread != Thread.currentThread ()) {
728                 /*
729                 * Bug in IBM JVM 1.6.  For some reason, under
730                 * conditions that are yet to be full understood,
731                 * Thread.currentThread() is either returning null
732                 * or a different instance from the one that was
733                 * saved when the Display was created.  This is
734                 * possibly a JIT problem because modifying this
735                 * method to print logging information when the
736                 * error happens seems to fix the problem.  The
737                 * fix is to use operating system calls to verify
738                 * that the current thread is not the Display thread.
739                 *
740                 * NOTE: Despite the fact that Thread.currentThread()
741                 * is used in other places, the failure has not been
742                 * observed in all places where it is called.
743                 */
744                 if (threadId != OS.GetCurrentThreadId ()) {
745                         error (SWT.ERROR_THREAD_INVALID_ACCESS);
746                 }
747         }
748         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
749 }
750
751 static void checkDisplay (Thread thread, boolean multiple) {
752         synchronized (Device.class) {
753                 for (int i=0; i<Displays.length; i++) {
754                         if (Displays [i] != null) {
755                                 if (!multiple) SWT.error (SWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]"); //$NON-NLS-1$
756                                 if (Displays [i].thread == thread) SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS);
757                         }
758                 }
759         }
760 }
761
762 void clearModal (Shell shell) {
763         if (modalShells == null) return;
764         int index = 0, length = modalShells.length;
765         while (index < length) {
766                 if (modalShells [index] == shell) break;
767                 if (modalShells [index] == null) return;
768                 index++;
769         }
770         if (index == length) return;
771         System.arraycopy (modalShells, index + 1, modalShells, index, --length - index);
772         modalShells [length] = null;
773         if (index == 0 && modalShells [0] == null) modalShells = null;
774         Shell [] shells = getShells ();
775         for (int i=0; i<shells.length; i++) shells [i].updateModal ();
776 }
777
778 int controlKey (int key) {
779         int upper = (int)OS.CharUpper ((short) key);
780         if (64 <= upper && upper <= 95) return upper & 0xBF;
781         return key;
782 }
783
784 /**
785  * Requests that the connection between SWT and the underlying
786  * operating system be closed.
787  *
788  * @exception SWTException <ul>
789  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
790  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
791  * </ul>
792  *
793  * @see Device#dispose
794  *
795  * @since 2.0
796  */
797 public void close () {
798         checkDevice ();
799         Event event = new Event ();
800         sendEvent (SWT.Close, event);
801         if (event.doit) dispose ();
802 }
803
804 /**
805  * Creates the device in the operating system.  If the device
806  * does not have a handle, this method may do nothing depending
807  * on the device.
808  * <p>
809  * This method is called before <code>init</code>.
810  * </p>
811  *
812  * @param data the DeviceData which describes the receiver
813  *
814  * @see #init
815  */
816 @Override
817 protected void create (DeviceData data) {
818         checkSubclass ();
819         checkDisplay (thread = Thread.currentThread (), true);
820         createDisplay (data);
821         register (this);
822         if (Default == null) Default = this;
823 }
824
825 void createDisplay (DeviceData data) {
826 }
827
828 static long create32bitDIB (Image image) {
829         int transparentPixel = -1, alpha = -1;
830         long hMask = 0, hBitmap = 0;
831         byte[] alphaData = null;
832         switch (image.type) {
833                 case SWT.ICON:
834                         ICONINFO info = new ICONINFO ();
835                         OS.GetIconInfo (image.handle, info);
836                         hBitmap = info.hbmColor;
837                         hMask = info.hbmMask;
838                         break;
839                 case SWT.BITMAP:
840                         ImageData data = image.getImageData (DPIUtil.getDeviceZoom ());
841                         hBitmap = image.handle;
842                         alpha = data.alpha;
843                         alphaData = data.alphaData;
844                         transparentPixel = data.transparentPixel;
845                         break;
846         }
847         BITMAP bm = new BITMAP ();
848         OS.GetObject (hBitmap, BITMAP.sizeof, bm);
849         int imgWidth = bm.bmWidth;
850         int imgHeight = bm.bmHeight;
851         long hDC = OS.GetDC (0);
852         long srcHdc = OS.CreateCompatibleDC (hDC);
853         long oldSrcBitmap = OS.SelectObject (srcHdc, hBitmap);
854         long memHdc = OS.CreateCompatibleDC (hDC);
855         BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
856         bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
857         bmiHeader.biWidth = imgWidth;
858         bmiHeader.biHeight = -imgHeight;
859         bmiHeader.biPlanes = 1;
860         bmiHeader.biBitCount = (short)32;
861         bmiHeader.biCompression = OS.BI_RGB;
862         byte [] bmi = new byte [BITMAPINFOHEADER.sizeof];
863         OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
864         long [] pBits = new long [1];
865         long memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
866         if (memDib == 0) SWT.error (SWT.ERROR_NO_HANDLES);
867         long oldMemBitmap = OS.SelectObject (memHdc, memDib);
868         BITMAP dibBM = new BITMAP ();
869         OS.GetObject (memDib, BITMAP.sizeof, dibBM);
870         int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
871         OS.BitBlt (memHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
872         byte red = 0, green = 0, blue = 0;
873         if (transparentPixel != -1) {
874                 if (bm.bmBitsPixel <= 8) {
875                         byte [] color = new byte [4];
876                         OS.GetDIBColorTable (srcHdc, transparentPixel, 1, color);
877                         blue = color [0];
878                         green = color [1];
879                         red = color [2];
880                 } else {
881                         switch (bm.bmBitsPixel) {
882                                 case 16:
883                                         blue = (byte)((transparentPixel & 0x1F) << 3);
884                                         green = (byte)((transparentPixel & 0x3E0) >> 2);
885                                         red = (byte)((transparentPixel & 0x7C00) >> 7);
886                                         break;
887                                 case 24:
888                                         blue = (byte)((transparentPixel & 0xFF0000) >> 16);
889                                         green = (byte)((transparentPixel & 0xFF00) >> 8);
890                                         red = (byte)(transparentPixel & 0xFF);
891                                         break;
892                                 case 32:
893                                         blue = (byte)((transparentPixel & 0xFF000000) >>> 24);
894                                         green = (byte)((transparentPixel & 0xFF0000) >> 16);
895                                         red = (byte)((transparentPixel & 0xFF00) >> 8);
896                                         break;
897                         }
898                 }
899         }
900         byte [] srcData = new byte [sizeInBytes];
901         OS.MoveMemory (srcData, pBits [0], sizeInBytes);
902         if (hMask != 0) {
903                 OS.SelectObject(srcHdc, hMask);
904                 for (int y = 0, dp = 0; y < imgHeight; ++y) {
905                         for (int x = 0; x < imgWidth; ++x) {
906                                 if (OS.GetPixel(srcHdc, x, y) != 0) {
907                                         srcData [dp + 0] = srcData [dp + 1] = srcData [dp + 2] = srcData[dp + 3] = (byte)0;
908                                 } else {
909                                         srcData[dp + 3] = (byte)0xFF;
910                                 }
911                                 dp += 4;
912                         }
913                 }
914         } else if (alpha != -1) {
915                 for (int y = 0, dp = 0; y < imgHeight; ++y) {
916                         for (int x = 0; x < imgWidth; ++x) {
917                                 int r = ((srcData[dp + 0] & 0xFF) * alpha) + 128;
918                                 r = (r + (r >> 8)) >> 8;
919                                 int g = ((srcData[dp + 1] & 0xFF) * alpha) + 128;
920                                 g = (g + (g >> 8)) >> 8;
921                                 int b = ((srcData[dp + 2] & 0xFF) * alpha) + 128;
922                                 b = (b + (b >> 8)) >> 8;
923                                 srcData[dp+0] = (byte)r;
924                                 srcData[dp+1] = (byte)g;
925                                 srcData[dp+2] = (byte)b;
926                                 srcData[dp+3] = (byte)alpha;
927                                 dp += 4;
928                         }
929                 }
930         } else if (alphaData != null) {
931                 for (int y = 0, dp = 0, ap = 0; y < imgHeight; ++y) {
932                         for (int x = 0; x < imgWidth; ++x) {
933                                 int a = alphaData[ap++] & 0xFF;
934                                 int r = ((srcData[dp + 0] & 0xFF) * a) + 128;
935                                 r = (r + (r >> 8)) >> 8;
936                                 int g = ((srcData[dp + 1] & 0xFF) * a) + 128;
937                                 g = (g + (g >> 8)) >> 8;
938                                 int b = ((srcData[dp + 2] & 0xFF) * a) + 128;
939                                 b = (b + (b >> 8)) >> 8;
940                                 srcData[dp+0] = (byte)r;
941                                 srcData[dp+1] = (byte)g;
942                                 srcData[dp+2] = (byte)b;
943                                 srcData[dp+3] = (byte)a;
944                                 dp += 4;
945                         }
946                 }
947         } else if (transparentPixel != -1) {
948                 for (int y = 0, dp = 0; y < imgHeight; ++y) {
949                         for (int x = 0; x < imgWidth; ++x) {
950                                 if (srcData [dp] == blue && srcData [dp + 1] == green && srcData [dp + 2] == red) {
951                                         srcData [dp + 0] = srcData [dp + 1] = srcData [dp + 2] = srcData [dp + 3] = (byte)0;
952                                 } else {
953                                         srcData [dp + 3] = (byte)0xFF;
954                                 }
955                                 dp += 4;
956                         }
957                 }
958         } else {
959                 for (int y = 0, dp = 0; y < imgHeight; ++y) {
960                         for (int x = 0; x < imgWidth; ++x) {
961                                 srcData [dp + 3] = (byte)0xFF;
962                                 dp += 4;
963                         }
964                 }
965         }
966         OS.MoveMemory (pBits [0], srcData, sizeInBytes);
967         OS.SelectObject (srcHdc, oldSrcBitmap);
968         OS.SelectObject (memHdc, oldMemBitmap);
969         OS.DeleteObject (srcHdc);
970         OS.DeleteObject (memHdc);
971         OS.ReleaseDC (0, hDC);
972         if (hBitmap != image.handle && hBitmap != 0) OS.DeleteObject (hBitmap);
973         if (hMask != 0) OS.DeleteObject (hMask);
974         return memDib;
975 }
976 static long create32bitDIB (long hBitmap, int alpha, byte [] alphaData, int transparentPixel) {
977         BITMAP bm = new BITMAP ();
978         OS.GetObject (hBitmap, BITMAP.sizeof, bm);
979         int imgWidth = bm.bmWidth;
980         int imgHeight = bm.bmHeight;
981         long hDC = OS.GetDC (0);
982         long srcHdc = OS.CreateCompatibleDC (hDC);
983         long oldSrcBitmap = OS.SelectObject (srcHdc, hBitmap);
984         long memHdc = OS.CreateCompatibleDC (hDC);
985         BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
986         bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
987         bmiHeader.biWidth = imgWidth;
988         bmiHeader.biHeight = -imgHeight;
989         bmiHeader.biPlanes = 1;
990         bmiHeader.biBitCount = (short)32;
991         bmiHeader.biCompression = OS.BI_RGB;
992         byte [] bmi = new byte [BITMAPINFOHEADER.sizeof];
993         OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
994         long [] pBits = new long [1];
995         long memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
996         if (memDib == 0) SWT.error (SWT.ERROR_NO_HANDLES);
997         long oldMemBitmap = OS.SelectObject (memHdc, memDib);
998         BITMAP dibBM = new BITMAP ();
999         OS.GetObject (memDib, BITMAP.sizeof, dibBM);
1000         int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
1001         OS.BitBlt (memHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
1002         byte red = 0, green = 0, blue = 0;
1003         if (transparentPixel != -1) {
1004                 if (bm.bmBitsPixel <= 8) {
1005                         byte [] color = new byte [4];
1006                         OS.GetDIBColorTable (srcHdc, transparentPixel, 1, color);
1007                         blue = color [0];
1008                         green = color [1];
1009                         red = color [2];
1010                 } else {
1011                         switch (bm.bmBitsPixel) {
1012                                 case 16:
1013                                         blue = (byte)((transparentPixel & 0x1F) << 3);
1014                                         green = (byte)((transparentPixel & 0x3E0) >> 2);
1015                                         red = (byte)((transparentPixel & 0x7C00) >> 7);
1016                                         break;
1017                                 case 24:
1018                                         blue = (byte)((transparentPixel & 0xFF0000) >> 16);
1019                                         green = (byte)((transparentPixel & 0xFF00) >> 8);
1020                                         red = (byte)(transparentPixel & 0xFF);
1021                                         break;
1022                                 case 32:
1023                                         blue = (byte)((transparentPixel & 0xFF000000) >>> 24);
1024                                         green = (byte)((transparentPixel & 0xFF0000) >> 16);
1025                                         red = (byte)((transparentPixel & 0xFF00) >> 8);
1026                                         break;
1027                         }
1028                 }
1029         }
1030         OS.SelectObject (srcHdc, oldSrcBitmap);
1031         OS.SelectObject (memHdc, oldMemBitmap);
1032         OS.DeleteObject (srcHdc);
1033         OS.DeleteObject (memHdc);
1034         OS.ReleaseDC (0, hDC);
1035         byte [] srcData = new byte [sizeInBytes];
1036         OS.MoveMemory (srcData, pBits [0], sizeInBytes);
1037         if (alpha != -1) {
1038                 for (int y = 0, dp = 0; y < imgHeight; ++y) {
1039                         for (int x = 0; x < imgWidth; ++x) {
1040                                 srcData [dp + 3] = (byte)alpha;
1041                                 dp += 4;
1042                         }
1043                 }
1044         } else if (alphaData != null) {
1045                 for (int y = 0, dp = 0, ap = 0; y < imgHeight; ++y) {
1046                         for (int x = 0; x < imgWidth; ++x) {
1047                                 srcData [dp + 3] = alphaData [ap++];
1048                                 dp += 4;
1049                         }
1050                 }
1051         } else if (transparentPixel != -1) {
1052                 for (int y = 0, dp = 0; y < imgHeight; ++y) {
1053                         for (int x = 0; x < imgWidth; ++x) {
1054                                 if (srcData [dp] == blue && srcData [dp + 1] == green && srcData [dp + 2] == red) {
1055                                         srcData [dp + 3] = (byte)0;
1056                                 } else {
1057                                         srcData [dp + 3] = (byte)0xFF;
1058                                 }
1059                                 dp += 4;
1060                         }
1061                 }
1062         }
1063         OS.MoveMemory (pBits [0], srcData, sizeInBytes);
1064         return memDib;
1065 }
1066
1067 static Image createIcon (Image image) {
1068         Device device = image.getDevice ();
1069         ImageData data = image.getImageData (DPIUtil.getDeviceZoom ());
1070         if (data.alpha == -1 && data.alphaData == null) {
1071                 ImageData mask = data.getTransparencyMask ();
1072                 return new Image (device, data, mask);
1073         }
1074         int width = data.width, height = data.height;
1075         long hMask, hBitmap;
1076         long hDC = device.internal_new_GC (null);
1077         long dstHdc = OS.CreateCompatibleDC (hDC), oldDstBitmap;
1078         hBitmap = Display.create32bitDIB (image.handle, data.alpha, data.alphaData, data.transparentPixel);
1079         hMask = OS.CreateBitmap (width, height, 1, 1, null);
1080         oldDstBitmap = OS.SelectObject (dstHdc, hMask);
1081         OS.PatBlt (dstHdc, 0, 0, width, height, OS.BLACKNESS);
1082         OS.SelectObject (dstHdc, oldDstBitmap);
1083         OS.DeleteDC (dstHdc);
1084         device.internal_dispose_GC (hDC, null);
1085         ICONINFO info = new ICONINFO ();
1086         info.fIcon = true;
1087         info.hbmColor = hBitmap;
1088         info.hbmMask = hMask;
1089         long hIcon = OS.CreateIconIndirect (info);
1090         if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1091         OS.DeleteObject (hBitmap);
1092         OS.DeleteObject (hMask);
1093         return Image.win32_new (device, SWT.ICON, hIcon);
1094 }
1095
1096 static void deregister (Display display) {
1097         synchronized (Device.class) {
1098                 for (int i=0; i<Displays.length; i++) {
1099                         if (display == Displays [i]) Displays [i] = null;
1100                 }
1101         }
1102 }
1103
1104 /**
1105  * Destroys the device in the operating system and releases
1106  * the device's handle.  If the device does not have a handle,
1107  * this method may do nothing depending on the device.
1108  * <p>
1109  * This method is called after <code>release</code>.
1110  * </p>
1111  * @see Device#dispose
1112  * @see #release
1113  */
1114 @Override
1115 protected void destroy () {
1116         if (this == Default) Default = null;
1117         deregister (this);
1118         destroyDisplay ();
1119 }
1120
1121 void destroyDisplay () {
1122 }
1123
1124 /**
1125  * Causes the <code>run()</code> method of the runnable to
1126  * be invoked by the user-interface thread just before the
1127  * receiver is disposed.  Specifying a <code>null</code> runnable
1128  * is ignored.
1129  *
1130  * @param runnable code to run at dispose time.
1131  *
1132  * @exception SWTException <ul>
1133  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1134  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1135  * </ul>
1136  */
1137 public void disposeExec (Runnable runnable) {
1138         checkDevice ();
1139         if (disposeList == null) disposeList = new Runnable [4];
1140         for (int i=0; i<disposeList.length; i++) {
1141                 if (disposeList [i] == null) {
1142                         disposeList [i] = runnable;
1143                         return;
1144                 }
1145         }
1146         Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
1147         System.arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
1148         newDisposeList [disposeList.length] = runnable;
1149         disposeList = newDisposeList;
1150 }
1151
1152 void drawMenuBars () {
1153         if (bars == null) return;
1154         for (int i=0; i<bars.length; i++) {
1155                 Menu menu = bars [i];
1156                 if (menu != null && !menu.isDisposed ()) menu.update ();
1157         }
1158         bars = null;
1159 }
1160
1161 long embeddedProc (long hwnd, long msg, long wParam, long lParam) {
1162         switch ((int)msg) {
1163                 case SWT_KEYMSG: {
1164                         MSG keyMsg = new MSG ();
1165                         OS.MoveMemory (keyMsg, lParam, MSG.sizeof);
1166                         OS.TranslateMessage (keyMsg);
1167                         OS.DispatchMessage (keyMsg);
1168                         long hHeap = OS.GetProcessHeap ();
1169                         OS.HeapFree (hHeap, 0, lParam);
1170                         break;
1171                 }
1172                 case SWT_DESTROY: {
1173                         OS.DestroyWindow (hwnd);
1174                         if (embeddedCallback != null) embeddedCallback.dispose ();
1175                         if (getMsgCallback != null) getMsgCallback.dispose ();
1176                         embeddedCallback = getMsgCallback = null;
1177                         embeddedProc = getMsgProc = 0;
1178                         break;
1179                 }
1180         }
1181         return OS.DefWindowProc (hwnd, (int)msg, wParam, lParam);
1182 }
1183
1184 /**
1185  * Does whatever display specific cleanup is required, and then
1186  * uses the code in <code>SWTError.error</code> to handle the error.
1187  *
1188  * @param code the descriptive error code
1189  *
1190  * @see SWT#error(int)
1191  */
1192 void error (int code) {
1193         SWT.error (code);
1194 }
1195
1196 boolean filterEvent (Event event) {
1197         if (filterTable != null) {
1198                 int type = event.type;
1199                 sendPreEvent (type);
1200                 try {
1201                         filterTable.sendEvent (event);
1202                 } finally {
1203                         sendPostEvent (type);
1204                 }
1205         }
1206         return false;
1207 }
1208
1209 boolean filters (int eventType) {
1210         if (filterTable == null) return false;
1211         return filterTable.hooks (eventType);
1212 }
1213
1214 boolean filterMessage (MSG msg) {
1215         int message = msg.message;
1216         if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) {
1217                 Control control = findControl (msg.hwnd);
1218                 if (control != null) {
1219                         if (translateAccelerator (msg, control) || translateMnemonic (msg, control) || translateTraversal (msg, control)) {
1220                                 lastAscii = lastKey = 0;
1221                                 lastVirtual = lastNull = lastDead = false;
1222                                 return true;
1223                         }
1224                 }
1225         }
1226         return false;
1227 }
1228
1229 Control findControl (long handle) {
1230         if (handle == 0) return null;
1231         long hwndOwner = 0;
1232         do {
1233                 Control control = getControl (handle);
1234                 if (control != null) return control;
1235                 hwndOwner = OS.GetWindow (handle, OS.GW_OWNER);
1236                 handle = OS.GetParent (handle);
1237         } while (handle != 0 && handle != hwndOwner);
1238         return null;
1239 }
1240
1241 /**
1242  * Given the operating system handle for a widget, returns
1243  * the instance of the <code>Widget</code> subclass which
1244  * represents it in the currently running application, if
1245  * such exists, or null if no matching widget can be found.
1246  * <p>
1247  * <b>IMPORTANT:</b> This method should not be called from
1248  * application code. The arguments are platform-specific.
1249  * </p>
1250  *
1251  * @param handle the handle for the widget
1252  * @return the SWT widget that the handle represents
1253  *
1254  * @exception SWTException <ul>
1255  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1256  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1257  * </ul>
1258  *
1259  * @noreference This method is not intended to be referenced by clients.
1260  */
1261 public Widget findWidget (long handle) {
1262         checkDevice ();
1263         return getControl (handle);
1264 }
1265
1266 /**
1267  * Given the operating system handle for a widget,
1268  * and widget-specific id, returns the instance of
1269  * the <code>Widget</code> subclass which represents
1270  * the handle/id pair in the currently running application,
1271  * if such exists, or null if no matching widget can be found.
1272  * <p>
1273  * <b>IMPORTANT:</b> This method should not be called from
1274  * application code. The arguments are platform-specific.
1275  * </p>
1276  *
1277  * @param handle the handle for the widget
1278  * @param id the id for the subwidget (usually an item)
1279  * @return the SWT widget that the handle/id pair represents
1280  *
1281  * @exception SWTException <ul>
1282  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1283  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1284  * </ul>
1285  *
1286  * @noreference This method is not intended to be referenced by clients.
1287  *
1288  * @since 3.1
1289  */
1290 public Widget findWidget (long handle, long id) {
1291         checkDevice ();
1292         Control control = getControl (handle);
1293         return control != null ? control.findItem (id) : null;
1294 }
1295
1296 /**
1297  * Given a widget and a widget-specific id, returns the
1298  * instance of the <code>Widget</code> subclass which represents
1299  * the widget/id pair in the currently running application,
1300  * if such exists, or null if no matching widget can be found.
1301  *
1302  * @param widget the widget
1303  * @param id the id for the subwidget (usually an item)
1304  * @return the SWT subwidget (usually an item) that the widget/id pair represents
1305  *
1306  * @exception SWTException <ul>
1307  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1308  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1309  * </ul>
1310  *
1311  * @noreference This method is not intended to be referenced by clients.
1312  *
1313  * @since 3.3
1314  */
1315 public Widget findWidget (Widget widget, long id) {
1316         checkDevice ();
1317         if (widget instanceof Control) {
1318                 return findWidget (((Control) widget).handle, id);
1319         }
1320         return null;
1321 }
1322
1323 long foregroundIdleProc (long code, long wParam, long lParam) {
1324         if (code >= 0) {
1325                 if (getMessageCount () != 0) {
1326                         sendPostExternalEventDispatchEvent ();
1327                         if (runMessagesInIdle) {
1328                                 if (runMessagesInMessageProc) {
1329                                         OS.PostMessage (hwndMessage, SWT_RUNASYNC, 0, 0);
1330                                 } else {
1331                                         runAsyncMessages (false);
1332                                 }
1333                         }
1334                         /*
1335                         * Bug in Windows.  For some reason, input events can be lost
1336                         * when a message is posted to the queue from a foreground idle
1337                         * hook.  The fix is to detect that there are outstanding input
1338                         * events and avoid posting the wake event.
1339                         *
1340                         * Note that PeekMessage() changes the state of events on the
1341                         * queue to no longer be considered new. If we peek for input
1342                         * events and posted messages (PM_QS_INPUT | PM_QS_POSTMESSAGE),
1343                         * it is possible to cause WaitMessage() to sleep until a new
1344                         * input event is generated causing sync runnables not to be
1345                         * executed.
1346                         */
1347                         MSG msg = new MSG();
1348                         int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT;
1349                         if (!OS.PeekMessage (msg, 0, 0, 0, flags)) wakeThread ();
1350                         sendPreExternalEventDispatchEvent ();
1351                 }
1352         }
1353         return OS.CallNextHookEx (idleHook, (int)code, wParam, lParam);
1354 }
1355
1356 /**
1357  * Returns the display which the given thread is the
1358  * user-interface thread for, or null if the given thread
1359  * is not a user-interface thread for any display.  Specifying
1360  * <code>null</code> as the thread will return <code>null</code>
1361  * for the display.
1362  *
1363  * @param thread the user-interface thread
1364  * @return the display for the given thread
1365  */
1366 public static Display findDisplay (Thread thread) {
1367         synchronized (Device.class) {
1368                 for (int i=0; i<Displays.length; i++) {
1369                         Display display = Displays [i];
1370                         if (display != null && display.thread == thread) {
1371                                 return display;
1372                         }
1373                 }
1374                 return null;
1375         }
1376 }
1377
1378 TouchSource findTouchSource (long touchDevice, Monitor monitor) {
1379         if (touchSources == null) touchSources = new TouchSource [4];
1380         int length = touchSources.length;
1381         for (int i=0; i<length; i++) {
1382                 if (touchSources [i] != null && touchSources [i].handle == touchDevice) {
1383                         return touchSources [i];
1384                 }
1385         }
1386         int index = 0;
1387         while (index < length) {
1388                 if (touchSources [index] == null) break;
1389                 index++;
1390         }
1391         if (index == length) {
1392                 TouchSource [] newTouchSources = new TouchSource [length + 4];
1393                 System.arraycopy (touchSources, 0, newTouchSources, 0, length);
1394                 touchSources = newTouchSources;
1395         }
1396         return touchSources [index] = new TouchSource (touchDevice, true, monitor.getBounds ());
1397 }
1398
1399 /**
1400  * Returns the currently active <code>Shell</code>, or null
1401  * if no shell belonging to the currently running application
1402  * is active.
1403  *
1404  * @return the active shell or null
1405  *
1406  * @exception SWTException <ul>
1407  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1408  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1409  * </ul>
1410  */
1411 public Shell getActiveShell () {
1412         checkDevice ();
1413         Control control = findControl (OS.GetActiveWindow ());
1414         return control != null ? control.getShell () : null;
1415 }
1416
1417 /**
1418  * Returns the single instance of the application menu bar, or
1419  * <code>null</code> if there is no application menu bar for the platform.
1420  *
1421  * @return the application menu bar, or <code>null</code>
1422  *
1423  * @exception SWTException <ul>
1424  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1425  * </ul>
1426  *
1427  * @since 3.7
1428  */
1429 public Menu getMenuBar () {
1430         checkDevice ();
1431         return null;
1432 }
1433
1434 /**
1435  * Returns a rectangle describing the receiver's size and location. Note that
1436  * on multi-monitor systems the origin can be negative.
1437  *
1438  * @return the bounding rectangle
1439  *
1440  * @exception SWTException <ul>
1441  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1442  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1443  * </ul>
1444  */
1445 @Override
1446 public Rectangle getBounds() {
1447         checkDevice ();
1448         return DPIUtil.autoScaleDown(getBoundsInPixels());
1449 }
1450
1451 Rectangle getBoundsInPixels () {
1452         checkDevice ();
1453         if (OS.GetSystemMetrics (OS.SM_CMONITORS) < 2) {
1454                 int width = OS.GetSystemMetrics (OS.SM_CXSCREEN);
1455                 int height = OS.GetSystemMetrics (OS.SM_CYSCREEN);
1456                 return new Rectangle (0, 0, width, height);
1457         }
1458         int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN);
1459         int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN);
1460         int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN);
1461         int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN);
1462         return new Rectangle (x, y, width, height);
1463 }
1464
1465 /**
1466  * Returns the display which the currently running thread is
1467  * the user-interface thread for, or null if the currently
1468  * running thread is not a user-interface thread for any display.
1469  *
1470  * @return the current display
1471  */
1472 public static Display getCurrent () {
1473         return findDisplay (Thread.currentThread ());
1474 }
1475
1476 int getClickCount (int type, int button, long hwnd, long lParam) {
1477         switch (type) {
1478                 case SWT.MouseDown:
1479                         int doubleClick = OS.GetDoubleClickTime ();
1480                         if (clickRect == null) clickRect = new RECT ();
1481                         int deltaTime = Math.abs (lastTime - getLastEventTime ());
1482                         POINT pt = new POINT ();
1483                         OS.POINTSTOPOINT (pt, lParam);
1484                         if (lastClickHwnd == hwnd && lastButton == button && (deltaTime <= doubleClick) && OS.PtInRect (clickRect, pt)) {
1485                                 clickCount++;
1486                         } else {
1487                                 clickCount = 1;
1488                         }
1489                         //FALL THROUGH
1490                 case SWT.MouseDoubleClick:
1491                         lastButton = button;
1492                         lastClickHwnd = hwnd;
1493                         lastTime = getLastEventTime ();
1494                         int xInset = OS.GetSystemMetrics (OS.SM_CXDOUBLECLK) / 2;
1495                         int yInset = OS.GetSystemMetrics (OS.SM_CYDOUBLECLK) / 2;
1496                         int x = OS.GET_X_LPARAM (lParam), y = OS.GET_Y_LPARAM (lParam);
1497                         OS.SetRect (clickRect, x - xInset, y - yInset, x + xInset, y + yInset);
1498                         //FALL THROUGH
1499                 case SWT.MouseUp:
1500                         return clickCount;
1501         }
1502         return 0;
1503 }
1504
1505 /**
1506  * Returns a rectangle which describes the area of the
1507  * receiver which is capable of displaying data.
1508  *
1509  * @return the client area
1510  *
1511  * @exception SWTException <ul>
1512  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1513  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1514  * </ul>
1515  *
1516  * @see #getBounds
1517  */
1518 @Override
1519 public Rectangle getClientArea () {
1520         checkDevice ();
1521         return DPIUtil.autoScaleDown(getClientAreaInPixels());
1522 }
1523
1524 Rectangle getClientAreaInPixels () {
1525         checkDevice ();
1526         if (OS.GetSystemMetrics (OS.SM_CMONITORS) < 2) {
1527                 RECT rect = new RECT ();
1528                 OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, rect, 0);
1529                 int width = rect.right - rect.left;
1530                 int height = rect.bottom - rect.top;
1531                 return new Rectangle (rect.left, rect.top, width, height);
1532         }
1533         int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN);
1534         int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN);
1535         int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN);
1536         int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN);
1537         return new Rectangle (x, y, width, height);
1538 }
1539
1540 Control getControl (long handle) {
1541         if (handle == 0) return null;
1542         if (lastControl != null && lastHwnd == handle) {
1543                 return lastControl;
1544         }
1545         if (lastGetControl != null && lastGetHwnd == handle) {
1546                 return lastGetControl;
1547         }
1548         int index = (int)OS.GetProp (handle, SWT_OBJECT_INDEX) - 1;
1549         if (0 <= index && index < controlTable.length) {
1550                 Control control = controlTable [index];
1551                 /*
1552                 * Because GWL_USERDATA can be used by native widgets that
1553                 * do not belong to SWT, it is possible that GWL_USERDATA
1554                 * could return an index that is in the range of the table,
1555                 * but was not put there by SWT.  Therefore, it is necessary
1556                 * to check the handle of the control that is in the table
1557                 * against the handle that provided the GWL_USERDATA.
1558                 */
1559                 if (control != null && control.checkHandle (handle)) {
1560                         lastGetHwnd = handle;
1561                         lastGetControl = control;
1562                         return control;
1563                 }
1564         }
1565         return null;
1566 }
1567
1568 /**
1569  * Returns the control which the on-screen pointer is currently
1570  * over top of, or null if it is not currently over one of the
1571  * controls built by the currently running application.
1572  *
1573  * @return the control under the cursor or <code>null</code>
1574  *
1575  * @exception SWTException <ul>
1576  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1577  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1578  * </ul>
1579  */
1580 public Control getCursorControl () {
1581         checkDevice ();
1582         POINT pt = new POINT ();
1583         if (!OS.GetCursorPos (pt)) return null;
1584         return findControl (OS.WindowFromPoint (pt));
1585 }
1586
1587 /**
1588  * Returns the location of the on-screen pointer relative
1589  * to the top left corner of the screen.
1590  *
1591  * @return the cursor location
1592  *
1593  * @exception SWTException <ul>
1594  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1595  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1596  * </ul>
1597  */
1598 public Point getCursorLocation () {
1599         checkDevice ();
1600         return DPIUtil.autoScaleDown(getCursorLocationInPixels());
1601 }
1602
1603 Point getCursorLocationInPixels () {
1604         POINT pt = new POINT ();
1605         OS.GetCursorPos (pt);
1606         return new Point (pt.x, pt.y);
1607 }
1608
1609 /**
1610  * Returns an array containing the recommended cursor sizes.
1611  *
1612  * @return the array of cursor sizes
1613  *
1614  * @exception SWTException <ul>
1615  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1616  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1617  * </ul>
1618  *
1619  * @since 3.0
1620  */
1621 public Point [] getCursorSizes () {
1622         checkDevice ();
1623         return new Point [] {
1624                 new Point (OS.GetSystemMetrics (OS.SM_CXCURSOR), OS.GetSystemMetrics (OS.SM_CYCURSOR))};
1625 }
1626
1627 /**
1628  * Returns the default display. One is created (making the
1629  * thread that invokes this method its user-interface thread)
1630  * if it did not already exist.
1631  *
1632  * @return the default display
1633  */
1634 public static Display getDefault () {
1635         synchronized (Device.class) {
1636                 if (Default == null) Default = new Display ();
1637                 return Default;
1638         }
1639 }
1640
1641 /**
1642  * @since 3.108
1643  */
1644 @Override
1645 protected int getDeviceZoom() {
1646         /*
1647          * Win8.1 and above we should pick zoom for the primary monitor which always
1648          * reflects the latest OS zoom value, for more details refer bug 537273.
1649          */
1650         if (OS.WIN32_VERSION >= OS.VERSION (6, 3)) {
1651                 return getPrimaryMonitor().getZoom();
1652         }
1653         /* Otherwise return Windows zoom level, as set during session login. */
1654         return super.getDeviceZoom();
1655 }
1656
1657 static boolean isValidClass (Class<?> clazz) {
1658         String name = clazz.getName ();
1659         int index = name.lastIndexOf ('.');
1660         return name.substring (0, index + 1).equals (PACKAGE_PREFIX);
1661 }
1662
1663 /**
1664  * Returns the application defined property of the receiver
1665  * with the specified name, or null if it has not been set.
1666  * <p>
1667  * Applications may have associated arbitrary objects with the
1668  * receiver in this fashion. If the objects stored in the
1669  * properties need to be notified when the display is disposed
1670  * of, it is the application's responsibility to provide a
1671  * <code>disposeExec()</code> handler which does so.
1672  * </p>
1673  *
1674  * @param key the name of the property
1675  * @return the value of the property or null if it has not been set
1676  *
1677  * @exception IllegalArgumentException <ul>
1678  *    <li>ERROR_NULL_ARGUMENT - if the key is null</li>
1679  * </ul>
1680  * @exception SWTException <ul>
1681  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1682  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1683  * </ul>
1684  *
1685  * @see #setData(String, Object)
1686  * @see #disposeExec(Runnable)
1687  */
1688 public Object getData (String key) {
1689         checkDevice ();
1690         if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
1691         if (key.equals (RUN_MESSAGES_IN_IDLE_KEY)) {
1692                 return runMessagesInIdle;
1693         }
1694         if (key.equals (RUN_MESSAGES_IN_MESSAGE_PROC_KEY)) {
1695                 return runMessagesInMessageProc;
1696         }
1697         if (key.equals (USE_OWNDC_KEY)) {
1698                 return useOwnDC;
1699         }
1700         if (key.equals (ACCEL_KEY_HIT)) {
1701                 return accelKeyHit;
1702         }
1703         if (keys == null) return null;
1704         for (int i=0; i<keys.length; i++) {
1705                 if (keys [i].equals (key)) return values [i];
1706         }
1707         return null;
1708 }
1709
1710 /**
1711  * Returns the application defined, display specific data
1712  * associated with the receiver, or null if it has not been
1713  * set. The <em>display specific data</em> is a single,
1714  * unnamed field that is stored with every display.
1715  * <p>
1716  * Applications may put arbitrary objects in this field. If
1717  * the object stored in the display specific data needs to
1718  * be notified when the display is disposed of, it is the
1719  * application's responsibility to provide a
1720  * <code>disposeExec()</code> handler which does so.
1721  * </p>
1722  *
1723  * @return the display specific data
1724  *
1725  * @exception SWTException <ul>
1726  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1727  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1728  * </ul>
1729  *
1730  * @see #setData(Object)
1731  * @see #disposeExec(Runnable)
1732  */
1733 public Object getData () {
1734         checkDevice ();
1735         return data;
1736 }
1737
1738 /**
1739  * Returns the button dismissal alignment, one of <code>LEFT</code> or <code>RIGHT</code>.
1740  * The button dismissal alignment is the ordering that should be used when positioning the
1741  * default dismissal button for a dialog.  For example, in a dialog that contains an OK and
1742  * CANCEL button, on platforms where the button dismissal alignment is <code>LEFT</code>, the
1743  * button ordering should be OK/CANCEL.  When button dismissal alignment is <code>RIGHT</code>,
1744  * the button ordering should be CANCEL/OK.
1745  *
1746  * @return the button dismissal order
1747  *
1748  * @exception SWTException <ul>
1749  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1750  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1751  * </ul>
1752  *
1753  * @since 2.1
1754  */
1755 public int getDismissalAlignment () {
1756         checkDevice ();
1757         return SWT.LEFT;
1758 }
1759
1760
1761 /**
1762  * Returns the longest duration, in milliseconds, between
1763  * two mouse button clicks that will be considered a
1764  * <em>double click</em> by the underlying operating system.
1765  *
1766  * @return the double click time
1767  *
1768  * @exception SWTException <ul>
1769  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1770  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1771  * </ul>
1772  */
1773 public int getDoubleClickTime () {
1774         checkDevice ();
1775         return OS.GetDoubleClickTime ();
1776 }
1777
1778 /**
1779  * Returns the control which currently has keyboard focus,
1780  * or null if keyboard events are not currently going to
1781  * any of the controls built by the currently running
1782  * application.
1783  *
1784  * @return the focus control or <code>null</code>
1785  *
1786  * @exception SWTException <ul>
1787  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1788  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1789  * </ul>
1790  */
1791 public Control getFocusControl () {
1792         checkDevice ();
1793         if (focusControl != null && !focusControl.isDisposed ()) {
1794                 return focusControl;
1795         }
1796         return _getFocusControl ();
1797 }
1798
1799 String getFontName (LOGFONT logFont) {
1800         char[] chars = logFont.lfFaceName;
1801         int index = 0;
1802         while (index < chars.length) {
1803                 if (chars [index] == 0) break;
1804                 index++;
1805         }
1806         return new String (chars, 0, index);
1807 }
1808
1809 /**
1810  * Returns true when the high contrast mode is enabled.
1811  * Otherwise, false is returned.
1812  * <p>
1813  * Note: This operation is a hint and is not supported on
1814  * platforms that do not have this concept.
1815  * </p>
1816  *
1817  * @return the high contrast mode
1818  *
1819  * @exception SWTException <ul>
1820  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1821  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1822  * </ul>
1823  *
1824  * @since 3.0
1825  */
1826 public boolean getHighContrast () {
1827         checkDevice ();
1828         HIGHCONTRAST pvParam = new HIGHCONTRAST ();
1829         pvParam.cbSize = HIGHCONTRAST.sizeof;
1830         OS.SystemParametersInfo (OS.SPI_GETHIGHCONTRAST, 0, pvParam, 0);
1831         return (pvParam.dwFlags & OS.HCF_HIGHCONTRASTON) != 0;
1832 }
1833
1834 /**
1835  * Returns the maximum allowed depth of icons on this display, in bits per pixel.
1836  * On some platforms, this may be different than the actual depth of the display.
1837  *
1838  * @return the maximum icon depth
1839  *
1840  * @exception SWTException <ul>
1841  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1842  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1843  * </ul>
1844  *
1845  * @see Device#getDepth
1846  */
1847 public int getIconDepth () {
1848         checkDevice ();
1849         if (getDepth () >= 24) return 32;
1850
1851         /* Use the character encoding for the default locale */
1852         TCHAR buffer1 = new TCHAR (0, "Control Panel\\Desktop\\WindowMetrics", true); //$NON-NLS-1$
1853
1854         long [] phkResult = new long [1];
1855         int result = OS.RegOpenKeyEx (OS.HKEY_CURRENT_USER, buffer1, 0, OS.KEY_READ, phkResult);
1856         if (result != 0) return 4;
1857         int depth = 4;
1858         int [] lpcbData = new int [1];
1859
1860         /* Use the character encoding for the default locale */
1861         TCHAR buffer2 = new TCHAR (0, "Shell Icon BPP", true); //$NON-NLS-1$
1862         result = OS.RegQueryValueEx (phkResult [0], buffer2, 0, null, (TCHAR) null, lpcbData);
1863         if (result == 0) {
1864                 TCHAR lpData = new TCHAR (0, lpcbData [0] / TCHAR.sizeof);
1865                 result = OS.RegQueryValueEx (phkResult [0], buffer2, 0, null, lpData, lpcbData);
1866                 if (result == 0) {
1867                         try {
1868                                 depth = Integer.parseInt (lpData.toString (0, lpData.strlen ()));
1869                         } catch (NumberFormatException e) {}
1870                 }
1871         }
1872         OS.RegCloseKey (phkResult [0]);
1873         return depth;
1874 }
1875
1876 /**
1877  * Returns an array containing the recommended icon sizes.
1878  *
1879  * @return the array of icon sizes
1880  *
1881  * @exception SWTException <ul>
1882  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1883  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1884  * </ul>
1885  *
1886  * @see Decorations#setImages(Image[])
1887  *
1888  * @since 3.0
1889  */
1890 public Point [] getIconSizes () {
1891         checkDevice ();
1892         return new Point [] {
1893                 new Point (OS.GetSystemMetrics (OS.SM_CXSMICON), OS.GetSystemMetrics (OS.SM_CYSMICON)),
1894                 new Point (OS.GetSystemMetrics (OS.SM_CXICON), OS.GetSystemMetrics (OS.SM_CYICON)),
1895         };
1896 }
1897
1898 ImageList getImageList (int style, int width, int height) {
1899         if (imageList == null) imageList = new ImageList [4];
1900
1901         int i = 0;
1902         int length = imageList.length;
1903         while (i < length) {
1904                 ImageList list = imageList [i];
1905                 if (list == null) break;
1906                 Point size = list.getImageSize();
1907                 if (size.x == width && size.y == height) {
1908                         if (list.getStyle () == style) {
1909                                 list.addRef();
1910                                 return list;
1911                         }
1912                 }
1913                 i++;
1914         }
1915
1916         if (i == length) {
1917                 ImageList [] newList = new ImageList [length + 4];
1918                 System.arraycopy (imageList, 0, newList, 0, length);
1919                 imageList = newList;
1920         }
1921
1922         ImageList list = new ImageList (style, width, height);
1923         imageList [i] = list;
1924         list.addRef();
1925         return list;
1926 }
1927
1928 ImageList getImageListToolBar (int style, int width, int height) {
1929         if (toolImageList == null) toolImageList = new ImageList [4];
1930
1931         int i = 0;
1932         int length = toolImageList.length;
1933         while (i < length) {
1934                 ImageList list = toolImageList [i];
1935                 if (list == null) break;
1936                 Point size = list.getImageSize();
1937                 if (size.x == width && size.y == height) {
1938                         if (list.getStyle () == style) {
1939                                 list.addRef();
1940                                 return list;
1941                         }
1942                 }
1943                 i++;
1944         }
1945
1946         if (i == length) {
1947                 ImageList [] newList = new ImageList [length + 4];
1948                 System.arraycopy (toolImageList, 0, newList, 0, length);
1949                 toolImageList = newList;
1950         }
1951
1952         ImageList list = new ImageList (style, width, height);
1953         toolImageList [i] = list;
1954         list.addRef();
1955         return list;
1956 }
1957
1958 ImageList getImageListToolBarDisabled (int style, int width, int height) {
1959         if (toolDisabledImageList == null) toolDisabledImageList = new ImageList [4];
1960
1961         int i = 0;
1962         int length = toolDisabledImageList.length;
1963         while (i < length) {
1964                 ImageList list = toolDisabledImageList [i];
1965                 if (list == null) break;
1966                 Point size = list.getImageSize();
1967                 if (size.x == width && size.y == height) {
1968                         if (list.getStyle () == style) {
1969                                 list.addRef();
1970                                 return list;
1971                         }
1972                 }
1973                 i++;
1974         }
1975
1976         if (i == length) {
1977                 ImageList [] newList = new ImageList [length + 4];
1978                 System.arraycopy (toolDisabledImageList, 0, newList, 0, length);
1979                 toolDisabledImageList = newList;
1980         }
1981
1982         ImageList list = new ImageList (style, width, height);
1983         toolDisabledImageList [i] = list;
1984         list.addRef();
1985         return list;
1986 }
1987
1988 ImageList getImageListToolBarHot (int style, int width, int height) {
1989         if (toolHotImageList == null) toolHotImageList = new ImageList [4];
1990
1991         int i = 0;
1992         int length = toolHotImageList.length;
1993         while (i < length) {
1994                 ImageList list = toolHotImageList [i];
1995                 if (list == null) break;
1996                 Point size = list.getImageSize();
1997                 if (size.x == width && size.y == height) {
1998                         if (list.getStyle () == style) {
1999                                 list.addRef();
2000                                 return list;
2001                         }
2002                 }
2003                 i++;
2004         }
2005
2006         if (i == length) {
2007                 ImageList [] newList = new ImageList [length + 4];
2008                 System.arraycopy (toolHotImageList, 0, newList, 0, length);
2009                 toolHotImageList = newList;
2010         }
2011
2012         ImageList list = new ImageList (style, width, height);
2013         toolHotImageList [i] = list;
2014         list.addRef();
2015         return list;
2016 }
2017
2018 /**
2019  * Returns <code>true</code> if the current OS theme has a dark appearance, else
2020  * returns <code>false</code>.
2021  * <p>
2022  * Note: This operation is a hint and is not supported on platforms that do not
2023  * have this concept.
2024  * </p>
2025  * <p>
2026  * Note: Windows 10 onwards users can separately configure the theme for OS and
2027  * Application level and this can be read from the Windows registry. Since the
2028  * application needs to honor the application level theme, this API reads the
2029  * Application level theme setting.
2030  * </p>
2031  *
2032  * @return <code>true</code> if the current OS theme has a dark appearance, else
2033  *         returns <code>false</code>.
2034  *
2035  * @since 3.112
2036  */
2037 public static boolean isSystemDarkTheme () {
2038         boolean isDarkTheme = false;
2039         /*
2040          * Win10 onwards we can read the Dark Theme from the OS registry.
2041          */
2042         if (OS.WIN32_VERSION >= OS.VERSION (10, 0)) {
2043                 try {
2044                         int result = OS.readRegistryDword(OS.HKEY_CURRENT_USER,
2045                                         "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme");
2046                         isDarkTheme = (result == 0);
2047                 } catch (Exception e) {
2048                         // Registry entry not found
2049                 }
2050         }
2051         return isDarkTheme;
2052 }
2053
2054 int getLastEventTime () {
2055         return OS.GetMessageTime ();
2056 }
2057
2058 MenuItem getMenuItem (int id) {
2059         if (items == null) return null;
2060         id = id - ID_START;
2061         if (0 <= id && id < items.length) return items [id];
2062         return null;
2063 }
2064
2065 int getMessageCount () {
2066         /*
2067          * On Windows10 (update 18272), an NPE is seen in below code which leads to a
2068          * possible crash, adding a null check for synchronizer instance. For more
2069          * details refer bug 540762
2070          */
2071         if (synchronizer != null) return synchronizer.getMessageCount ();
2072         return 0;
2073 }
2074
2075
2076 Shell getModalShell () {
2077         if (modalShells == null) return null;
2078         int index = modalShells.length;
2079         while (--index >= 0) {
2080                 Shell shell = modalShells [index];
2081                 if (shell != null) return shell;
2082         }
2083         return null;
2084 }
2085
2086 Dialog getModalDialog () {
2087         return modalDialog;
2088 }
2089
2090 Monitor getMonitor (long hmonitor) {
2091         MONITORINFO lpmi = new MONITORINFO ();
2092         lpmi.cbSize = MONITORINFO.sizeof;
2093         OS.GetMonitorInfo (hmonitor, lpmi);
2094         Monitor monitor = new Monitor ();
2095         monitor.handle = hmonitor;
2096         Rectangle boundsInPixels = new Rectangle (lpmi.rcMonitor_left, lpmi.rcMonitor_top, lpmi.rcMonitor_right - lpmi.rcMonitor_left,lpmi.rcMonitor_bottom - lpmi.rcMonitor_top);
2097         monitor.setBounds (DPIUtil.autoScaleDown (boundsInPixels));
2098         Rectangle clientAreaInPixels = new Rectangle (lpmi.rcWork_left, lpmi.rcWork_top, lpmi.rcWork_right - lpmi.rcWork_left, lpmi.rcWork_bottom - lpmi.rcWork_top);
2099         monitor.setClientArea (DPIUtil.autoScaleDown (clientAreaInPixels));
2100         if (OS.WIN32_VERSION >= OS.VERSION (6, 3)) {
2101                 int [] dpiX = new int[1];
2102                 int [] dpiY = new int[1];
2103                 int result = OS.GetDpiForMonitor (monitor.handle, OS.MDT_EFFECTIVE_DPI, dpiX, dpiY);
2104                 result = (result == OS.S_OK) ? DPIUtil.mapDPIToZoom (dpiX[0]) : 100;
2105                 /*
2106                  * Always return true monitor zoom value as fetched from native, else will lead
2107                  * to scaling issue on OS Win8.1 and above, for more details refer bug 537614.
2108                  */
2109                 monitor.zoom = result;
2110         } else {
2111                 monitor.zoom = getDeviceZoom ();
2112         }
2113         return monitor;
2114 }
2115
2116 /**
2117  * Returns an array of monitors attached to the device.
2118  *
2119  * @return the array of monitors
2120  *
2121  * @since 3.0
2122  */
2123 public Monitor [] getMonitors () {
2124         checkDevice ();
2125         monitors = new Monitor [4];
2126         Callback callback = new Callback (this, "monitorEnumProc", 4); //$NON-NLS-1$
2127         long lpfnEnum = callback.getAddress ();
2128         if (lpfnEnum == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
2129         OS.EnumDisplayMonitors (0, null, lpfnEnum, 0);
2130         callback.dispose ();
2131         Monitor [] result = new Monitor [monitorCount];
2132         System.arraycopy (monitors, 0, result, 0, monitorCount);
2133         monitors = null;
2134         monitorCount = 0;
2135         return result;
2136 }
2137
2138 long getMsgProc (long code, long wParam, long lParam) {
2139         if (embeddedHwnd == 0) {
2140                 long hInstance = OS.GetModuleHandle (null);
2141                 embeddedHwnd = OS.CreateWindowEx (0,
2142                         windowClass,
2143                         null,
2144                         OS.WS_OVERLAPPED,
2145                         0, 0, 0, 0,
2146                         0,
2147                         0,
2148                         hInstance,
2149                         null);
2150                 embeddedCallback = new Callback (this, "embeddedProc", 4); //$NON-NLS-1$
2151                 embeddedProc = embeddedCallback.getAddress ();
2152                 if (embeddedProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
2153                 OS.SetWindowLongPtr (embeddedHwnd, OS.GWLP_WNDPROC, embeddedProc);
2154         }
2155         if (code >= 0 && (wParam & OS.PM_REMOVE) != 0) {
2156                 MSG msg = new MSG ();
2157                 OS.MoveMemory (msg, lParam, MSG.sizeof);
2158                 switch (msg.message) {
2159                         case OS.WM_KEYDOWN:
2160                         case OS.WM_KEYUP:
2161                         case OS.WM_SYSKEYDOWN:
2162                         case OS.WM_SYSKEYUP: {
2163                                 Control control = findControl (msg.hwnd);
2164                                 if (control != null) {
2165                                         long hHeap = OS.GetProcessHeap ();
2166                                         long keyMsg = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, MSG.sizeof);
2167                                         OS.MoveMemory (keyMsg, msg, MSG.sizeof);
2168                                         OS.PostMessage (hwndMessage, SWT_KEYMSG, wParam, keyMsg);
2169                                         switch ((int)msg.wParam) {
2170                                                 case OS.VK_SHIFT:
2171                                                 case OS.VK_MENU:
2172                                                 case OS.VK_CONTROL:
2173                                                 case OS.VK_CAPITAL:
2174                                                 case OS.VK_NUMLOCK:
2175                                                 case OS.VK_SCROLL:
2176                                                         break;
2177                                                 default:
2178                                                         msg.message = OS.WM_NULL;
2179                                                         OS.MoveMemory (lParam, msg, MSG.sizeof);
2180                                         }
2181                                 }
2182                         }
2183                 }
2184         }
2185         return OS.CallNextHookEx (msgHook, (int)code, wParam, lParam);
2186 }
2187
2188 /**
2189  * Returns the primary monitor for that device.
2190  *
2191  * @return the primary monitor
2192  *
2193  * @since 3.0
2194  */
2195 public Monitor getPrimaryMonitor () {
2196         checkDevice ();
2197         long hmonitor = OS.MonitorFromWindow (0, OS.MONITOR_DEFAULTTOPRIMARY);
2198         return getMonitor (hmonitor);
2199 }
2200
2201 /**
2202  * Returns a (possibly empty) array containing all shells which have
2203  * not been disposed and have the receiver as their display.
2204  *
2205  * @return the receiver's shells
2206  *
2207  * @exception SWTException <ul>
2208  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2209  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2210  * </ul>
2211  */
2212 public Shell [] getShells () {
2213         checkDevice ();
2214         int index = 0;
2215         Shell [] result = new Shell [16];
2216         for (int i = 0; i < controlTable.length; i++) {
2217                 Control control = controlTable [i];
2218                 if (control != null && control instanceof Shell) {
2219                         int j = 0;
2220                         while (j < index) {
2221                                 if (result [j] == control) break;
2222                                 j++;
2223                         }
2224                         if (j == index) {
2225                                 if (index == result.length) {
2226                                         Shell [] newResult = new Shell [index + 16];
2227                                         System.arraycopy (result, 0, newResult, 0, index);
2228                                         result = newResult;
2229                                 }
2230                                 result [index++] = (Shell) control;
2231                         }
2232                 }
2233         }
2234         if (index == result.length) return result;
2235         Shell [] newResult = new Shell [index];
2236         System.arraycopy (result, 0, newResult, 0, index);
2237         return newResult;
2238 }
2239
2240 /**
2241  * Gets the synchronizer used by the display.
2242  *
2243  * @return the receiver's synchronizer
2244  *
2245  * @exception SWTException <ul>
2246  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2247  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2248  * </ul>
2249  *
2250  * @since 3.4
2251  */
2252 public Synchronizer getSynchronizer () {
2253         checkDevice ();
2254         return synchronizer;
2255 }
2256
2257 /**
2258  * Returns the thread that has invoked <code>syncExec</code>
2259  * or null if no such runnable is currently being invoked by
2260  * the user-interface thread.
2261  * <p>
2262  * Note: If a runnable invoked by asyncExec is currently
2263  * running, this method will return null.
2264  * </p>
2265  *
2266  * @return the receiver's sync-interface thread
2267  *
2268  * @exception SWTException <ul>
2269  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2270  * </ul>
2271  */
2272 public Thread getSyncThread () {
2273         synchronized (Device.class) {
2274                 if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2275                 return synchronizer.syncThread;
2276         }
2277 }
2278
2279 /**
2280  * Returns the matching standard color for the given
2281  * constant, which should be one of the color constants
2282  * specified in class <code>SWT</code>. Any value other
2283  * than one of the SWT color constants which is passed
2284  * in will result in the color black. This color should
2285  * not be free'd because it was allocated by the system,
2286  * not the application.
2287  *
2288  * @param id the color constant
2289  * @return the matching color
2290  *
2291  * @exception SWTException <ul>
2292  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2293  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2294  * </ul>
2295  *
2296  * @see SWT
2297  */
2298 @Override
2299 public Color getSystemColor (int id) {
2300         checkDevice ();
2301         int pixel = 0x00000000;
2302         switch (id) {
2303                 case SWT.COLOR_WIDGET_DARK_SHADOW:              pixel = OS.GetSysColor (OS.COLOR_3DDKSHADOW);   break;
2304                 case SWT.COLOR_WIDGET_DISABLED_FOREGROUND: pixel = OS.GetSysColor(OS.COLOR_GRAYTEXT); break;
2305                 case SWT.COLOR_WIDGET_NORMAL_SHADOW:    pixel = OS.GetSysColor (OS.COLOR_3DSHADOW);     break;
2306                 case SWT.COLOR_WIDGET_LIGHT_SHADOW:     pixel = OS.GetSysColor (OS.COLOR_3DLIGHT);      break;
2307                 case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW: pixel = OS.GetSysColor (OS.COLOR_3DHIGHLIGHT);  break;
2308                 case SWT.COLOR_TEXT_DISABLED_BACKGROUND:
2309                 case SWT.COLOR_WIDGET_BACKGROUND:               pixel = OS.GetSysColor (OS.COLOR_3DFACE);       break;
2310                 case SWT.COLOR_WIDGET_BORDER:           pixel = OS.GetSysColor (OS.COLOR_WINDOWFRAME);  break;
2311                 case SWT.COLOR_WIDGET_FOREGROUND:
2312                 case SWT.COLOR_LIST_FOREGROUND:                 pixel = OS.GetSysColor (OS.COLOR_WINDOWTEXT);   break;
2313                 case SWT.COLOR_LIST_BACKGROUND:                 pixel = OS.GetSysColor (OS.COLOR_WINDOW);       break;
2314                 case SWT.COLOR_LIST_SELECTION:          pixel = OS.GetSysColor (OS.COLOR_HIGHLIGHT);    break;
2315                 case SWT.COLOR_LIST_SELECTION_TEXT:     pixel = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);break;
2316                 case SWT.COLOR_LINK_FOREGROUND:         pixel = OS.GetSysColor (OS.COLOR_HOTLIGHT);break;
2317                 case SWT.COLOR_INFO_FOREGROUND:         pixel = OS.GetSysColor (OS.COLOR_INFOTEXT);     break;
2318                 case SWT.COLOR_INFO_BACKGROUND:         pixel = OS.GetSysColor (OS.COLOR_INFOBK);               break;
2319                 case SWT.COLOR_TITLE_FOREGROUND:                pixel = OS.GetSysColor (OS.COLOR_CAPTIONTEXT);  break;
2320                 case SWT.COLOR_TITLE_BACKGROUND:                pixel = OS.GetSysColor (OS.COLOR_ACTIVECAPTION);                break;
2321                 case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:
2322                         pixel = OS.GetSysColor (OS.COLOR_GRADIENTACTIVECAPTION);
2323                         if (pixel == 0) pixel = OS.GetSysColor (OS.COLOR_ACTIVECAPTION);
2324                         break;
2325                 case SWT.COLOR_TITLE_INACTIVE_FOREGROUND:               pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTIONTEXT);  break;
2326                 case SWT.COLOR_TITLE_INACTIVE_BACKGROUND:                       pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTION);              break;
2327                 case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:
2328                         pixel = OS.GetSysColor (OS.COLOR_GRADIENTINACTIVECAPTION);
2329                         if (pixel == 0) pixel = OS.GetSysColor (OS.COLOR_INACTIVECAPTION);
2330                         break;
2331                 default:
2332                         return super.getSystemColor (id);
2333         }
2334         return Color.win32_new (this, pixel);
2335 }
2336
2337 /**
2338  * Returns the matching standard platform cursor for the given
2339  * constant, which should be one of the cursor constants
2340  * specified in class <code>SWT</code>. This cursor should
2341  * not be free'd because it was allocated by the system,
2342  * not the application.  A value of <code>null</code> will
2343  * be returned if the supplied constant is not an SWT cursor
2344  * constant.
2345  *
2346  * @param id the SWT cursor constant
2347  * @return the corresponding cursor or <code>null</code>
2348  *
2349  * @exception SWTException <ul>
2350  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2351  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2352  * </ul>
2353  *
2354  * @see SWT#CURSOR_ARROW
2355  * @see SWT#CURSOR_WAIT
2356  * @see SWT#CURSOR_CROSS
2357  * @see SWT#CURSOR_APPSTARTING
2358  * @see SWT#CURSOR_HELP
2359  * @see SWT#CURSOR_SIZEALL
2360  * @see SWT#CURSOR_SIZENESW
2361  * @see SWT#CURSOR_SIZENS
2362  * @see SWT#CURSOR_SIZENWSE
2363  * @see SWT#CURSOR_SIZEWE
2364  * @see SWT#CURSOR_SIZEN
2365  * @see SWT#CURSOR_SIZES
2366  * @see SWT#CURSOR_SIZEE
2367  * @see SWT#CURSOR_SIZEW
2368  * @see SWT#CURSOR_SIZENE
2369  * @see SWT#CURSOR_SIZESE
2370  * @see SWT#CURSOR_SIZESW
2371  * @see SWT#CURSOR_SIZENW
2372  * @see SWT#CURSOR_UPARROW
2373  * @see SWT#CURSOR_IBEAM
2374  * @see SWT#CURSOR_NO
2375  * @see SWT#CURSOR_HAND
2376  *
2377  * @since 3.0
2378  */
2379 public Cursor getSystemCursor (int id) {
2380         checkDevice ();
2381         if (!(0 <= id && id < cursors.length)) return null;
2382         if (cursors [id] == null) {
2383                 cursors [id] = new Cursor (this, id);
2384         }
2385         return cursors [id];
2386 }
2387
2388 /**
2389  * Returns a reasonable font for applications to use.
2390  * On some platforms, this will match the "default font"
2391  * or "system font" if such can be found.  This font
2392  * should not be free'd because it was allocated by the
2393  * system, not the application.
2394  * <p>
2395  * Typically, applications which want the default look
2396  * should simply not set the font on the widgets they
2397  * create. Widgets are always created with the correct
2398  * default font for the class of user-interface component
2399  * they represent.
2400  * </p>
2401  *
2402  * @return a font
2403  *
2404  * @exception SWTException <ul>
2405  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2406  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2407  * </ul>
2408  */
2409 @Override
2410 public Font getSystemFont () {
2411         checkDevice ();
2412         if (systemFont != null) return systemFont;
2413         long hFont = 0;
2414         NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
2415         info.cbSize = NONCLIENTMETRICS.sizeof;
2416         if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
2417                 LOGFONT logFont = info.lfMessageFont;
2418                 hFont = OS.CreateFontIndirect (logFont);
2419                 lfSystemFont = hFont != 0 ? logFont : null;
2420         }
2421         if (hFont == 0) hFont = OS.GetStockObject (OS.DEFAULT_GUI_FONT);
2422         if (hFont == 0) hFont = OS.GetStockObject (OS.SYSTEM_FONT);
2423         return systemFont = Font.win32_new (this, hFont);
2424 }
2425
2426 /**
2427  * Returns the matching standard platform image for the given
2428  * constant, which should be one of the icon constants
2429  * specified in class <code>SWT</code>. This image should
2430  * not be free'd because it was allocated by the system,
2431  * not the application.  A value of <code>null</code> will
2432  * be returned either if the supplied constant is not an
2433  * SWT icon constant or if the platform does not define an
2434  * image that corresponds to the constant.
2435  *
2436  * @param id the SWT icon constant
2437  * @return the corresponding image or <code>null</code>
2438  *
2439  * @exception SWTException <ul>
2440  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2441  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2442  * </ul>
2443  *
2444  * @see SWT#ICON_ERROR
2445  * @see SWT#ICON_INFORMATION
2446  * @see SWT#ICON_QUESTION
2447  * @see SWT#ICON_WARNING
2448  * @see SWT#ICON_WORKING
2449  *
2450  * @since 3.0
2451  */
2452 public Image getSystemImage (int id) {
2453         checkDevice ();
2454         switch (id) {
2455                 case SWT.ICON_ERROR: {
2456                         if (errorImage != null) return errorImage;
2457                         long hIcon = OS.LoadImage (0, OS.OIC_HAND, OS.IMAGE_ICON, 0, 0, OS.LR_SHARED);
2458                         return errorImage = Image.win32_new (this, SWT.ICON, hIcon);
2459                 }
2460                 case SWT.ICON_WORKING:
2461                 case SWT.ICON_INFORMATION: {
2462                         if (infoImage != null) return infoImage;
2463                         long hIcon = OS.LoadImage (0, OS.OIC_INFORMATION, OS.IMAGE_ICON, 0, 0, OS.LR_SHARED);
2464                         return infoImage = Image.win32_new (this, SWT.ICON, hIcon);
2465                 }
2466                 case SWT.ICON_QUESTION: {
2467                         if (questionImage != null) return questionImage;
2468                         long hIcon = OS.LoadImage (0, OS.OIC_QUES, OS.IMAGE_ICON, 0, 0, OS.LR_SHARED);
2469                         return questionImage = Image.win32_new (this, SWT.ICON, hIcon);
2470                 }
2471                 case SWT.ICON_WARNING: {
2472                         if (warningIcon != null) return warningIcon;
2473                         long hIcon = OS.LoadImage (0, OS.OIC_BANG, OS.IMAGE_ICON, 0, 0, OS.LR_SHARED);
2474                         return warningIcon = Image.win32_new (this, SWT.ICON, hIcon);
2475                 }
2476         }
2477         return null;
2478 }
2479
2480 /**
2481  * Returns the single instance of the system-provided menu for the application, or
2482  * <code>null</code> on platforms where no menu is provided for the application.
2483  *
2484  * @return the system menu, or <code>null</code>
2485  *
2486  * @exception SWTException <ul>
2487  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2488  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2489  * </ul>
2490  *
2491  * @since 3.7
2492  */
2493 public Menu getSystemMenu () {
2494         checkDevice();
2495         return null;
2496 }
2497
2498 /**
2499  * Returns the single instance of the system taskBar or null
2500  * when there is no system taskBar available for the platform.
2501  *
2502  * @return the system taskBar or <code>null</code>
2503  *
2504  * @exception SWTException <ul>
2505  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2506  * </ul>
2507  *
2508  * @since 3.6
2509  */
2510 public TaskBar getSystemTaskBar () {
2511         checkDevice ();
2512         if (taskBar != null) return taskBar;
2513         if (OS.WIN32_VERSION >= OS.VERSION (6, 1)) {
2514                 taskBar = new TaskBar (this, SWT.NONE);
2515         }
2516         return taskBar;
2517 }
2518
2519 /**
2520  * Returns the single instance of the system tray or null
2521  * when there is no system tray available for the platform.
2522  *
2523  * @return the system tray or <code>null</code>
2524  *
2525  * @exception SWTException <ul>
2526  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2527  * </ul>
2528  *
2529  * @since 3.0
2530  */
2531 public Tray getSystemTray () {
2532         checkDevice ();
2533         if (tray == null) tray = new Tray (this, SWT.NONE);
2534         return tray;
2535 }
2536
2537 /**
2538  * Returns the user-interface thread for the receiver.
2539  *
2540  * @return the receiver's user-interface thread
2541  *
2542  * @exception SWTException <ul>
2543  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2544  * </ul>
2545  */
2546 public Thread getThread () {
2547         synchronized (Device.class) {
2548                 if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2549                 return thread;
2550         }
2551 }
2552
2553 /**
2554  * Returns a boolean indicating whether a touch-aware input device is
2555  * attached to the system and is ready for use.
2556  *
2557  * @return <code>true</code> if a touch-aware input device is detected, or <code>false</code> otherwise
2558  *
2559  * @exception SWTException <ul>
2560  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2561  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2562  * </ul>
2563  *
2564  * @since 3.7
2565  */
2566 public boolean getTouchEnabled () {
2567         checkDevice();
2568         int value = OS.GetSystemMetrics (OS.SM_DIGITIZER);
2569         return (value & (OS.NID_READY | OS.NID_MULTI_INPUT)) == (OS.NID_READY | OS.NID_MULTI_INPUT);
2570 }
2571
2572 long hButtonTheme () {
2573         if (hButtonTheme != 0) return hButtonTheme;
2574         return hButtonTheme = OS.OpenThemeData (hwndMessage, BUTTON);
2575 }
2576
2577 long hEditTheme () {
2578         if (hEditTheme != 0) return hEditTheme;
2579         return hEditTheme = OS.OpenThemeData (hwndMessage, EDIT);
2580 }
2581
2582 long hExplorerBarTheme () {
2583         if (hExplorerBarTheme != 0) return hExplorerBarTheme;
2584         return hExplorerBarTheme = OS.OpenThemeData (hwndMessage, EXPLORERBAR);
2585 }
2586
2587 long hScrollBarTheme () {
2588         if (hScrollBarTheme != 0) return hScrollBarTheme;
2589         return hScrollBarTheme = OS.OpenThemeData (hwndMessage, SCROLLBAR);
2590 }
2591
2592 long hTabTheme () {
2593         if (hTabTheme != 0) return hTabTheme;
2594         return hTabTheme = OS.OpenThemeData (hwndMessage, TAB);
2595 }
2596
2597 /**
2598  * Invokes platform specific functionality to allocate a new GC handle.
2599  * <p>
2600  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
2601  * API for <code>Display</code>. It is marked public only so that it
2602  * can be shared within the packages provided by SWT. It is not
2603  * available on all platforms, and should never be called from
2604  * application code.
2605  * </p>
2606  *
2607  * @param data the platform specific GC data
2608  * @return the platform specific GC handle
2609  *
2610  * @exception SWTException <ul>
2611  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2612  * </ul>
2613  * @exception SWTError <ul>
2614  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for gc creation</li>
2615  * </ul>
2616  *
2617  * @noreference This method is not intended to be referenced by clients.
2618  */
2619 @Override
2620 public long internal_new_GC (GCData data) {
2621         if (isDisposed()) error(SWT.ERROR_DEVICE_DISPOSED);
2622         long hDC = OS.GetDC (0);
2623         if (hDC == 0) error (SWT.ERROR_NO_HANDLES);
2624         if (data != null) {
2625                 int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
2626                 if ((data.style & mask) != 0) {
2627                         data.layout = (data.style & SWT.RIGHT_TO_LEFT) != 0 ? OS.LAYOUT_RTL : 0;
2628                 } else {
2629                         data.style |= SWT.LEFT_TO_RIGHT;
2630                 }
2631                 data.device = this;
2632                 data.font = getSystemFont ();
2633         }
2634         return hDC;
2635 }
2636
2637 /**
2638  * Initializes any internal resources needed by the
2639  * device.
2640  * <p>
2641  * This method is called after <code>create</code>.
2642  * </p>
2643  *
2644  * @see #create
2645  */
2646 @Override
2647 protected void init () {
2648         super.init ();
2649         DPIUtil.setDeviceZoom (getDeviceZoom ());
2650
2651         /* Set the application user model ID, if APP_NAME is non Default */
2652         char [] appName = null;
2653         if (APP_NAME != null && !"SWT".equalsIgnoreCase (APP_NAME)) {
2654                 if (OS.WIN32_VERSION >= OS.VERSION (6, 1)) {
2655                         int length = APP_NAME.length ();
2656                         appName = new char [length + 1];
2657                         APP_NAME.getChars (0, length, appName, 0);
2658                         long [] appID = new long [1];
2659                         if (OS.GetCurrentProcessExplicitAppUserModelID(appID) != 0) {
2660                                 OS.SetCurrentProcessExplicitAppUserModelID (appName);
2661                         }
2662                         if (appID[0] != 0) OS.CoTaskMemFree(appID[0]);
2663                 }
2664         }
2665
2666         /* Create the callbacks */
2667         windowCallback = new Callback (this, "windowProc", 4); //$NON-NLS-1$
2668         windowProc = windowCallback.getAddress ();
2669         if (windowProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
2670
2671         /* Remember the current thread id */
2672         threadId = OS.GetCurrentThreadId ();
2673
2674         /* Use the character encoding for the default locale */
2675         windowClass = new TCHAR (0, WindowName + WindowClassCount, true);
2676         windowShadowClass = new TCHAR (0, WindowShadowName + WindowClassCount, true);
2677         windowOwnDCClass = new TCHAR (0, WindowOwnDCName + WindowClassCount, true);
2678         WindowClassCount++;
2679
2680         /* Register the SWT window class */
2681         long hInstance = OS.GetModuleHandle (null);
2682         WNDCLASS lpWndClass = new WNDCLASS ();
2683         lpWndClass.hInstance = hInstance;
2684         lpWndClass.lpfnWndProc = windowProc;
2685         lpWndClass.style = OS.CS_DBLCLKS;
2686         lpWndClass.hCursor = OS.LoadCursor (0, OS.IDC_ARROW);
2687         lpWndClass.hIcon = OS.LoadIcon (0, OS.IDI_APPLICATION);
2688         OS.RegisterClass (windowClass, lpWndClass);
2689
2690         /* Register the SWT drop shadow window class */
2691         lpWndClass.style |= OS.CS_DROPSHADOW;
2692         OS.RegisterClass (windowShadowClass, lpWndClass);
2693
2694         /* Register the CS_OWNDC window class */
2695         lpWndClass.style |= OS.CS_OWNDC;
2696         OS.RegisterClass (windowOwnDCClass, lpWndClass);
2697
2698         /* Create the message only HWND */
2699         hwndMessage = OS.CreateWindowEx (0,
2700                 windowClass,
2701                 null,
2702                 OS.WS_OVERLAPPED,
2703                 0, 0, 0, 0,
2704                 0,
2705                 0,
2706                 hInstance,
2707                 null);
2708         String title = "SWT_Window_"+APP_NAME;
2709         OS.SetWindowText(hwndMessage, new TCHAR(0, title, true));
2710         messageCallback = new Callback (this, "messageProc", 4); //$NON-NLS-1$
2711         messageProc = messageCallback.getAddress ();
2712         if (messageProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
2713         OS.SetWindowLongPtr (hwndMessage, OS.GWLP_WNDPROC, messageProc);
2714
2715         /* Create the filter hook */
2716         msgFilterCallback = new Callback (this, "msgFilterProc", 3); //$NON-NLS-1$
2717         msgFilterProc = msgFilterCallback.getAddress ();
2718         if (msgFilterProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
2719         filterHook = OS.SetWindowsHookEx (OS.WH_MSGFILTER, msgFilterProc, 0, threadId);
2720
2721         /* Create the idle hook */
2722         foregroundIdleCallback = new Callback (this, "foregroundIdleProc", 3); //$NON-NLS-1$
2723         foregroundIdleProc = foregroundIdleCallback.getAddress ();
2724         if (foregroundIdleProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
2725         idleHook = OS.SetWindowsHookEx (OS.WH_FOREGROUNDIDLE, foregroundIdleProc, 0, threadId);
2726
2727         /* Register window messages */
2728         TASKBARCREATED = OS.RegisterWindowMessage (new TCHAR (0, "TaskbarCreated", true)); //$NON-NLS-1$
2729         TASKBARBUTTONCREATED = OS.RegisterWindowMessage (new TCHAR (0, "TaskbarButtonCreated", true)); //$NON-NLS-1$
2730         SWT_RESTORECARET = OS.RegisterWindowMessage (new TCHAR (0, "SWT_RESTORECARET", true)); //$NON-NLS-1$
2731         DI_GETDRAGIMAGE = OS.RegisterWindowMessage (new TCHAR (0, "ShellGetDragImage", true)); //$NON-NLS-1$
2732         SWT_OPENDOC = OS.RegisterWindowMessage(new TCHAR (0, "SWT_OPENDOC", true)); //$NON-NLS-1$
2733
2734         /* Initialize OLE */
2735         OS.OleInitialize (0);
2736
2737         if (appName != null) {
2738                 /* Delete any old jump list set for the ID */
2739                 long [] ppv = new long [1];
2740                 int hr = COM.CoCreateInstance (COM.CLSID_DestinationList, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_ICustomDestinationList, ppv);
2741                 if (hr == OS.S_OK) {
2742                         ICustomDestinationList pList = new ICustomDestinationList (ppv [0]);
2743                         pList.DeleteList (appName);
2744                         pList.Release ();
2745                 }
2746         }
2747
2748         /* Initialize buffered painting */
2749         OS.BufferedPaintInit ();
2750
2751         /* Initialize the Widget Table */
2752         indexTable = new int [GROW_SIZE];
2753         controlTable = new Control [GROW_SIZE];
2754         for (int i=0; i<GROW_SIZE-1; i++) indexTable [i] = i + 1;
2755         indexTable [GROW_SIZE - 1] = -1;
2756 }
2757
2758 /**
2759  * Invokes platform specific functionality to dispose a GC handle.
2760  * <p>
2761  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
2762  * API for <code>Display</code>. It is marked public only so that it
2763  * can be shared within the packages provided by SWT. It is not
2764  * available on all platforms, and should never be called from
2765  * application code.
2766  * </p>
2767  *
2768  * @param hDC the platform specific GC handle
2769  * @param data the platform specific GC data
2770  *
2771  * @noreference This method is not intended to be referenced by clients.
2772  */
2773 @Override
2774 public void internal_dispose_GC (long hDC, GCData data) {
2775         OS.ReleaseDC (0, hDC);
2776 }
2777
2778 boolean isXMouseActive () {
2779         /*
2780         * NOTE: X-Mouse is active when bit 1 of the UserPreferencesMask is set.
2781         */
2782         boolean xMouseActive = false;
2783         try {
2784                 int result = OS.readRegistryDword(OS.HKEY_CURRENT_USER, "Control Panel\\Desktop", "UserPreferencesMask");
2785                 xMouseActive = (result & 0x01) != 0;
2786         } catch (Exception e) {
2787                 // Registry entry not found
2788         }
2789         return xMouseActive;
2790 }
2791
2792 boolean isValidThread () {
2793         return thread == Thread.currentThread ();
2794 }
2795
2796 /**
2797  * Maps a point from one coordinate system to another.
2798  * When the control is null, coordinates are mapped to
2799  * the display.
2800  * <p>
2801  * NOTE: On right-to-left platforms where the coordinate
2802  * systems are mirrored, special care needs to be taken
2803  * when mapping coordinates from one control to another
2804  * to ensure the result is correctly mirrored.
2805  *
2806  * Mapping a point that is the origin of a rectangle and
2807  * then adding the width and height is not equivalent to
2808  * mapping the rectangle.  When one control is mirrored
2809  * and the other is not, adding the width and height to a
2810  * point that was mapped causes the rectangle to extend
2811  * in the wrong direction.  Mapping the entire rectangle
2812  * instead of just one point causes both the origin and
2813  * the corner of the rectangle to be mapped.
2814  * </p>
2815  *
2816  * @param from the source <code>Control</code> or <code>null</code>
2817  * @param to the destination <code>Control</code> or <code>null</code>
2818  * @param point to be mapped
2819  * @return point with mapped coordinates
2820  *
2821  * @exception IllegalArgumentException <ul>
2822  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
2823  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2824  * </ul>
2825  * @exception SWTException <ul>
2826  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2827  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2828  * </ul>
2829  *
2830  * @since 2.1.2
2831  */
2832 public Point map (Control from, Control to, Point point) {
2833         checkDevice ();
2834         if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
2835         point = DPIUtil.autoScaleUp(point);
2836         return DPIUtil.autoScaleDown(mapInPixels(from, to, point));
2837 }
2838
2839 Point mapInPixels (Control from, Control to, Point point) {
2840         return mapInPixels (from, to, point.x, point.y);
2841 }
2842
2843 /**
2844  * Maps a point from one coordinate system to another.
2845  * When the control is null, coordinates are mapped to
2846  * the display.
2847  * <p>
2848  * NOTE: On right-to-left platforms where the coordinate
2849  * systems are mirrored, special care needs to be taken
2850  * when mapping coordinates from one control to another
2851  * to ensure the result is correctly mirrored.
2852  *
2853  * Mapping a point that is the origin of a rectangle and
2854  * then adding the width and height is not equivalent to
2855  * mapping the rectangle.  When one control is mirrored
2856  * and the other is not, adding the width and height to a
2857  * point that was mapped causes the rectangle to extend
2858  * in the wrong direction.  Mapping the entire rectangle
2859  * instead of just one point causes both the origin and
2860  * the corner of the rectangle to be mapped.
2861  * </p>
2862  *
2863  * @param from the source <code>Control</code> or <code>null</code>
2864  * @param to the destination <code>Control</code> or <code>null</code>
2865  * @param x coordinates to be mapped
2866  * @param y coordinates to be mapped
2867  * @return point with mapped coordinates
2868  *
2869  * @exception IllegalArgumentException <ul>
2870  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2871  * </ul>
2872  * @exception SWTException <ul>
2873  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2874  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2875  * </ul>
2876  *
2877  * @since 2.1.2
2878  */
2879 public Point map (Control from, Control to, int x, int y) {
2880         checkDevice ();
2881         x = DPIUtil.autoScaleUp(x);
2882         y = DPIUtil.autoScaleUp(y);
2883         return DPIUtil.autoScaleDown(mapInPixels(from, to, x, y));
2884 }
2885
2886 Point mapInPixels (Control from, Control to, int x, int y) {
2887         if (from != null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2888         if (to != null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2889         if (from == to) return new Point (x, y);
2890         long hwndFrom = from != null ? from.handle : 0;
2891         long hwndTo = to != null ? to.handle : 0;
2892         POINT point = new POINT ();
2893         point.x = x;
2894         point.y = y;
2895         OS.MapWindowPoints (hwndFrom, hwndTo, point, 1);
2896         return new Point (point.x, point.y);
2897 }
2898
2899 /**
2900  * Maps a point from one coordinate system to another.
2901  * When the control is null, coordinates are mapped to
2902  * the display.
2903  * <p>
2904  * NOTE: On right-to-left platforms where the coordinate
2905  * systems are mirrored, special care needs to be taken
2906  * when mapping coordinates from one control to another
2907  * to ensure the result is correctly mirrored.
2908  *
2909  * Mapping a point that is the origin of a rectangle and
2910  * then adding the width and height is not equivalent to
2911  * mapping the rectangle.  When one control is mirrored
2912  * and the other is not, adding the width and height to a
2913  * point that was mapped causes the rectangle to extend
2914  * in the wrong direction.  Mapping the entire rectangle
2915  * instead of just one point causes both the origin and
2916  * the corner of the rectangle to be mapped.
2917  * </p>
2918  *
2919  * @param from the source <code>Control</code> or <code>null</code>
2920  * @param to the destination <code>Control</code> or <code>null</code>
2921  * @param rectangle to be mapped
2922  * @return rectangle with mapped coordinates
2923  *
2924  * @exception IllegalArgumentException <ul>
2925  *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
2926  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2927  * </ul>
2928  * @exception SWTException <ul>
2929  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2930  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2931  * </ul>
2932  *
2933  * @since 2.1.2
2934  */
2935 public Rectangle map (Control from, Control to, Rectangle rectangle) {
2936         checkDevice ();
2937         if (rectangle == null) error (SWT.ERROR_NULL_ARGUMENT);
2938         rectangle = DPIUtil.autoScaleUp(rectangle);
2939         return DPIUtil.autoScaleDown(mapInPixels(from, to, rectangle));
2940 }
2941
2942 Rectangle mapInPixels (Control from, Control to, Rectangle rectangle) {
2943         return mapInPixels (from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
2944 }
2945
2946 /**
2947  * Maps a point from one coordinate system to another.
2948  * When the control is null, coordinates are mapped to
2949  * the display.
2950  * <p>
2951  * NOTE: On right-to-left platforms where the coordinate
2952  * systems are mirrored, special care needs to be taken
2953  * when mapping coordinates from one control to another
2954  * to ensure the result is correctly mirrored.
2955  *
2956  * Mapping a point that is the origin of a rectangle and
2957  * then adding the width and height is not equivalent to
2958  * mapping the rectangle.  When one control is mirrored
2959  * and the other is not, adding the width and height to a
2960  * point that was mapped causes the rectangle to extend
2961  * in the wrong direction.  Mapping the entire rectangle
2962  * instead of just one point causes both the origin and
2963  * the corner of the rectangle to be mapped.
2964  * </p>
2965  *
2966  * @param from the source <code>Control</code> or <code>null</code>
2967  * @param to the destination <code>Control</code> or <code>null</code>
2968  * @param x coordinates to be mapped
2969  * @param y coordinates to be mapped
2970  * @param width coordinates to be mapped
2971  * @param height coordinates to be mapped
2972  * @return rectangle with mapped coordinates
2973  *
2974  * @exception IllegalArgumentException <ul>
2975  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2976  * </ul>
2977  * @exception SWTException <ul>
2978  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2979  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2980  * </ul>
2981  *
2982  * @since 2.1.2
2983  */
2984 public Rectangle map (Control from, Control to, int x, int y, int width, int height) {
2985         checkDevice ();
2986         x = DPIUtil.autoScaleUp(x);
2987         y = DPIUtil.autoScaleUp(y);
2988         width = DPIUtil.autoScaleUp(width);
2989         height = DPIUtil.autoScaleUp(height);
2990         return DPIUtil.autoScaleDown(mapInPixels(from, to, x, y, width, height));
2991 }
2992
2993 Rectangle mapInPixels (Control from, Control to, int x, int y, int width, int height) {
2994         if (from != null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2995         if (to != null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2996         if (from == to) return new Rectangle (x, y, width, height);
2997         long hwndFrom = from != null ? from.handle : 0;
2998         long hwndTo = to != null ? to.handle : 0;
2999         RECT rect = new RECT ();
3000         rect.left = x;
3001         rect.top  = y;
3002         rect.right = x + width;
3003         rect.bottom = y + height;
3004         OS.MapWindowPoints (hwndFrom, hwndTo, rect, 2);
3005         return new Rectangle (rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
3006 }
3007
3008 long messageProc (long hwnd, long msg, long wParam, long lParam) {
3009         switch ((int)msg) {
3010                 case SWT_RUNASYNC: {
3011                         if (runMessagesInIdle) runAsyncMessages (false);
3012                         break;
3013                 }
3014                 case SWT_KEYMSG: {
3015                         boolean consumed = false;
3016                         MSG keyMsg = new MSG ();
3017                         OS.MoveMemory (keyMsg, lParam, MSG.sizeof);
3018                         Control control = findControl (keyMsg.hwnd);
3019                         if (control != null) {
3020                                 /*
3021                                 * Feature in Windows.  When the user types an accent key such
3022                                 * as ^ in order to get an accented character on a German keyboard,
3023                                 * calling TranslateMessage(), ToUnicode() or ToAscii() consumes
3024                                 * the key.  This means that a subsequent call to TranslateMessage()
3025                                 * will see a regular key rather than the accented key.  The fix
3026                                 * is to use MapVirtualKey() and VkKeyScan () to detect an accent
3027                                 * and avoid calls to TranslateMessage().
3028                                 */
3029                                 boolean accentKey = false;
3030                                 switch (keyMsg.message) {
3031                                         case OS.WM_KEYDOWN:
3032                                         case OS.WM_SYSKEYDOWN: {
3033                                                 switch ((int)keyMsg.wParam) {
3034                                                         case OS.VK_SHIFT:
3035                                                         case OS.VK_MENU:
3036                                                         case OS.VK_CONTROL:
3037                                                         case OS.VK_CAPITAL:
3038                                                         case OS.VK_NUMLOCK:
3039                                                         case OS.VK_SCROLL:
3040                                                                 break;
3041                                                         default: {
3042                                                                 int mapKey = OS.MapVirtualKey ((int)keyMsg.wParam, 2);
3043                                                                 if (mapKey != 0) {
3044                                                                         accentKey = (mapKey & 0x80000000) != 0;
3045                                                                         if (!accentKey) {
3046                                                                                 for (int i=0; i<ACCENTS.length; i++) {
3047                                                                                         int value = OS.VkKeyScan (ACCENTS [i]);
3048                                                                                         if (value != -1 && (value & 0xFF) == keyMsg.wParam) {
3049                                                                                                 int state = value >> 8;
3050                                                                                                 if ((OS.GetKeyState (OS.VK_SHIFT) < 0) == ((state & 0x1) != 0) &&
3051                                                                                                         (OS.GetKeyState (OS.VK_CONTROL) < 0) == ((state & 0x2) != 0) &&
3052                                                                                                         (OS.GetKeyState (OS.VK_MENU) < 0) == ((state & 0x4) != 0)) {
3053                                                                                                                 if ((state & 0x7) != 0) accentKey = true;
3054                                                                                                                 break;
3055                                                                                                 }
3056                                                                                         }
3057                                                                                 }
3058                                                                         }
3059                                                                 }
3060                                                                 break;
3061                                                         }
3062                                                 }
3063                                                 break;
3064                                         }
3065                                 }
3066                                 if (!accentKey && !ignoreNextKey) {
3067                                         keyMsg.hwnd = control.handle;
3068                                         int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
3069                                         do {
3070                                                 if (!(consumed |= filterMessage (keyMsg))) {
3071                                                         OS.TranslateMessage (keyMsg);
3072                                                         consumed |= OS.DispatchMessage (keyMsg) == 1;
3073                                                 }
3074                                         } while (OS.PeekMessage (keyMsg, keyMsg.hwnd, OS.WM_KEYFIRST, OS.WM_KEYLAST, flags));
3075                                 }
3076                                 switch (keyMsg.message) {
3077                                         case OS.WM_KEYDOWN:
3078                                         case OS.WM_SYSKEYDOWN: {
3079                                                 switch ((int)keyMsg.wParam) {
3080                                                         case OS.VK_SHIFT:
3081                                                         case OS.VK_MENU:
3082                                                         case OS.VK_CONTROL:
3083                                                         case OS.VK_CAPITAL:
3084                                                         case OS.VK_NUMLOCK:
3085                                                         case OS.VK_SCROLL:
3086                                                                 break;
3087                                                         default: {
3088                                                                 ignoreNextKey = accentKey;
3089                                                                 break;
3090                                                         }
3091                                                 }
3092                                         }
3093                                 }
3094                         }
3095                         switch ((int)keyMsg.wParam) {
3096                                 case OS.VK_SHIFT:
3097                                 case OS.VK_MENU:
3098                                 case OS.VK_CONTROL:
3099                                 case OS.VK_CAPITAL:
3100                                 case OS.VK_NUMLOCK:
3101                                 case OS.VK_SCROLL:
3102                                         consumed = true;
3103                         }
3104                         if (consumed) {
3105                                 long hHeap = OS.GetProcessHeap ();
3106                                 OS.HeapFree (hHeap, 0, lParam);
3107                         } else {
3108                                 OS.PostMessage (embeddedHwnd, SWT_KEYMSG, wParam, lParam);
3109                         }
3110                         return 0;
3111                 }
3112                 case SWT_TRAYICONMSG: {
3113                         if (tray != null) {
3114                                 TrayItem [] items = tray.items;
3115                                 for (int i=0; i<items.length; i++) {
3116                                         TrayItem item = items [i];
3117                                         if (item != null && item.id == wParam) {
3118                                                 return item.messageProc (hwnd, (int)msg, wParam, lParam);
3119                                         }
3120                                 }
3121                         }
3122                         return 0;
3123                 }
3124                 case OS.WM_ACTIVATEAPP: {
3125                         /*
3126                         * Feature in Windows.  When multiple shells are
3127                         * disabled and one of the shells has an enabled
3128                         * dialog child and the user selects a disabled
3129                         * shell that does not have the enabled dialog
3130                         * child using the Task bar, Windows brings the
3131                         * disabled shell to the front.  As soon as the
3132                         * user clicks on the disabled shell, the enabled
3133                         * dialog child comes to the front.  This behavior
3134                         * is unspecified and seems strange.  Normally, a
3135                         * disabled shell is frozen on the screen and the
3136                         * user cannot change the z-order by clicking with
3137                         * the mouse.  The fix is to look for WM_ACTIVATEAPP
3138                         * and force the enabled dialog child to the front.
3139                         * This is typically what the user is expecting.
3140                         *
3141                         * NOTE: If the modal shell is disabled for any
3142                         * reason, it should not be brought to the front.
3143                         */
3144                         if (wParam != 0) {
3145                                 if (!isXMouseActive ()) {
3146                                         long hwndActive = OS.GetActiveWindow ();
3147                                         if (hwndActive != 0 && OS.IsWindowEnabled (hwndActive)) break;
3148                                         Shell modal = modalDialog != null ? modalDialog.parent : getModalShell ();
3149                                         if (modal != null && !modal.isDisposed ()) {
3150                                                 long hwndModal = modal.handle;
3151                                                 if (OS.IsWindowEnabled (hwndModal)) {
3152                                                         modal.bringToTop ();
3153                                                         if (modal.isDisposed ()) break;
3154                                                 }
3155                                                 long hwndPopup = OS.GetLastActivePopup (hwndModal);
3156                                                 if (hwndPopup != 0 && hwndPopup != modal.handle) {
3157                                                         if (getControl (hwndPopup) == null) {
3158                                                                 if (OS.IsWindowEnabled (hwndPopup)) {
3159                                                                         OS.SetActiveWindow (hwndPopup);
3160                                                                 }
3161                                                         }
3162                                                 }
3163                                         }
3164                                 }
3165                         }
3166                         break;
3167                 }
3168                 case OS.WM_ENDSESSION: {
3169                         if (wParam != 0) {
3170                                 dispose ();
3171                                 /*
3172                                 * When the session is ending, no SWT program can continue
3173                                 * to run.  In order to avoid running code after the display
3174                                 * has been disposed, exit from Java.
3175                                 */
3176                                 /* This code is intentionally commented */
3177 //                              System.exit (0);
3178                         }
3179                         break;
3180                 }
3181                 case OS.WM_QUERYENDSESSION: {
3182                         Event event = new Event ();
3183                         sendEvent (SWT.Close, event);
3184                         if (!event.doit) return 0;
3185                         break;
3186                 }
3187                 case OS.WM_DWMCOLORIZATIONCOLORCHANGED:
3188                 case OS.WM_SETTINGCHANGE: {
3189                         /* Set the initial timer or push the time out period forward */
3190                         OS.SetTimer (hwndMessage, SETTINGS_ID, SETTINGS_DELAY, 0);
3191                         break;
3192                 }
3193                 case OS.WM_THEMECHANGED: {
3194                         if (hButtonTheme != 0) OS.CloseThemeData (hButtonTheme);
3195                         if (hEditTheme != 0) OS.CloseThemeData (hEditTheme);
3196                         if (hExplorerBarTheme != 0) OS.CloseThemeData (hExplorerBarTheme);
3197                         if (hScrollBarTheme != 0) OS.CloseThemeData (hScrollBarTheme);
3198                         if (hTabTheme != 0) OS.CloseThemeData (hTabTheme);
3199                         hButtonTheme = hEditTheme = hExplorerBarTheme = hScrollBarTheme = hTabTheme = 0;
3200                         break;
3201                 }
3202                 case OS.WM_TIMER: {
3203                         if (wParam == SETTINGS_ID) {
3204                                 OS.KillTimer (hwndMessage, SETTINGS_ID);
3205                                 runSettings ();
3206                         } else {
3207                                 runTimer (wParam);
3208                         }
3209                         break;
3210                 }
3211                 default: {
3212                         if ((int)msg == TASKBARCREATED) {
3213                                 if (tray != null) {
3214                                         TrayItem [] items = tray.items;
3215                                         for (int i=0; i<items.length; i++) {
3216                                                 TrayItem item = items [i];
3217                                                 if (item != null) item.recreate ();
3218                                         }
3219                                 }
3220                         }
3221                         if ((int)msg == SWT_OPENDOC) {
3222                                 String filename = getSharedData((int)wParam, (int)lParam);
3223                                 if (filename != null) {
3224                                         if (filename.startsWith (TASKBAR_EVENT)) {
3225                                                 String text = filename.substring (TASKBAR_EVENT.length ());
3226                                                 int id = Integer.parseInt (text);
3227                                                 MenuItem item = getMenuItem (id);
3228                                                 if (item != null) {
3229                                                         item.sendSelectionEvent (SWT.Selection);
3230                                                 }
3231                                         } else {
3232                                                 Event event = new Event ();
3233                                                 event.text = filename;
3234                                                 try {
3235                                                         new URI (filename);
3236                                                         sendEvent (SWT.OpenUrl, event);
3237                                                 } catch (URISyntaxException e) {
3238                                                         sendEvent (SWT.OpenDocument, event);
3239                                                 }
3240                                         }
3241                                         wakeThread ();
3242                                 }
3243                         }
3244                 }
3245         }
3246         return OS.DefWindowProc (hwnd, (int)msg, wParam, lParam);
3247 }
3248
3249 String getSharedData(int pid, int  handle) {
3250         long [] mapHandle = new long [1];
3251         if (pid == OS.GetCurrentProcessId()) {
3252                 mapHandle[0] = handle;
3253         } else {
3254                 long processHandle = OS.OpenProcess(OS.PROCESS_VM_READ|OS.PROCESS_DUP_HANDLE, false, pid);
3255                 if (processHandle == 0) return null;
3256                 OS.DuplicateHandle(processHandle, handle, OS.GetCurrentProcess(), mapHandle, OS.DUPLICATE_SAME_ACCESS, false, OS.DUPLICATE_SAME_ACCESS);
3257                 OS.CloseHandle(processHandle);
3258         }
3259
3260         long sharedData = OS.MapViewOfFile(mapHandle[0], OS.FILE_MAP_READ, 0, 0, 0);
3261         if (sharedData == 0) return null;
3262         int length = OS.wcslen (sharedData);
3263         TCHAR buffer = new TCHAR (0, length);
3264         int byteCount = buffer.length () * TCHAR.sizeof;
3265         OS.MoveMemory (buffer, sharedData, byteCount);
3266         String result = buffer.toString (0, length);
3267         OS.UnmapViewOfFile(sharedData);
3268         if (handle != mapHandle[0]) {
3269                 OS.CloseHandle(mapHandle[0]);
3270         }
3271         return result;
3272 }
3273
3274 long monitorEnumProc (long hmonitor, long hdc, long lprcMonitor, long dwData) {
3275         if (monitorCount >= monitors.length) {
3276                 Monitor[] newMonitors = new Monitor [monitors.length + 4];
3277                 System.arraycopy (monitors, 0, newMonitors, 0, monitors.length);
3278                 monitors = newMonitors;
3279         }
3280         monitors [monitorCount++] = getMonitor (hmonitor);
3281         return 1;
3282 }
3283
3284 long msgFilterProc (long code, long wParam, long lParam) {
3285         switch ((int)code) {
3286                 case OS.MSGF_COMMCTRL_BEGINDRAG: {
3287                         if (!runDragDrop && !dragCancelled) {
3288                                 OS.MoveMemory (hookMsg, lParam, MSG.sizeof);
3289                                 if (hookMsg.message == OS.WM_MOUSEMOVE) {
3290                                         dragCancelled = true;
3291                                         OS.SendMessage (hookMsg.hwnd, OS.WM_CANCELMODE, 0, 0);
3292                                 }
3293                         }
3294                         break;
3295                 }
3296                 /*
3297                 * Feature in Windows.  For some reason, when the user clicks
3298                 * a table or tree, the Windows hook WH_MSGFILTER is sent when
3299                 * an input event from a dialog box, message box, menu, or scroll
3300                 * bar did not occur, causing async messages to run at the wrong
3301                 * time.  The fix is to check the message filter code.
3302                 */
3303                 case OS.MSGF_DIALOGBOX:
3304                 case OS.MSGF_MAINLOOP:
3305                 case OS.MSGF_MENU:
3306                 case OS.MSGF_MOVE:
3307                 case OS.MSGF_MESSAGEBOX:
3308                 case OS.MSGF_NEXTWINDOW:
3309                 case OS.MSGF_SCROLLBAR:
3310                 case OS.MSGF_SIZE: {
3311                         OS.MoveMemory (hookMsg, lParam, MSG.sizeof);
3312                         if (hookMsg.message == OS.WM_NULL) {
3313                                 MSG msg = new MSG ();
3314                                 int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
3315                                 if (!OS.PeekMessage (msg, 0, 0, 0, flags)) {
3316                                         if (runAsyncMessages (false)) wakeThread ();
3317                                 }
3318                         }
3319                         break;
3320                 }
3321         }
3322         return OS.CallNextHookEx (filterHook, (int)code, wParam, lParam);
3323 }
3324
3325 int numpadKey (int key) {
3326         switch (key) {
3327                 case OS.VK_NUMPAD0:     return '0';
3328                 case OS.VK_NUMPAD1:     return '1';
3329                 case OS.VK_NUMPAD2:     return '2';
3330                 case OS.VK_NUMPAD3:     return '3';
3331                 case OS.VK_NUMPAD4:     return '4';
3332                 case OS.VK_NUMPAD5:     return '5';
3333                 case OS.VK_NUMPAD6:     return '6';
3334                 case OS.VK_NUMPAD7:     return '7';
3335                 case OS.VK_NUMPAD8:     return '8';
3336                 case OS.VK_NUMPAD9:     return '9';
3337                 case OS.VK_MULTIPLY:    return '*';
3338                 case OS.VK_ADD:                 return '+';
3339                 case OS.VK_SEPARATOR:   return '\0';
3340                 case OS.VK_SUBTRACT:    return '-';
3341                 case OS.VK_DECIMAL:     return '.';
3342                 case OS.VK_DIVIDE:              return '/';
3343         }
3344         return 0;
3345 }
3346
3347 /**
3348  * Generate a low level system event.
3349  *
3350  * <code>post</code> is used to generate low level keyboard
3351  * and mouse events. The intent is to enable automated UI
3352  * testing by simulating the input from the user.  Most
3353  * SWT applications should never need to call this method.
3354  * <p>
3355  * Note that this operation can fail when the operating system
3356  * fails to generate the event for any reason.  For example,
3357  * this can happen when there is no such key or mouse button
3358  * or when the system event queue is full.
3359  * </p>
3360  * <p>
3361  * <b>Event Types:</b>
3362  * <p>KeyDown, KeyUp
3363  * <p>The following fields in the <code>Event</code> apply:
3364  * <ul>
3365  * <li>(in) type KeyDown or KeyUp</li></ul>
3366  * <p> Either one of:</p>
3367  * <ul><li>(in) character a character that corresponds to a keyboard key</li>
3368  * <li>(in) keyCode the key code of the key that was typed,
3369  *          as defined by the key code constants in class <code>SWT</code></li></ul>
3370  * <p> Optional (on some platforms): </p>
3371  * <ul><li>(in) stateMask the state of the keyboard modifier,
3372  *                      as defined by the key code constants in class <code>SWT</code>
3373  * </li>
3374  * </ul>
3375  * <p>MouseDown, MouseUp</p>
3376  * <p>The following fields in the <code>Event</code> apply:
3377  * <ul>
3378  * <li>(in) type MouseDown or MouseUp
3379  * <li>(in) button the button that is pressed or released
3380  * </ul>
3381  * <p>MouseMove</p>
3382  * <p>The following fields in the <code>Event</code> apply:
3383  * <ul>
3384  * <li>(in) type MouseMove</li>
3385  * <li>(in) x the x coordinate to move the mouse pointer to in screen coordinates</li>
3386  * <li>(in) y the y coordinate to move the mouse pointer to in screen coordinates</li>
3387  * </ul>
3388  * <p>MouseWheel</p>
3389  * <p>The following fields in the <code>Event</code> apply:</p>
3390  * <ul>
3391  * <li>(in) type MouseWheel</li>
3392  * <li>(in) detail either SWT.SCROLL_LINE or SWT.SCROLL_PAGE</li>
3393  * <li>(in) count the number of lines or pages to scroll</li>
3394  * </ul>
3395  *
3396  * @param event the event to be generated
3397  *
3398  * @return true if the event was generated or false otherwise
3399  *
3400  * @exception IllegalArgumentException <ul>
3401  *    <li>ERROR_NULL_ARGUMENT - if the event is null</li>
3402  * </ul>
3403  * @exception SWTException <ul>
3404  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3405  * </ul>
3406  *
3407  * @since 3.0
3408  *
3409  */
3410 public boolean post (Event event) {
3411         synchronized (Device.class) {
3412                 if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
3413                 if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
3414                 int type = event.type;
3415                 switch (type){
3416                         case SWT.KeyDown:
3417                         case SWT.KeyUp: {
3418                                 KEYBDINPUT inputs = new KEYBDINPUT ();
3419                                 inputs.wVk = (short) untranslateKey (event.keyCode);
3420                                 if (inputs.wVk == 0) {
3421                                         char key = event.character;
3422                                         switch (key) {
3423                                                 case SWT.BS: inputs.wVk = (short) OS.VK_BACK; break;
3424                                                 case SWT.CR: inputs.wVk = (short) OS.VK_RETURN; break;
3425                                                 case SWT.DEL: inputs.wVk = (short) OS.VK_DELETE; break;
3426                                                 case SWT.ESC: inputs.wVk = (short) OS.VK_ESCAPE; break;
3427                                                 case SWT.TAB: inputs.wVk = (short) OS.VK_TAB; break;
3428                                                 /*
3429                                                 * Since there is no LF key on the keyboard, do not attempt
3430                                                 * to map LF to CR or attempt to post an LF key.
3431                                                 */
3432 //                                              case SWT.LF: inputs.wVk = (short) OS.VK_RETURN; break;
3433                                                 case SWT.LF: return false;
3434                                                 default: {
3435                                                         inputs.wVk = OS.VkKeyScan ((short) key);
3436                                                         if (inputs.wVk == -1) return false;
3437                                                         inputs.wVk &= 0xFF;
3438                                                 }
3439                                         }
3440                                 }
3441                                 inputs.dwFlags = type == SWT.KeyUp ? OS.KEYEVENTF_KEYUP : 0;
3442                                 switch (inputs.wVk) {
3443                                         case OS.VK_INSERT:
3444                                         case OS.VK_DELETE:
3445                                         case OS.VK_HOME:
3446                                         case OS.VK_END:
3447                                         case OS.VK_PRIOR:
3448                                         case OS.VK_NEXT:
3449                                         case OS.VK_UP:
3450                                         case OS.VK_DOWN:
3451                                         case OS.VK_LEFT:
3452                                         case OS.VK_RIGHT:
3453                                         case OS.VK_NUMLOCK:
3454                                         case OS.VK_SNAPSHOT:
3455                                         case OS.VK_CANCEL:
3456                                         case OS.VK_DIVIDE:
3457                                                 inputs.dwFlags |= OS.KEYEVENTF_EXTENDEDKEY;
3458                                 }
3459                                 long hHeap = OS.GetProcessHeap ();
3460                                 long pInputs = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, INPUT.sizeof);
3461                                 OS.MoveMemory(pInputs, new int[] {OS.INPUT_KEYBOARD}, 4);
3462                                 //TODO - DWORD type of INPUT structure aligned to 8 bytes on 64 bit
3463                                 OS.MoveMemory (pInputs + C.PTR_SIZEOF, inputs, KEYBDINPUT.sizeof);
3464                                 boolean result = OS.SendInput (1, pInputs, INPUT.sizeof) != 0;
3465                                 OS.HeapFree (hHeap, 0, pInputs);
3466                                 return result;
3467                         }
3468                         case SWT.MouseDown:
3469                         case SWT.MouseMove:
3470                         case SWT.MouseUp:
3471                         case SWT.MouseWheel: {
3472                                 MOUSEINPUT inputs = new MOUSEINPUT ();
3473                                 if (type == SWT.MouseMove){
3474                                         inputs.dwFlags = OS.MOUSEEVENTF_MOVE | OS.MOUSEEVENTF_ABSOLUTE | OS.MOUSEEVENTF_VIRTUALDESK;
3475                                         int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN);
3476                                         int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN);
3477                                         int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN);
3478                                         int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN);
3479                                         Point loc = event.getLocationInPixels();
3480                                         inputs.dx = ((loc.x - x) * 65535 + width - 2) / (width - 1);
3481                                         inputs.dy = ((loc.y - y) * 65535 + height - 2) / (height - 1);
3482                                 } else {
3483                                         if (type == SWT.MouseWheel) {
3484                                                 inputs.dwFlags = OS.MOUSEEVENTF_WHEEL;
3485                                                 switch (event.detail) {
3486                                                         case SWT.SCROLL_PAGE:
3487                                                                 inputs.mouseData = event.count * OS.WHEEL_DELTA;
3488                                                                 break;
3489                                                         case SWT.SCROLL_LINE:
3490                                                                 int [] value = new int [1];
3491                                                                 OS.SystemParametersInfo (OS.SPI_GETWHEELSCROLLLINES, 0, value, 0);
3492                                                                 inputs.mouseData = event.count * OS.WHEEL_DELTA / value [0];
3493                                                                 break;
3494                                                         default: return false;
3495                                                 }
3496                                         } else {
3497                                                 switch (event.button) {
3498                                                         case 1: inputs.dwFlags = type == SWT.MouseDown ? OS.MOUSEEVENTF_LEFTDOWN : OS.MOUSEEVENTF_LEFTUP; break;
3499                                                         case 2: inputs.dwFlags = type == SWT.MouseDown ? OS.MOUSEEVENTF_MIDDLEDOWN : OS.MOUSEEVENTF_MIDDLEUP; break;
3500                                                         case 3: inputs.dwFlags = type == SWT.MouseDown ? OS.MOUSEEVENTF_RIGHTDOWN : OS.MOUSEEVENTF_RIGHTUP; break;
3501                                                         case 4: {
3502                                                                 inputs.dwFlags = type == SWT.MouseDown ? OS.MOUSEEVENTF_XDOWN : OS.MOUSEEVENTF_XUP;
3503                                                                 inputs.mouseData = OS.XBUTTON1;
3504                                                                 break;
3505                                                         }
3506                                                         case 5: {
3507                                                                 inputs.dwFlags = type == SWT.MouseDown ? OS.MOUSEEVENTF_XDOWN : OS.MOUSEEVENTF_XUP;
3508                                                                 inputs.mouseData = OS.XBUTTON2;
3509                                                                 break;
3510                                                         }
3511                                                         default: return false;
3512                                                 }
3513                                         }
3514                                 }
3515                                 long hHeap = OS.GetProcessHeap ();
3516                                 long pInputs = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, INPUT.sizeof);
3517                                 OS.MoveMemory(pInputs, new int[] {OS.INPUT_MOUSE}, 4);
3518                                 //TODO - DWORD type of INPUT structure aligned to 8 bytes on 64 bit
3519                                 OS.MoveMemory (pInputs + C.PTR_SIZEOF, inputs, MOUSEINPUT.sizeof);
3520                                 boolean result = OS.SendInput (1, pInputs, INPUT.sizeof) != 0;
3521                                 OS.HeapFree (hHeap, 0, pInputs);
3522                                 return result;
3523                         }
3524                 }
3525                 return false;
3526         }
3527 }
3528
3529 void postEvent (Event event) {
3530         /*
3531         * Place the event at the end of the event queue.
3532         * This code is always called in the Display's
3533         * thread so it must be re-enterant but does not
3534         * need to be synchronized.
3535         */
3536         if (eventQueue == null) eventQueue = new Event [4];
3537         int index = 0;
3538         int length = eventQueue.length;
3539         while (index < length) {
3540                 if (eventQueue [index] == null) break;
3541                 index++;
3542         }
3543         if (index == length) {
3544                 Event [] newQueue = new Event [length + 4];
3545                 System.arraycopy (eventQueue, 0, newQueue, 0, length);
3546                 eventQueue = newQueue;
3547         }
3548         eventQueue [index] = event;
3549 }
3550
3551 /**
3552  * Reads an event from the operating system's event queue,
3553  * dispatches it appropriately, and returns <code>true</code>
3554  * if there is potentially more work to do, or <code>false</code>
3555  * if the caller can sleep until another event is placed on
3556  * the event queue.
3557  * <p>
3558  * In addition to checking the system event queue, this method also
3559  * checks if any inter-thread messages (created by <code>syncExec()</code>
3560  * or <code>asyncExec()</code>) are waiting to be processed, and if
3561  * so handles them before returning.
3562  * </p>
3563  *
3564  * @return <code>false</code> if the caller can sleep upon return from this method
3565  *
3566  * @exception SWTException <ul>
3567  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3568  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3569  *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
3570  * </ul>
3571  *
3572  * @see #sleep
3573  * @see #wake
3574  */
3575 public boolean readAndDispatch () {
3576         checkDevice ();
3577         lpStartupInfo = null;
3578         drawMenuBars ();
3579         runSkin ();
3580         runDeferredLayouts ();
3581         runPopups ();
3582         if (OS.PeekMessage (msg, 0, 0, 0, OS.PM_REMOVE)) {
3583                 if (!filterMessage (msg)) {
3584                         OS.TranslateMessage (msg);
3585                         OS.DispatchMessage (msg);
3586                 }
3587                 runDeferredEvents ();
3588                 return true;
3589         }
3590         return isDisposed () || runAsyncMessages (false);
3591 }
3592
3593 static void register (Display display) {
3594         synchronized (Device.class) {
3595                 for (int i=0; i<Displays.length; i++) {
3596                         if (Displays [i] == null) {
3597                                 Displays [i] = display;
3598                                 return;
3599                         }
3600                 }
3601                 Display [] newDisplays = new Display [Displays.length + 4];
3602                 System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
3603                 newDisplays [Displays.length] = display;
3604                 Displays = newDisplays;
3605         }
3606 }
3607
3608 /**
3609  * Releases any internal resources back to the operating
3610  * system and clears all fields except the device handle.
3611  * <p>
3612  * Disposes all shells which are currently open on the display.
3613  * After this method has been invoked, all related related shells
3614  * will answer <code>true</code> when sent the message
3615  * <code>isDisposed()</code>.
3616  * </p><p>
3617  * When a device is destroyed, resources that were acquired
3618  * on behalf of the programmer need to be returned to the
3619  * operating system.  For example, if the device allocated a
3620  * font to be used as the system font, this font would be
3621  * freed in <code>release</code>.  Also,to assist the garbage
3622  * collector and minimize the amount of memory that is not
3623  * reclaimed when the programmer keeps a reference to a
3624  * disposed device, all fields except the handle are zero'd.
3625  * The handle is needed by <code>destroy</code>.
3626  * </p>
3627  * This method is called before <code>destroy</code>.
3628  *
3629  * @see Device#dispose
3630  * @see #destroy
3631  */
3632 @Override
3633 protected void release () {
3634         sendEvent (SWT.Dispose, new Event ());
3635         Shell [] shells = getShells ();
3636         for (int i=0; i<shells.length; i++) {
3637                 Shell shell = shells [i];
3638                 if (!shell.isDisposed ()) shell.dispose ();
3639         }
3640         if (tray != null) tray.dispose ();
3641         tray = null;
3642         if (taskBar != null) taskBar.dispose ();
3643         taskBar = null;
3644         while (readAndDispatch ()) {}
3645         if (disposeList != null) {
3646                 for (int i=0; i<disposeList.length; i++) {
3647                         Runnable next = disposeList [i];
3648                         if (next != null) {
3649                                 try {
3650                                         next.run ();
3651                                 } catch (RuntimeException exception) {
3652                                         runtimeExceptionHandler.accept (exception);
3653                                 } catch (Error error) {
3654                                         errorHandler.accept (error);
3655                                 }
3656                         }
3657                 }
3658         }
3659         disposeList = null;
3660         synchronizer.releaseSynchronizer ();
3661         synchronizer = null;
3662         releaseDisplay ();
3663         super.release ();
3664 }
3665
3666 void releaseDisplay () {
3667         if (embeddedHwnd != 0) {
3668                 OS.PostMessage (embeddedHwnd, SWT_DESTROY, 0, 0);
3669         }
3670
3671         /* Free custom icons */
3672         if (hIconSearch != 0) OS.DestroyIcon (hIconSearch);
3673         if (hIconCancel != 0) OS.DestroyIcon (hIconCancel);
3674
3675         /* Release XP Themes */
3676         if (hButtonTheme != 0) OS.CloseThemeData (hButtonTheme);
3677         if (hEditTheme != 0) OS.CloseThemeData (hEditTheme);
3678         if (hExplorerBarTheme != 0) OS.CloseThemeData (hExplorerBarTheme);
3679         if (hScrollBarTheme != 0) OS.CloseThemeData (hScrollBarTheme);
3680         if (hTabTheme != 0) OS.CloseThemeData (hTabTheme);
3681         hButtonTheme = hEditTheme = hExplorerBarTheme = hScrollBarTheme = hTabTheme = 0;
3682
3683         /* Unhook the message hook */
3684         if (msgHook != 0) OS.UnhookWindowsHookEx (msgHook);
3685         msgHook = 0;
3686
3687         /* Unhook the filter hook */
3688         if (filterHook != 0) OS.UnhookWindowsHookEx (filterHook);
3689         filterHook = 0;
3690         msgFilterCallback.dispose ();
3691         msgFilterCallback = null;
3692         msgFilterProc = 0;
3693
3694         /* Unhook the idle hook */
3695         if (idleHook != 0) OS.UnhookWindowsHookEx (idleHook);
3696         idleHook = 0;
3697         foregroundIdleCallback.dispose ();
3698         foregroundIdleCallback = null;
3699         foregroundIdleProc = 0;
3700
3701         /* Stop the settings timer */
3702         OS.KillTimer (hwndMessage, SETTINGS_ID);
3703
3704         /* Destroy the message only HWND */
3705         if (hwndMessage != 0) OS.DestroyWindow (hwndMessage);
3706         hwndMessage = 0;
3707         messageCallback.dispose ();
3708         messageCallback = null;
3709         messageProc = 0;
3710
3711         /* Unregister the SWT window class */
3712         long hHeap = OS.GetProcessHeap ();
3713         long hInstance = OS.GetModuleHandle (null);
3714         OS.UnregisterClass (windowClass, hInstance);
3715
3716         /* Unregister the SWT drop shadow and CS_OWNDC window class */
3717         OS.UnregisterClass (windowShadowClass, hInstance);
3718         OS.UnregisterClass (windowOwnDCClass, hInstance);
3719         windowClass = windowShadowClass = windowOwnDCClass = null;
3720         windowCallback.dispose ();
3721         windowCallback = null;
3722         windowProc = 0;
3723
3724         /* Release the System fonts */
3725         if (systemFont != null) systemFont.dispose ();
3726         systemFont = null;
3727         lfSystemFont = null;
3728
3729         /* Release the System Images */
3730         if (errorImage != null) errorImage.dispose ();
3731         if (infoImage != null) infoImage.dispose ();
3732         if (questionImage != null) questionImage.dispose ();
3733         if (warningIcon != null) warningIcon.dispose ();
3734         errorImage = infoImage = questionImage = warningIcon = null;
3735
3736         /* Release the System Cursors */
3737         for (int i = 0; i < cursors.length; i++) {
3738                 if (cursors [i] != null) cursors [i].dispose ();
3739         }
3740         cursors = null;
3741
3742         /* Release Acquired Resources */
3743         if (resources != null) {
3744                 for (int i=0; i<resources.length; i++) {
3745                         if (resources [i] != null) resources [i].dispose ();
3746                 }
3747                 resources = null;
3748         }
3749
3750         /* Release Custom Colors for ChooseColor */
3751         if (lpCustColors != 0) OS.HeapFree (hHeap, 0, lpCustColors);
3752         lpCustColors = 0;
3753
3754         /* Uninitialize OLE */
3755         OS.OleUninitialize ();
3756
3757         /* Uninitialize buffered painting */
3758         OS.BufferedPaintUnInit ();
3759
3760         /* Release references */
3761         thread = null;
3762         msg = hookMsg = null;
3763         keyboard = null;
3764         modalDialog = null;
3765         modalShells = null;
3766         data = null;
3767         keys = null;
3768         values = null;
3769         bars = popups = null;
3770         indexTable = null;
3771         timerIds = null;
3772         controlTable = null;
3773         lastControl = lastGetControl = lastHittestControl = null;
3774         imageList = toolImageList = toolHotImageList = toolDisabledImageList = null;
3775         timerList = null;
3776         tableBuffer = null;
3777         eventTable = filterTable = null;
3778         items = null;
3779         clickRect = null;
3780         monitors = null;
3781         touchSources = null;
3782
3783         /* Release handles */
3784         threadId = 0;
3785 }
3786
3787 void releaseImageList (ImageList list) {
3788         int i = 0;
3789         int length = imageList.length;
3790         while (i < length) {
3791                 if (imageList [i] == list) {
3792                         if (list.removeRef () > 0) return;
3793                         list.dispose ();
3794                         System.arraycopy (imageList, i + 1, imageList, i, --length - i);
3795                         imageList [length] = null;
3796                         for (int j=0; j<length; j++) {
3797                                 if (imageList [j] != null) return;
3798                         }
3799                         imageList = null;
3800                         return;
3801                 }
3802                 i++;
3803         }
3804 }
3805
3806 void releaseToolImageList (ImageList list) {
3807         int i = 0;
3808         int length = toolImageList.length;
3809         while (i < length) {
3810                 if (toolImageList [i] == list) {
3811                         if (list.removeRef () > 0) return;
3812                         list.dispose ();
3813                         System.arraycopy (toolImageList, i + 1, toolImageList, i, --length - i);
3814                         toolImageList [length] = null;
3815                         for (int j=0; j<length; j++) {
3816                                 if (toolImageList [j] != null) return;
3817                         }
3818                         toolImageList = null;
3819                         return;
3820                 }
3821                 i++;
3822         }
3823 }
3824
3825 void releaseToolHotImageList (ImageList list) {
3826         int i = 0;
3827         int length = toolHotImageList.length;
3828         while (i < length) {
3829                 if (toolHotImageList [i] == list) {
3830                         if (list.removeRef () > 0) return;
3831                         list.dispose ();
3832                         System.arraycopy (toolHotImageList, i + 1, toolHotImageList, i, --length - i);
3833                         toolHotImageList [length] = null;
3834                         for (int j=0; j<length; j++) {
3835                                 if (toolHotImageList [j] != null) return;
3836                         }
3837                         toolHotImageList = null;
3838                         return;
3839                 }
3840                 i++;
3841         }
3842 }
3843
3844 void releaseToolDisabledImageList (ImageList list) {
3845         int i = 0;
3846         int length = toolDisabledImageList.length;
3847         while (i < length) {
3848                 if (toolDisabledImageList [i] == list) {
3849                         if (list.removeRef () > 0) return;
3850                         list.dispose ();
3851                         System.arraycopy (toolDisabledImageList, i + 1, toolDisabledImageList, i, --length - i);
3852                         toolDisabledImageList [length] = null;
3853                         for (int j=0; j<length; j++) {
3854                                 if (toolDisabledImageList [j] != null) return;
3855                         }
3856                         toolDisabledImageList = null;
3857                         return;
3858                 }
3859                 i++;
3860         }
3861 }
3862
3863 /**
3864  * Removes the listener from the collection of listeners who will
3865  * be notified when an event of the given type occurs anywhere in
3866  * a widget. The event type is one of the event constants defined
3867  * in class <code>SWT</code>.
3868  *
3869  * @param eventType the type of event to listen for
3870  * @param listener the listener which should no longer be notified when the event occurs
3871  *
3872  * @exception IllegalArgumentException <ul>
3873  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3874  * </ul>
3875  * @exception SWTException <ul>
3876  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3877  * </ul>
3878  *
3879  * @see Listener
3880  * @see SWT
3881  * @see #addFilter
3882  * @see #addListener
3883  *
3884  * @since 3.0
3885  */
3886 public void removeFilter (int eventType, Listener listener) {
3887         checkDevice ();
3888         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
3889         if (filterTable == null) return;
3890         filterTable.unhook (eventType, listener);
3891         if (filterTable.size () == 0) filterTable = null;
3892 }
3893
3894 /**
3895  * Removes the listener from the collection of listeners who will
3896  * be notified when an event of the given type occurs. The event type
3897  * is one of the event constants defined in class <code>SWT</code>.
3898  *
3899  * @param eventType the type of event to listen for
3900  * @param listener the listener which should no longer be notified
3901  *
3902  * @exception IllegalArgumentException <ul>
3903  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3904  * </ul>
3905  * @exception SWTException <ul>
3906  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3907  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3908  * </ul>
3909  *
3910  * @see Listener
3911  * @see SWT
3912  * @see #addListener
3913  *
3914  * @since 2.0
3915  */
3916 public void removeListener (int eventType, Listener listener) {
3917         checkDevice ();
3918         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
3919         if (eventTable == null) return;
3920         eventTable.unhook (eventType, listener);
3921 }
3922
3923 void removeBar (Menu menu) {
3924         if (bars == null) return;
3925         for (int i=0; i<bars.length; i++) {
3926                 if (bars [i] == menu) {
3927                         bars [i] = null;
3928                         return;
3929                 }
3930         }
3931 }
3932
3933 Control removeControl (long handle) {
3934         if (handle == 0) return null;
3935         lastControl = lastGetControl = null;
3936         Control control = null;
3937         int index = (int)OS.RemoveProp (handle, SWT_OBJECT_INDEX) - 1;
3938         if (0 <= index && index < controlTable.length) {
3939                 control = controlTable [index];
3940                 controlTable [index] = null;
3941                 indexTable [index] = freeSlot;
3942                 freeSlot = index;
3943         }
3944         return control;
3945 }
3946
3947 void removeMenuItem (MenuItem item) {
3948         if (items == null) return;
3949         items [item.id - ID_START] = null;
3950 }
3951
3952 void removePopup (Menu menu) {
3953         if (popups == null) return;
3954         for (int i=0; i<popups.length; i++) {
3955                 if (popups [i] == menu) {
3956                         popups [i] = null;
3957                         return;
3958                 }
3959         }
3960 }
3961
3962 boolean runAsyncMessages (boolean all) {
3963         return synchronizer.runAsyncMessages (all);
3964 }
3965
3966 boolean runDeferredEvents () {
3967         boolean run = false;
3968         /*
3969         * Run deferred events.  This code is always
3970         * called in the Display's thread so it must
3971         * be re-enterant but need not be synchronized.
3972         */
3973         while (eventQueue != null) {
3974
3975                 /* Take an event off the queue */
3976                 Event event = eventQueue [0];
3977                 if (event == null) break;
3978                 int length = eventQueue.length;
3979                 System.arraycopy (eventQueue, 1, eventQueue, 0, --length);
3980                 eventQueue [length] = null;
3981
3982                 /* Run the event */
3983                 Widget widget = event.widget;
3984                 if (widget != null && !widget.isDisposed ()) {
3985                         Widget item = event.item;
3986                         if (item == null || !item.isDisposed ()) {
3987                                 run = true;
3988                                 widget.sendEvent (event);
3989                         }
3990                 }
3991
3992                 /*
3993                 * At this point, the event queue could
3994                 * be null due to a recursive invocation
3995                 * when running the event.
3996                 */
3997         }
3998
3999         /* Clear the queue */
4000         eventQueue = null;
4001         return run;
4002 }
4003
4004 boolean runDeferredLayouts () {
4005         if (layoutDeferredCount != 0) {
4006                 Composite[] temp = layoutDeferred;
4007                 int count = layoutDeferredCount;
4008                 layoutDeferred = null;
4009                 layoutDeferredCount = 0;
4010                 for (int i = 0; i < count; i++) {
4011                         Composite comp = temp[i];
4012                         if (!comp.isDisposed()) comp.setLayoutDeferred (false);
4013                 }
4014                 return true;
4015         }
4016         return false;
4017 }
4018
4019 boolean runPopups () {
4020         if (popups == null) return false;
4021         boolean result = false;
4022         while (popups != null) {
4023                 Menu menu = popups [0];
4024                 if (menu == null) break;
4025                 int length = popups.length;
4026                 System.arraycopy (popups, 1, popups, 0, --length);
4027                 popups [length] = null;
4028                 runDeferredEvents ();
4029                 if (!menu.isDisposed ()) menu._setVisible (true);
4030                 result = true;
4031         }
4032         popups = null;
4033         return result;
4034 }
4035
4036 void runSettings () {
4037         Font oldFont = getSystemFont ();
4038         saveResources ();
4039         sendEvent (SWT.Settings, null);
4040         Font newFont = getSystemFont ();
4041         boolean sameFont = oldFont.equals (newFont);
4042         Shell [] shells = getShells ();
4043         for (int i=0; i<shells.length; i++) {
4044                 Shell shell = shells [i];
4045                 if (!shell.isDisposed ()) {
4046                         if (!sameFont) {
4047                                 shell.updateFont (oldFont, newFont);
4048                         }
4049                         /* This code is intentionally commented */
4050                         //shell.redraw (true);
4051                         shell.layout (true, true);
4052                 }
4053         }
4054 }
4055
4056 boolean runSkin () {
4057         if (skinCount > 0) {
4058                 Widget [] oldSkinWidgets = skinList;
4059                 int count = skinCount;
4060                 skinList = new Widget[GROW_SIZE];
4061                 skinCount = 0;
4062                 if (eventTable != null && eventTable.hooks(SWT.Skin)) {
4063                         for (int i = 0; i < count; i++) {
4064                                 Widget widget = oldSkinWidgets[i];
4065                                 if (widget != null && !widget.isDisposed()) {
4066                                         widget.state &= ~Widget.SKIN_NEEDED;
4067                                         oldSkinWidgets[i] = null;
4068                                         Event event = new Event ();
4069                                         event.widget = widget;
4070                                         sendEvent (SWT.Skin, event);
4071                                 }
4072                         }
4073                 }
4074                 return true;
4075         }
4076         return false;
4077 }
4078
4079 boolean runTimer (long id) {
4080         if (timerList != null && timerIds != null) {
4081                 int index = 0;
4082                 while (index <timerIds.length) {
4083                         if (timerIds [index] == id) {
4084                                 OS.KillTimer (hwndMessage, timerIds [index]);
4085                                 timerIds [index] = 0;
4086                                 Runnable runnable = timerList [index];
4087                                 timerList [index] = null;
4088                                 if (runnable != null) {
4089                                         try {
4090                                                 runnable.run ();
4091                                         } catch (RuntimeException exception) {
4092                                                 runtimeExceptionHandler.accept (exception);
4093                                         } catch (Error exception) {
4094                                                 errorHandler.accept (exception);
4095                                         }
4096                                 }
4097                                 return true;
4098                         }
4099                         index++;
4100                 }
4101         }
4102         return false;
4103 }
4104
4105 void saveResources () {
4106         int resourceCount = 0;
4107         if (resources == null) {
4108                 resources = new Resource [RESOURCE_SIZE];
4109         } else {
4110                 resourceCount = resources.length;
4111                 Resource [] newResources = new Resource [resourceCount + RESOURCE_SIZE];
4112                 System.arraycopy (resources, 0, newResources, 0, resourceCount);
4113                 resources = newResources;
4114         }
4115         if (systemFont != null) {
4116                 NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
4117                 info.cbSize = NONCLIENTMETRICS.sizeof;
4118                 if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
4119                         LOGFONT logFont = info.lfMessageFont;
4120                         if (lfSystemFont == null ||
4121                                 logFont.lfCharSet != lfSystemFont.lfCharSet ||
4122                                 logFont.lfHeight != lfSystemFont.lfHeight ||
4123                                 logFont.lfWidth != lfSystemFont.lfWidth ||
4124                                 logFont.lfEscapement != lfSystemFont.lfEscapement ||
4125                                 logFont.lfOrientation != lfSystemFont.lfOrientation ||
4126                                 logFont.lfWeight != lfSystemFont.lfWeight ||
4127                                 logFont.lfItalic != lfSystemFont.lfItalic ||
4128                                 logFont.lfUnderline != lfSystemFont.lfUnderline ||
4129                                 logFont.lfStrikeOut != lfSystemFont.lfStrikeOut ||
4130                                 logFont.lfCharSet != lfSystemFont.lfCharSet ||
4131                                 logFont.lfOutPrecision != lfSystemFont.lfOutPrecision ||
4132                                 logFont.lfClipPrecision != lfSystemFont.lfClipPrecision ||
4133                                 logFont.lfQuality != lfSystemFont.lfQuality ||
4134                                 logFont.lfPitchAndFamily != lfSystemFont.lfPitchAndFamily ||
4135                                 !getFontName (logFont).equals (getFontName (lfSystemFont))) {
4136                                         resources [resourceCount++] = systemFont;
4137                                         lfSystemFont = logFont;
4138                                         systemFont = null;
4139                         }
4140                 }
4141         }
4142         if (errorImage != null) resources [resourceCount++] = errorImage;
4143         if (infoImage != null) resources [resourceCount++] = infoImage;
4144         if (questionImage != null) resources [resourceCount++] = questionImage;
4145         if (warningIcon != null) resources [resourceCount++] = warningIcon;
4146         errorImage = infoImage = questionImage = warningIcon = null;
4147         for (int i=0; i<cursors.length; i++) {
4148                 if (cursors [i] != null) resources [resourceCount++] = cursors [i];
4149                 cursors [i] = null;
4150         }
4151         if (resourceCount < RESOURCE_SIZE) {
4152                 Resource [] newResources = new Resource [resourceCount];
4153                 System.arraycopy (resources, 0, newResources, 0, resourceCount);
4154                 resources = newResources;
4155         }
4156 }
4157
4158 void sendEvent (int eventType, Event event) {
4159         if (eventTable == null && filterTable == null) {
4160                 return;
4161         }
4162         if (event == null) event = new Event ();
4163         event.display = this;
4164         event.type = eventType;
4165         if (event.time == 0) event.time = getLastEventTime ();
4166         if (!filterEvent (event)) {
4167                 if (eventTable != null) sendEvent (eventTable, event);
4168         }
4169 }
4170
4171 void sendEvent (EventTable eventTable, Event event) {
4172         int type = event.type;
4173         sendPreEvent (type);
4174         try {
4175                 eventTable.sendEvent (event);
4176         } finally {
4177                 sendPostEvent (type);
4178         }
4179 }
4180
4181 void sendPreEvent (int eventType) {
4182         if (eventType != SWT.PreEvent && eventType != SWT.PostEvent
4183                         && eventType != SWT.PreExternalEventDispatch
4184                         && eventType != SWT.PostExternalEventDispatch) {
4185                 if (eventTable != null && eventTable.hooks (SWT.PreEvent)) {
4186                         Event event = new Event ();
4187                         event.detail = eventType;
4188                         sendEvent (SWT.PreEvent, event);
4189                 }
4190         }
4191 }
4192
4193 void sendPostEvent (int eventType) {
4194         if (eventType != SWT.PreEvent && eventType != SWT.PostEvent
4195                         && eventType != SWT.PreExternalEventDispatch
4196                         && eventType != SWT.PostExternalEventDispatch) {
4197                 if (eventTable != null && eventTable.hooks (SWT.PostEvent)) {
4198                         Event event = new Event ();
4199                         event.detail = eventType;
4200                         sendEvent (SWT.PostEvent, event);
4201                 }
4202         }
4203 }
4204
4205 /**
4206  * Sends a SWT.PreExternalEventDispatch event.
4207  *
4208  * @noreference This method is not intended to be referenced by clients.
4209  */
4210 public void sendPreExternalEventDispatchEvent () {
4211         if (eventTable != null && eventTable.hooks (SWT.PreExternalEventDispatch)) {
4212                 sendEvent (SWT.PreExternalEventDispatch, null);
4213         }
4214 }
4215
4216 /**
4217  * Sends a SWT.PostExternalEventDispatch event.
4218  *
4219  * @noreference This method is not intended to be referenced by clients.
4220  */
4221 public void sendPostExternalEventDispatchEvent () {
4222         if (eventTable != null && eventTable.hooks (SWT.PostExternalEventDispatch)) {
4223                 sendEvent (SWT.PostExternalEventDispatch, null);
4224         }
4225 }
4226
4227 /**
4228  * Sets the location of the on-screen pointer relative to the top left corner
4229  * of the screen.  <b>Note: It is typically considered bad practice for a
4230  * program to move the on-screen pointer location.</b>
4231  *
4232  * @param x the new x coordinate for the cursor
4233  * @param y the new y coordinate for the cursor
4234  *
4235  * @exception SWTException <ul>
4236  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4237  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4238  * </ul>
4239  *
4240  * @since 2.1
4241  */
4242 public void setCursorLocation (int x, int y) {
4243         checkDevice ();
4244         setCursorLocationInPixels (DPIUtil.autoScaleUp (x), DPIUtil.autoScaleUp (y));
4245 }
4246
4247 void setCursorLocationInPixels (int x, int y) {
4248         OS.SetCursorPos (x, y);
4249 }
4250
4251 /**
4252  * Sets the location of the on-screen pointer relative to the top left corner
4253  * of the screen.  <b>Note: It is typically considered bad practice for a
4254  * program to move the on-screen pointer location.</b>
4255  *
4256  * @param point new position
4257  *
4258  * @exception SWTException <ul>
4259  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4260  *    <li>ERROR_NULL_ARGUMENT - if the point is null
4261  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4262  * </ul>
4263  *
4264  * @since 2.0
4265  */
4266 public void setCursorLocation (Point point) {
4267         checkDevice ();
4268         if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
4269         setCursorLocation (point.x, point.y);
4270 }
4271
4272 /**
4273  * Sets the application defined property of the receiver
4274  * with the specified name to the given argument.
4275  * <p>
4276  * Applications may have associated arbitrary objects with the
4277  * receiver in this fashion. If the objects stored in the
4278  * properties need to be notified when the display is disposed
4279  * of, it is the application's responsibility provide a
4280  * <code>disposeExec()</code> handler which does so.
4281  * </p>
4282  *
4283  * @param key the name of the property
4284  * @param value the new value for the property
4285  *
4286  * @exception IllegalArgumentException <ul>
4287  *    <li>ERROR_NULL_ARGUMENT - if the key is null</li>
4288  * </ul>
4289  * @exception SWTException <ul>
4290  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4291  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4292  * </ul>
4293  *
4294  * @see #getData(String)
4295  * @see #disposeExec(Runnable)
4296  */
4297 public void setData (String key, Object value) {
4298         checkDevice ();
4299         if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
4300
4301         if (key.equals (RUN_MESSAGES_IN_IDLE_KEY)) {
4302                 Boolean data = (Boolean) value;
4303                 runMessagesInIdle = data != null && data.booleanValue ();
4304                 return;
4305         }
4306         if (key.equals (RUN_MESSAGES_IN_MESSAGE_PROC_KEY)) {
4307                 Boolean data = (Boolean) value;
4308                 runMessagesInMessageProc = data != null && data.booleanValue ();
4309                 return;
4310         }
4311         if (key.equals (USE_OWNDC_KEY)) {
4312                 Boolean data = (Boolean) value;
4313                 useOwnDC = data != null && data.booleanValue ();
4314                 return;
4315         }
4316         if (key.equals (ACCEL_KEY_HIT)) {
4317                 Boolean data = (Boolean) value;
4318                 accelKeyHit = data != null && data.booleanValue ();
4319                 return;
4320         }
4321         if (key.equals (EXTERNAL_EVENT_LOOP_KEY)) {
4322                 Boolean data = (Boolean) value;
4323                 externalEventLoop = data != null && data.booleanValue ();
4324                 return;
4325         }
4326         /* Remove the key/value pair */
4327         if (value == null) {
4328                 if (keys == null) return;
4329                 int index = 0;
4330                 while (index < keys.length && !keys [index].equals (key)) index++;
4331                 if (index == keys.length) return;
4332                 if (keys.length == 1) {
4333                         keys = null;
4334                         values = null;
4335                 } else {
4336                         String [] newKeys = new String [keys.length - 1];
4337                         Object [] newValues = new Object [values.length - 1];
4338                         System.arraycopy (keys, 0, newKeys, 0, index);
4339                         System.arraycopy (keys, index + 1, newKeys, index, newKeys.length - index);
4340                         System.arraycopy (values, 0, newValues, 0, index);
4341                         System.arraycopy (values, index + 1, newValues, index, newValues.length - index);
4342                         keys = newKeys;
4343                         values = newValues;
4344                 }
4345                 return;
4346         }
4347
4348         /* Add the key/value pair */
4349         if (keys == null) {
4350                 keys = new String [] {key};
4351                 values = new Object [] {value};
4352                 return;
4353         }
4354         for (int i=0; i<keys.length; i++) {
4355                 if (keys [i].equals (key)) {
4356                         values [i] = value;
4357                         return;
4358                 }
4359         }
4360         String [] newKeys = new String [keys.length + 1];
4361         Object [] newValues = new Object [values.length + 1];
4362         System.arraycopy (keys, 0, newKeys, 0, keys.length);
4363         System.arraycopy (values, 0, newValues, 0, values.length);
4364         newKeys [keys.length] = key;
4365         newValues [values.length] = value;
4366         keys = newKeys;
4367         values = newValues;
4368 }
4369
4370 /**
4371  * Sets the application defined, display specific data
4372  * associated with the receiver, to the argument.
4373  * The <em>display specific data</em> is a single,
4374  * unnamed field that is stored with every display.
4375  * <p>
4376  * Applications may put arbitrary objects in this field. If
4377  * the object stored in the display specific data needs to
4378  * be notified when the display is disposed of, it is the
4379  * application's responsibility provide a
4380  * <code>disposeExec()</code> handler which does so.
4381  * </p>
4382  *
4383  * @param data the new display specific data
4384  *
4385  * @exception SWTException <ul>
4386  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4387  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4388  * </ul>
4389  *
4390  * @see #getData()
4391  * @see #disposeExec(Runnable)
4392  */
4393 public void setData (Object data) {
4394         checkDevice ();
4395         this.data = data;
4396 }
4397
4398 /**
4399  * Returns the application name.
4400  *
4401  * @return the application name
4402  *
4403  * @see #setAppName(String)
4404  *
4405  * @since 3.6
4406  */
4407 public static String getAppName () {
4408         return APP_NAME;
4409 }
4410
4411 /**
4412  * Returns the application version.
4413  *
4414  * @return the application version
4415  *
4416  * @see #setAppVersion(String)
4417  *
4418  * @since 3.6
4419  */
4420 public static String getAppVersion () {
4421         return APP_VERSION;
4422 }
4423
4424 /**
4425  * Sets the application name to the argument.
4426  * <p>
4427  * The application name can be used in several ways,
4428  * depending on the platform and tools being used.
4429  * Accessibility tools could ask for the application
4430  * name. On Windows, if the application name is set
4431  * to any value other than "SWT" (case insensitive),
4432  * it is used to set the application user model ID
4433  * which is used by the OS for taskbar grouping.
4434  * @see <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd378459%28v=vs.85%29.aspx#HOW">AppUserModelID (Windows)</a>
4435  * </p><p>
4436  * Specifying <code>null</code> for the name clears it.
4437  * </p>
4438  *
4439  * @param name the new app name or <code>null</code>
4440  */
4441 public static void setAppName (String name) {
4442         APP_NAME = name;
4443 }
4444
4445 /**
4446  * Sets the application version to the argument.
4447  *
4448  * @param version the new app version
4449  *
4450  * @since 3.6
4451  */
4452 public static void setAppVersion (String version) {
4453         APP_VERSION = version;
4454 }
4455
4456 void setModalDialog (Dialog modalDailog) {
4457         this.modalDialog = modalDailog;
4458         Shell [] shells = getShells ();
4459         for (int i=0; i<shells.length; i++) shells [i].updateModal ();
4460 }
4461
4462 void setModalShell (Shell shell) {
4463         if (modalShells == null) modalShells = new Shell [4];
4464         int index = 0, length = modalShells.length;
4465         while (index < length) {
4466                 if (modalShells [index] == shell) return;
4467                 if (modalShells [index] == null) break;
4468                 index++;
4469         }
4470         if (index == length) {
4471                 Shell [] newModalShells = new Shell [length + 4];
4472                 System.arraycopy (modalShells, 0, newModalShells, 0, length);
4473                 modalShells = newModalShells;
4474         }
4475         modalShells [index] = shell;
4476         Shell [] shells = getShells ();
4477         for (int i=0; i<shells.length; i++) shells [i].updateModal ();
4478 }
4479
4480 /**
4481  * Sets the synchronizer used by the display to be
4482  * the argument, which can not be null.
4483  *
4484  * @param synchronizer the new synchronizer for the display (must not be null)
4485  *
4486  * @exception IllegalArgumentException <ul>
4487  *    <li>ERROR_NULL_ARGUMENT - if the synchronizer is null</li>
4488  * </ul>
4489  * @exception SWTException <ul>
4490  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4491  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4492  *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
4493  * </ul>
4494  */
4495 public void setSynchronizer (Synchronizer synchronizer) {
4496         checkDevice ();
4497         if (synchronizer == null) error (SWT.ERROR_NULL_ARGUMENT);
4498         if (synchronizer == this.synchronizer) return;
4499         Synchronizer oldSynchronizer;
4500         synchronized (Device.class) {
4501                 oldSynchronizer = this.synchronizer;
4502                 this.synchronizer = synchronizer;
4503         }
4504         if (oldSynchronizer != null) {
4505                 oldSynchronizer.moveAllEventsTo(synchronizer);
4506         }
4507 }
4508
4509 /**
4510  * Sets a callback that will be invoked whenever an exception is thrown by a listener or external
4511  * callback function. The application may use this to set a global exception handling policy:
4512  * the most common policies are either to log and discard the exception or to re-throw the
4513  * exception.
4514  * <p>
4515  * The default SWT error handling policy is to rethrow exceptions.
4516  *
4517  * @param runtimeExceptionHandler new exception handler to be registered.
4518  * @since 3.106
4519  */
4520 public final void setRuntimeExceptionHandler (Consumer<RuntimeException> runtimeExceptionHandler) {
4521         checkDevice();
4522         this.runtimeExceptionHandler = Objects.requireNonNull (runtimeExceptionHandler);
4523 }
4524
4525 /**
4526  * Returns the current exception handler. It will receive all exceptions thrown by listeners
4527  * and external callbacks in this display. If code wishes to temporarily replace the exception
4528  * handler (for example, during a unit test), it is common practice to invoke this method prior
4529  * to replacing the exception handler so that the old handler may be restored afterward.
4530  *
4531  * @return the current exception handler. Never <code>null</code>.
4532  * @since 3.106
4533  */
4534 public final Consumer<RuntimeException> getRuntimeExceptionHandler () {
4535         return runtimeExceptionHandler;
4536 }
4537
4538 /**
4539  * Sets a callback that will be invoked whenever an error is thrown by a listener or external
4540  * callback function. The application may use this to set a global exception handling policy:
4541  * the most common policies are either to log and discard the exception or to re-throw the
4542  * exception.
4543  * <p>
4544  * The default SWT error handling policy is to rethrow exceptions.
4545  *
4546  * @param errorHandler new error handler to be registered.
4547  * @since 3.106
4548  */
4549 public final void setErrorHandler (Consumer<Error> errorHandler) {
4550         checkDevice();
4551         this.errorHandler = Objects.requireNonNull (errorHandler);
4552 }
4553
4554 /**
4555  * Returns the current exception handler. It will receive all errors thrown by listeners
4556  * and external callbacks in this display. If code wishes to temporarily replace the error
4557  * handler (for example, during a unit test), it is common practice to invoke this method prior
4558  * to replacing the error handler so that the old handler may be restored afterward.
4559  *
4560  * @return the current error handler. Never <code>null</code>.
4561  * @since 3.106
4562  */
4563 public final Consumer<Error> getErrorHandler () {
4564         return errorHandler;
4565 }
4566
4567 int shiftedKey (int key) {
4568         /* Clear the virtual keyboard and press the shift key */
4569         for (int i=0; i<keyboard.length; i++) keyboard [i] = 0;
4570         keyboard [OS.VK_SHIFT] |= 0x80;
4571
4572         /* Translate the key to ASCII or UNICODE using the virtual keyboard */
4573         char [] result = new char [1];
4574         if (OS.ToUnicode (key, key, keyboard, result, 1, 0) == 1) return result [0];
4575         return 0;
4576 }
4577
4578 /**
4579  * Causes the user-interface thread to <em>sleep</em> (that is,
4580  * to be put in a state where it does not consume CPU cycles)
4581  * until an event is received or it is otherwise awakened.
4582  *
4583  * @return <code>true</code> if an event requiring dispatching was placed on the queue.
4584  *
4585  * @exception SWTException <ul>
4586  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4587  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4588  * </ul>
4589  *
4590  * @see #wake
4591  */
4592 public boolean sleep () {
4593         checkDevice ();
4594         if (getMessageCount () != 0) return true;
4595         sendPreExternalEventDispatchEvent ();
4596         boolean result = OS.WaitMessage ();
4597         sendPostExternalEventDispatchEvent ();
4598         return result;
4599 }
4600
4601 /**
4602  * Causes the <code>run()</code> method of the runnable to
4603  * be invoked by the user-interface thread at the next
4604  * reasonable opportunity. The thread which calls this method
4605  * is suspended until the runnable completes.  Specifying <code>null</code>
4606  * as the runnable simply wakes the user-interface thread.
4607  * <p>
4608  * Note that at the time the runnable is invoked, widgets
4609  * that have the receiver as their display may have been
4610  * disposed. Therefore, it is necessary to check for this
4611  * case inside the runnable before accessing the widget.
4612  * </p>
4613  *
4614  * @param runnable code to run on the user-interface thread or <code>null</code>
4615  *
4616  * @exception SWTException <ul>
4617  *    <li>ERROR_FAILED_EXEC - if an exception occurred when executing the runnable</li>
4618  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4619  * </ul>
4620  *
4621  * @see #asyncExec
4622  */
4623 public void syncExec (Runnable runnable) {
4624         Synchronizer synchronizer;
4625         synchronized (Device.class) {
4626                 if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
4627                 synchronizer = this.synchronizer;
4628         }
4629         synchronizer.syncExec (runnable);
4630 }
4631
4632 /**
4633  * Causes the <code>run()</code> method of the runnable to
4634  * be invoked by the user-interface thread after the specified
4635  * number of milliseconds have elapsed. If milliseconds is less
4636  * than zero, the runnable is not executed.
4637  * <p>
4638  * Note that at the time the runnable is invoked, widgets
4639  * that have the receiver as their display may have been
4640  * disposed. Therefore, it is necessary to check for this
4641  * case inside the runnable before accessing the widget.
4642  * </p>
4643  *
4644  * @param milliseconds the delay before running the runnable
4645  * @param runnable code to run on the user-interface thread
4646  *
4647  * @exception IllegalArgumentException <ul>
4648  *    <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
4649  * </ul>
4650  * @exception SWTException <ul>
4651  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4652  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4653  * </ul>
4654  *
4655  * @see #asyncExec
4656  */
4657 public void timerExec (int milliseconds, Runnable runnable) {
4658         checkDevice ();
4659         if (runnable == null) error (SWT.ERROR_NULL_ARGUMENT);
4660         if (timerList == null) timerList = new Runnable [4];
4661         if (timerIds == null) timerIds = new long [4];
4662         int index = 0;
4663         while (index < timerList.length) {
4664                 if (timerList [index] == runnable) break;
4665                 index++;
4666         }
4667         long timerId = 0;
4668         if (index != timerList.length) {
4669                 timerId = timerIds [index];
4670                 if (milliseconds < 0) {
4671                         OS.KillTimer (hwndMessage, timerId);
4672                         timerList [index] = null;
4673                         timerIds [index] = 0;
4674                         return;
4675                 }
4676         } else {
4677                 if (milliseconds < 0) return;
4678                 index = 0;
4679                 while (index < timerList.length) {
4680                         if (timerList [index] == null) break;
4681                         index++;
4682                 }
4683                 timerId = nextTimerId++;
4684                 if (index == timerList.length) {
4685                         Runnable [] newTimerList = new Runnable [timerList.length + 4];
4686                         System.arraycopy (timerList, 0, newTimerList, 0, timerList.length);
4687                         timerList = newTimerList;
4688                         long [] newTimerIds = new long [timerIds.length + 4];
4689                         System.arraycopy (timerIds, 0, newTimerIds, 0, timerIds.length);
4690                         timerIds = newTimerIds;
4691                 }
4692         }
4693         long newTimerID = OS.SetTimer (hwndMessage, timerId, milliseconds, 0);
4694         if (newTimerID != 0) {
4695                 timerList [index] = runnable;
4696                 timerIds [index] = newTimerID;
4697         }
4698 }
4699
4700 boolean translateAccelerator (MSG msg, Control control) {
4701         accelKeyHit = true;
4702         boolean result = control.translateAccelerator (msg);
4703         accelKeyHit = false;
4704         return result;
4705 }
4706
4707 static int translateKey (int key) {
4708         for (int i=0; i<KeyTable.length; i++) {
4709                 if (KeyTable [i] [0] == key) return KeyTable [i] [1];
4710         }
4711         return 0;
4712 }
4713
4714 boolean translateMnemonic (MSG msg, Control control) {
4715         switch (msg.message) {
4716                 case OS.WM_CHAR:
4717                 case OS.WM_SYSCHAR:
4718                         return control.translateMnemonic (msg);
4719         }
4720         return false;
4721 }
4722
4723 boolean translateTraversal (MSG msg, Control control) {
4724         switch (msg.message) {
4725                 case OS.WM_KEYDOWN:
4726                         switch ((int)msg.wParam) {
4727                                 case OS.VK_RETURN:
4728                                 case OS.VK_ESCAPE:
4729                                 case OS.VK_TAB:
4730                                 case OS.VK_UP:
4731                                 case OS.VK_DOWN:
4732                                 case OS.VK_LEFT:
4733                                 case OS.VK_RIGHT:
4734                                 case OS.VK_PRIOR:
4735                                 case OS.VK_NEXT:
4736                                         return control.translateTraversal (msg);
4737                         }
4738                         break;
4739                 case OS.WM_SYSKEYDOWN:
4740                         switch ((int)msg.wParam) {
4741                                 case OS.VK_MENU:
4742                                         return control.translateTraversal (msg);
4743                         }
4744                         break;
4745         }
4746         return false;
4747 }
4748
4749 static int untranslateKey (int key) {
4750         for (int i=0; i<KeyTable.length; i++) {
4751                 if (KeyTable [i] [1] == key) return KeyTable [i] [0];
4752         }
4753         return 0;
4754 }
4755
4756 /**
4757  * Forces all outstanding paint requests for the display
4758  * to be processed before this method returns.
4759  *
4760  * @exception SWTException <ul>
4761  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4762  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4763  * </ul>
4764  *
4765  * @see Control#update()
4766  */
4767 public void update() {
4768         checkDevice ();
4769         /*
4770         * Feature in Windows.  When an application does not remove
4771         * events from the event queue for some time, Windows assumes
4772         * the application is not responding and no longer sends paint
4773         * events to the application.  The fix is to detect that the
4774         * application is not responding and call PeekMessage() with
4775         * PM_REMOVE to tell Windows that the application is ready
4776         * to dispatch events.  Note that the message does not have
4777         * to be found or dispatched in order to wake Windows up.
4778         *
4779         * NOTE: This allows other cross thread messages to be delivered,
4780         * most notably WM_ACTIVATE.
4781         */
4782         if (OS.IsHungAppWindow (hwndMessage)) {
4783                 MSG msg = new MSG ();
4784                 int flags = OS.PM_REMOVE | OS.PM_NOYIELD;
4785                 OS.PeekMessage (msg, hwndMessage, SWT_NULL, SWT_NULL, flags);
4786         }
4787         Shell[] shells = getShells ();
4788         for (int i=0; i<shells.length; i++) {
4789                 Shell shell = shells [i];
4790                 if (!shell.isDisposed ()) shell.update (true);
4791         }
4792 }
4793
4794 /**
4795  * If the receiver's user-interface thread was <code>sleep</code>ing,
4796  * causes it to be awakened and start running again. Note that this
4797  * method may be called from any thread.
4798  *
4799  * @exception SWTException <ul>
4800  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4801  * </ul>
4802  *
4803  * @see #sleep
4804  */
4805 public void wake () {
4806         synchronized (Device.class) {
4807                 if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
4808                 if (thread == Thread.currentThread ()) return;
4809                 wakeThread ();
4810         }
4811 }
4812
4813 void wakeThread () {
4814         OS.PostThreadMessage (threadId, OS.WM_NULL, 0, 0);
4815 }
4816
4817 long windowProc (long hwnd, long msg, long wParam, long lParam) {
4818         if (lastControl != null && lastHwnd == hwnd) {
4819                 return lastControl.windowProc (hwnd, (int)msg, wParam, lParam);
4820         }
4821         int index = (int)OS.GetProp (hwnd, SWT_OBJECT_INDEX) - 1;
4822         if (0 <= index && index < controlTable.length) {
4823                 Control control = controlTable [index];
4824                 if (control != null) {
4825                         lastHwnd = hwnd;
4826                         lastControl = control;
4827                         return control.windowProc (hwnd, (int)msg, wParam, lParam);
4828                 }
4829         }
4830         return OS.DefWindowProc (hwnd, (int)msg, wParam, lParam);
4831 }
4832
4833 int textWidth (String text, long handle) {
4834         long oldFont = 0;
4835         RECT rect = new RECT ();
4836         long hDC = OS.GetDC (handle);
4837         long newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
4838         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
4839         int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
4840         char [] buffer = text.toCharArray ();
4841         OS.DrawText (hDC, buffer, buffer.length, rect, flags);
4842         if (newFont != 0) OS.SelectObject (hDC, oldFont);
4843         OS.ReleaseDC (handle, hDC);
4844         return (rect.right - rect.left);
4845 }
4846
4847 String wrapText (String text, long handle, int width) {
4848         String Lf = "\r\n"; //$NON-NLS-1$
4849         text = withCrLf (text);
4850         int length = text.length ();
4851         if (width <= 0 || length == 0 || length == 1) return text;
4852         StringBuilder result = new StringBuilder ();
4853         int lineStart = 0, lineEnd = 0;
4854         while (lineStart < length) {
4855                 lineEnd = text.indexOf (Lf, lineStart);
4856                 boolean noLf = lineEnd == -1;
4857                 if (noLf) lineEnd = length;
4858                 int nextStart = lineEnd + Lf.length ();
4859                 while (lineEnd > lineStart + 1 && Character.isWhitespace (text.charAt (lineEnd - 1))) {
4860                         lineEnd--;
4861                 }
4862                 int wordStart = lineStart, wordEnd = lineStart;
4863                 int i = lineStart;
4864                 while (i < lineEnd) {
4865                         int lastStart = wordStart, lastEnd = wordEnd;
4866                         wordStart = i;
4867                         while (i < lineEnd && !Character.isWhitespace (text.charAt (i))) {
4868                                 i++;
4869                         }
4870                         wordEnd = i - 1;
4871                         String line = text.substring (lineStart, wordEnd + 1);
4872                         int lineWidth = textWidth (line, handle);
4873                         while (i < lineEnd && Character.isWhitespace (text.charAt (i))) {
4874                                 i++;
4875                         }
4876                         if (lineWidth > width) {
4877                                 if (lastStart == wordStart) {
4878                                         while (wordStart < wordEnd) {
4879                                                 line = text.substring (lineStart, wordStart + 1);
4880                                                 lineWidth = textWidth (line, handle);
4881                                                 if (lineWidth >= width) break;
4882                                                 wordStart++;
4883                                         }
4884                                         if (wordStart == lastStart) wordStart++;
4885                                         lastEnd = wordStart - 1;
4886                                 }
4887                                 line = text.substring (lineStart, lastEnd + 1);
4888                                 result.append (line); result.append (Lf);
4889                                 i = wordStart; lineStart = wordStart; wordEnd = wordStart;
4890                         }
4891                 }
4892                 if (lineStart < lineEnd) {
4893                         result.append (text.substring (lineStart, lineEnd));
4894                 }
4895                 if (!noLf) {
4896                         result.append (Lf);
4897                 }
4898                 lineStart = nextStart;
4899         }
4900         return result.toString ();
4901 }
4902
4903 static String withCrLf (String string) {
4904
4905         /* If the string is empty, return the string. */
4906         int length = string.length ();
4907         if (length == 0) return string;
4908
4909         /*
4910         * Check for an LF or CR/LF and assume the rest of
4911         * the string is formated that way.  This will not
4912         * work if the string contains mixed delimiters.
4913         */
4914         int i = string.indexOf ('\n', 0);
4915         if (i == -1) return string;
4916         if (i > 0 && string.charAt (i - 1) == '\r') {
4917                 return string;
4918         }
4919
4920         /*
4921         * The string is formatted with LF.  Compute the
4922         * number of lines and the size of the buffer
4923         * needed to hold the result
4924         */
4925         i++;
4926         int count = 1;
4927         while (i < length) {
4928                 if ((i = string.indexOf ('\n', i)) == -1) break;
4929                 count++; i++;
4930         }
4931         count += length;
4932
4933         /* Create a new string with the CR/LF line terminator. */
4934         i = 0;
4935         StringBuilder result = new StringBuilder (count);
4936         while (i < length) {
4937                 int j = string.indexOf ('\n', i);
4938                 if (j == -1) j = length;
4939                 result.append (string.substring (i, j));
4940                 if ((i = j) < length) {
4941                         result.append ("\r\n"); //$NON-NLS-1$
4942                         i++;
4943                 }
4944         }
4945         return result.toString ();
4946 }
4947
4948 static char [] withCrLf (char [] string) {
4949         /* If the string is empty, return the string. */
4950         int length = string.length;
4951         if (length == 0) return string;
4952
4953         /*
4954         * Check for an LF or CR/LF and assume the rest of
4955         * the string is formated that way.  This will not
4956         * work if the string contains mixed delimiters.
4957         * Also, compute the number of lines.
4958         */
4959         int count = 0;
4960         for (int i = 0; i < string.length; i++) {
4961                 if (string [i] == '\n') {
4962                         count++;
4963                         if (count == 1 && i > 0 && string [i - 1] == '\r') return string;
4964                 }
4965         }
4966         if (count == 0) return string;
4967
4968         /*
4969         * The string is formatted with LF.
4970         */
4971         count += length;
4972
4973         /* Create a new string with the CR/LF line terminator. */
4974         char [] result = new char [count];
4975         for (int i = 0, j = 0; i < length && j < count; i++) {
4976                 if (string [i] == '\n') {
4977                         result [j++] = '\r';
4978                 }
4979                 result [j++] = string [i];
4980         }
4981
4982         return result;
4983 }
4984
4985 }