1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.widgets.Display;
14 
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.graphics.Color;
17 import org.eclipse.swt.graphics.Cursor;
18 import org.eclipse.swt.graphics.Device;
19 import org.eclipse.swt.graphics.DeviceData;
20 import org.eclipse.swt.graphics.Font;
21 import org.eclipse.swt.graphics.GCData;
22 import org.eclipse.swt.graphics.Image;
23 import org.eclipse.swt.graphics.ImageData;
24 import org.eclipse.swt.graphics.PaletteData;
25 import org.eclipse.swt.graphics.Point;
26 import org.eclipse.swt.graphics.Rectangle;
27 import org.eclipse.swt.graphics.Resource;
28 import org.eclipse.swt.internal.Compatibility;
29 import org.eclipse.swt.internal.Converter;
30 import org.eclipse.swt.internal.Lock;
31 import org.eclipse.swt.internal.LONG;
32 import org.eclipse.swt.internal.gtk.OS;
33 import org.eclipse.swt.widgets.Caret;
34 import org.eclipse.swt.widgets.Control;
35 import org.eclipse.swt.widgets.Dialog;
36 import org.eclipse.swt.widgets.Event;
37 import org.eclipse.swt.widgets.EventTable;
38 import org.eclipse.swt.widgets.Listener;
39 import org.eclipse.swt.widgets.Menu;
40 import org.eclipse.swt.widgets.Monitor;
41 import org.eclipse.swt.widgets.Shell;
42 import org.eclipse.swt.widgets.Synchronizer;
43 import org.eclipse.swt.widgets.Tray;
44 import org.eclipse.swt.widgets.Widget;
45 
46 import java.lang.all;
47 
48 import java.lang.Thread;
49 version(Tango){
50 import tango.stdc..string;
51 } else { // Phobos
52 }
53 
54 /**
55  * Instances of this class are responsible for managing the
56  * connection between SWT and the underlying operating
57  * system. Their most important function is to implement
58  * the SWT event loop in terms of the platform event model.
59  * They also provide various methods for accessing information
60  * about the operating system, and have overall control over
61  * the operating system resources which SWT allocates.
62  * <p>
63  * Applications which are built with SWT will <em>almost always</em>
64  * require only a single display. In particular, some platforms
65  * which SWT supports will not allow more than one <em>active</em>
66  * display. In other words, some platforms do not support
67  * creating a new display if one already exists that has not been
68  * sent the <code>dispose()</code> message.
69  * <p>
70  * In SWT, the thread which creates a <code>Display</code>
71  * instance is distinguished as the <em>user-interface thread</em>
72  * for that display.
73  * </p>
74  * The user-interface thread for a particular display has the
75  * following special attributes:
76  * <ul>
77  * <li>
78  * The event loop for that display must be run from the thread.
79  * </li>
80  * <li>
81  * Some SWT API methods (notably, most of the public methods in
82  * <code>Widget</code> and its subclasses), may only be called
83  * from the thread. (To support multi-threaded user-interface
84  * applications, class <code>Display</code> provides inter-thread
85  * communication methods which allow threads other than the
86  * user-interface thread to request that it perform operations
87  * on their behalf.)
88  * </li>
89  * <li>
90  * The thread is not allowed to construct other
91  * <code>Display</code>s until that display has been disposed.
92  * (Note that, this is in addition to the restriction mentioned
93  * above concerning platform support for multiple displays. Thus,
94  * the only way to have multiple simultaneously active displays,
95  * even on platforms which support it, is to have multiple threads.)
96  * </li>
97  * </ul>
98  * Enforcing these attributes allows SWT to be implemented directly
99  * on the underlying operating system's event model. This has
100  * numerous benefits including smaller footprint, better use of
101  * resources, safer memory management, clearer program logic,
102  * better performance, and fewer overall operating system threads
103  * required. The down side however, is that care must be taken
104  * (only) when constructing multi-threaded applications to use the
105  * inter-thread communication mechanisms which this class provides
106  * when required.
107  * </p><p>
108  * All SWT API methods which may only be called from the user-interface
109  * thread are distinguished in their documentation by indicating that
110  * they throw the "<code>ERROR_THREAD_INVALID_ACCESS</code>"
111  * SWT exception.
112  * </p>
113  * <dl>
114  * <dt><b>Styles:</b></dt>
115  * <dd>(none)</dd>
116  * <dt><b>Events:</b></dt>
117  * <dd>Close, Dispose, Settings</dd>
118  * </dl>
119  * <p>
120  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
121  * </p>
122  * @see #syncExec
123  * @see #asyncExec
124  * @see #wake
125  * @see #readAndDispatch
126  * @see #sleep
127  * @see Device#dispose
128  * @see <a href="http://www.eclipse.org/swt/snippets/#display">Display snippets</a>
129  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
130  */
131 public class Display : Device {
132 
133     /* Events Dispatching and Callback */
134     int gdkEventCount;
135     GdkEvent* [] gdkEvents;
136     Widget [] gdkEventWidgets;
137     int [] dispatchEvents;
138     Event [] eventQueue;
139     GPollFD[] fds;
140     int allocated_nfds;
141     bool wake_state;
142     int max_priority, timeout;
143     void*/*Callback*/ eventCallback, filterCallback;
144 
145     CallbackData*[int] windowProcCallbackDatas; // to prevent GC from collect
146 
147     CallbackData  filterProcCallbackData;
148     EventTable eventTable, filterTable;
149     static String APP_NAME = "SWT"; //$NON-NLS-1$
150     static const String DISPATCH_EVENT_KEY = "org.eclipse.swt.internal.gtk.dispatchEvent";
151     static const String ADD_WIDGET_KEY = "org.eclipse.swt.internal.addWidget";
152     GClosure*[] closures;
153     int [] signalIds;
154 
155     /* Widget Table */
156     ptrdiff_t [] indexTable;
157     ptrdiff_t freeSlot;
158     GtkWidget* lastHandle;
159     Widget lastWidget;
160     Widget [] widgetTable;
161     const static int GROW_SIZE = 1024;
162     static int SWT_OBJECT_INDEX;
163     static int SWT_OBJECT_INDEX1;
164     static int SWT_OBJECT_INDEX2;
165 
166     /* Modality */
167     Shell [] modalShells;
168     Dialog modalDialog;
169     static const String GET_MODAL_DIALOG = "org.eclipse.swt.internal.gtk.getModalDialog"; //$NON-NLS-1$
170     static const String SET_MODAL_DIALOG = "org.eclipse.swt.internal.gtk.setModalDialog"; //$NON-NLS-1$
171 
172     /* Focus */
173     int focusEvent;
174     Control focusControl;
175     Shell activeShell;
176     bool activePending;
177     bool ignoreActivate, ignoreFocus;
178 
179     /* Input method resources */
180     Control imControl;
181     GtkWindow* preeditWindow;
182     GtkLabel* preeditLabel;
183 
184     /* Sync/Async Widget Communication */
185     Synchronizer synchronizer;
186     Thread thread;
187 
188     /* Display Shutdown */
189     Runnable [] disposeList;
190 
191     /* System Tray */
192     Tray tray;
193 
194     /* Timers */
195     int [] timerIds;
196     Runnable [] timerList;
197     CallbackData timerProcCallbackData;
198 
199     /* Caret */
200     Caret currentCaret;
201     int caretId;
202     CallbackData caretProcCallbackData;
203 
204     /* Mnemonics */
205     Control mnemonicControl;
206 
207     /* Mouse hover */
208     int mouseHoverId;
209     GtkWidget* mouseHoverHandle;
210     CallbackData mouseHoverProcCallbackData;
211 
212     /* Menu position callback */
213 
214     /* Tooltip size allocate callback */
215 
216     /* Shell map callback */
217     CallbackData shellMapProcCallbackData;
218     GClosure* shellMapProcClosure;
219 
220     /* Idle proc callback */
221     CallbackData idleProcCallbackData;
222     uint idleHandle;
223     static const String ADD_IDLE_PROC_KEY = "org.eclipse.swt.internal.gtk.addIdleProc";
224     static const String REMOVE_IDLE_PROC_KEY = "org.eclipse.swt.internal.gtk.removeIdleProc";
225     Object idleLock;
226     bool idleNeeded;
227 
228     /* GtkTreeView callbacks */
229     int[] treeSelection;
230     int treeSelectionLength;
231 
232     /* Set direction callback */
233     CallbackData setDirectionProcCallbackData;
234     static const String GET_DIRECTION_PROC_KEY = "org.eclipse.swt.internal.gtk.getDirectionProc"; //$NON-NLS-1$
235 
236     /* Set emissionProc callback */
237     CallbackData emissionProcCallbackData;
238     static const String GET_EMISSION_PROC_KEY = "org.eclipse.swt.internal.gtk.getEmissionProc"; //$NON-NLS-1$
239 
240     /* Get all children callback */
241     CallbackData allChildrenProcCallbackData;
242     GList* allChildren;
243 
244     CallbackData cellDataProcCallbackData;
245 
246     /* Settings callbacks */
247     GtkWidget* shellHandle;
248     bool settingsChanged, runSettingsFld;
249     CallbackData styleSetProcCallbackData;
250 
251     /* Entry focus behaviour */
252     bool entrySelectOnFocus;
253 
254     /* Enter/Exit events */
255     Control currentControl;
256 
257     /* Flush exposes */
258     int checkIfEventProc;
259     void*/*Callback*/ checkIfEventCallback;
260     GdkWindow* flushWindow;
261     bool flushAll;
262     GdkRectangle* flushRect;
263     XExposeEvent* exposeEvent;
264     XVisibilityEvent* visibilityEvent;
265     //int [] flushData = new int [1];
266 
267     /* System Resources */
268     Font systemFont;
269     Image errorImage, infoImage, questionImage, warningImage;
270     Cursor [] cursors;
271     Resource [] resources;
272     static const int RESOURCE_SIZE = 1 + 4 + SWT.CURSOR_HAND + 1;
273 
274     /* Colors */
275     GdkColor* COLOR_WIDGET_DARK_SHADOW, COLOR_WIDGET_NORMAL_SHADOW, COLOR_WIDGET_LIGHT_SHADOW;
276     GdkColor* COLOR_WIDGET_HIGHLIGHT_SHADOW, COLOR_WIDGET_BACKGROUND, COLOR_WIDGET_FOREGROUND, COLOR_WIDGET_BORDER;
277     GdkColor* COLOR_LIST_FOREGROUND, COLOR_LIST_BACKGROUND, COLOR_LIST_SELECTION, COLOR_LIST_SELECTION_TEXT;
278     GdkColor* COLOR_INFO_BACKGROUND, COLOR_INFO_FOREGROUND;
279     GdkColor* COLOR_TITLE_FOREGROUND, COLOR_TITLE_BACKGROUND, COLOR_TITLE_BACKGROUND_GRADIENT;
280     GdkColor* COLOR_TITLE_INACTIVE_FOREGROUND, COLOR_TITLE_INACTIVE_BACKGROUND, COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT;
281 
282     /* Popup Menus */
283     Menu [] popups;
284 
285     /* Click count*/
286     int clickCount = 1;
287 
288     /* Timestamp of the Last Received Events */
289     int lastEventTime, lastUserEventTime;
290 
291     /* Fixed Subclass */
292     static ptrdiff_t fixed_type;
293     static ptrdiff_t fixed_info_ptr;
294     static extern(C) void function(GtkWidget* handle, GtkAllocation* allocation) oldFixedSizeAllocateProc;
295 
296 
297     /* Renderer Subclass */
298     static ptrdiff_t text_renderer_type, pixbuf_renderer_type, toggle_renderer_type;
299     static ptrdiff_t text_renderer_info_ptr, pixbuf_renderer_info_ptr, toggle_renderer_info_ptr;
300 
301     /* Key Mappings */
302     static const int [] [] KeyTable = [
303 
304         /* Keyboard and Mouse Masks */
305         [OS.GDK_Alt_L,      SWT.ALT],
306         [OS.GDK_Alt_R,      SWT.ALT],
307         [OS.GDK_Meta_L, SWT.ALT],
308         [OS.GDK_Meta_R, SWT.ALT],
309         [OS.GDK_Shift_L,        SWT.SHIFT],
310         [OS.GDK_Shift_R,        SWT.SHIFT],
311         [OS.GDK_Control_L,  SWT.CONTROL],
312         [OS.GDK_Control_R,  SWT.CONTROL],
313 //      [OS.GDK_????,       SWT.COMMAND],
314 //      [OS.GDK_????,       SWT.COMMAND],
315 
316         /* Non-Numeric Keypad Keys */
317         [OS.GDK_Up,                     SWT.ARROW_UP],
318         [OS.GDK_KP_Up,                  SWT.ARROW_UP],
319         [OS.GDK_Down,                   SWT.ARROW_DOWN],
320         [OS.GDK_KP_Down,            SWT.ARROW_DOWN],
321         [OS.GDK_Left,                       SWT.ARROW_LEFT],
322         [OS.GDK_KP_Left,                SWT.ARROW_LEFT],
323         [OS.GDK_Right,                  SWT.ARROW_RIGHT],
324         [OS.GDK_KP_Right,               SWT.ARROW_RIGHT],
325         [OS.GDK_Page_Up,                SWT.PAGE_UP],
326         [OS.GDK_KP_Page_Up,     SWT.PAGE_UP],
327         [OS.GDK_Page_Down,          SWT.PAGE_DOWN],
328         [OS.GDK_KP_Page_Down,   SWT.PAGE_DOWN],
329         [OS.GDK_Home,                   SWT.HOME],
330         [OS.GDK_KP_Home,            SWT.HOME],
331         [OS.GDK_End,                        SWT.END],
332         [OS.GDK_KP_End,             SWT.END],
333         [OS.GDK_Insert,                 SWT.INSERT],
334         [OS.GDK_KP_Insert,          SWT.INSERT],
335 
336         /* Virtual and Ascii Keys */
337         [OS.GDK_BackSpace,      SWT.BS],
338         [OS.GDK_Return,             SWT.CR],
339         [OS.GDK_Delete,             SWT.DEL],
340         [OS.GDK_KP_Delete,      SWT.DEL],
341         [OS.GDK_Escape,         SWT.ESC],
342         [OS.GDK_Linefeed,           SWT.LF],
343         [OS.GDK_Tab,                    SWT.TAB],
344         [OS.GDK_ISO_Left_Tab,   SWT.TAB],
345 
346         /* Functions Keys */
347         [OS.GDK_F1,     SWT.F1],
348         [OS.GDK_F2,     SWT.F2],
349         [OS.GDK_F3,     SWT.F3],
350         [OS.GDK_F4,     SWT.F4],
351         [OS.GDK_F5,     SWT.F5],
352         [OS.GDK_F6,     SWT.F6],
353         [OS.GDK_F7,     SWT.F7],
354         [OS.GDK_F8,     SWT.F8],
355         [OS.GDK_F9,     SWT.F9],
356         [OS.GDK_F10,        SWT.F10],
357         [OS.GDK_F11,        SWT.F11],
358         [OS.GDK_F12,        SWT.F12],
359         [OS.GDK_F13,        SWT.F13],
360         [OS.GDK_F14,        SWT.F14],
361         [OS.GDK_F15,        SWT.F15],
362 
363         /* Numeric Keypad Keys */
364         [OS.GDK_KP_Multiply,        SWT.KEYPAD_MULTIPLY],
365         [OS.GDK_KP_Add,         SWT.KEYPAD_ADD],
366         [OS.GDK_KP_Enter,           SWT.KEYPAD_CR],
367         [OS.GDK_KP_Subtract,    SWT.KEYPAD_SUBTRACT],
368         [OS.GDK_KP_Decimal, SWT.KEYPAD_DECIMAL],
369         [OS.GDK_KP_Divide,      SWT.KEYPAD_DIVIDE],
370         [OS.GDK_KP_0,           SWT.KEYPAD_0],
371         [OS.GDK_KP_1,           SWT.KEYPAD_1],
372         [OS.GDK_KP_2,           SWT.KEYPAD_2],
373         [OS.GDK_KP_3,           SWT.KEYPAD_3],
374         [OS.GDK_KP_4,           SWT.KEYPAD_4],
375         [OS.GDK_KP_5,           SWT.KEYPAD_5],
376         [OS.GDK_KP_6,           SWT.KEYPAD_6],
377         [OS.GDK_KP_7,           SWT.KEYPAD_7],
378         [OS.GDK_KP_8,           SWT.KEYPAD_8],
379         [OS.GDK_KP_9,           SWT.KEYPAD_9],
380         [OS.GDK_KP_Equal,   SWT.KEYPAD_EQUAL],
381 
382         /* Other keys */
383         [OS.GDK_Caps_Lock,      SWT.CAPS_LOCK],
384         [OS.GDK_Num_Lock,       SWT.NUM_LOCK],
385         [OS.GDK_Scroll_Lock,        SWT.SCROLL_LOCK],
386         [OS.GDK_Pause,              SWT.PAUSE],
387         [OS.GDK_Break,              SWT.BREAK],
388         [OS.GDK_Print,                  SWT.PRINT_SCREEN],
389         [OS.GDK_Help,                   SWT.HELP],
390 
391     ];
392 
393     /* Multiple Displays. */
394     static Display Default;
395     static Display [] Displays;
396 
397     /* Package name */
398     static const String PACKAGE_PREFIX = "org.eclipse.swt.widgets.";
399     /* This code is intentionally commented.
400      * ".class" can not be used on CLDC.
401      */
402 //  static {
403 //      String name = Display.class.getName ();
404 //      int index = name.lastIndexOf ('.');
405 //      PACKAGE_NAME = name.substring (0, index + 1);
406 //  }
407 
408     static this() {
409         Displays = new Display [4];
410         initDeviceFinder();
411         SWT_OBJECT_INDEX = OS.g_quark_from_string ("SWT_OBJECT_INDEX");
412         SWT_OBJECT_INDEX1 = OS.g_quark_from_string ("SWT_OBJECT_INDEX1");
413         SWT_OBJECT_INDEX2 = OS.g_quark_from_string ("SWT_OBJECT_INDEX2");
414     }
415 
416     /* GTK Version */
417     static const int MAJOR = 2;
418     static const int MINOR = 0;
419     static const int MICRO = 6;
420 
421     /* Display Data */
422     Object data;
423     String [] keys;
424     Object [] values;
425 
426     /* Initial Guesses for Shell Trimmings. */
427     int borderTrimWidth = 4, borderTrimHeight = 4;
428     int resizeTrimWidth = 6, resizeTrimHeight = 6;
429     int titleBorderTrimWidth = 5, titleBorderTrimHeight = 28;
430     int titleResizeTrimWidth = 6, titleResizeTrimHeight = 29;
431     int titleTrimWidth = 0, titleTrimHeight = 23;
432     bool ignoreTrim;
433 
434     /* Window Manager */
435     String windowManager;
436 
437     /*
438     * TEMPORARY CODE.  Install the runnable that
439     * gets the current display. This code will
440     * be removed in the future.
441     */
442     private static void initDeviceFinder(){
443         DeviceFinder = new class() Runnable {
444             public void run () {
445                 Device device = getCurrent ();
446                 if (device is null) {
447                     device = getDefault ();
448                 }
449                 setDevice (device);
450             }
451         };
452     }
453 
454 /*
455 * TEMPORARY CODE.
456 */
457 static void setDevice (Device device) {
458     CurrentDevice = device;
459 }
460 
461 /**
462  * Constructs a new instance of this class.
463  * <p>
464  * Note: The resulting display is marked as the <em>current</em>
465  * display. If this is the first display which has been
466  * constructed since the application started, it is also
467  * marked as the <em>default</em> display.
468  * </p>
469  *
470  * @exception SWTException <ul>
471  *    <li>ERROR_THREAD_INVALID_ACCESS - if called from a thread that already created an existing display</li>
472  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
473  * </ul>
474  *
475  * @see #getCurrent
476  * @see #getDefault
477  * @see Widget#checkSubclass
478  * @see Shell
479  */
480 public this () {
481     this (null);
482 }
483 
484 /**
485  * Constructs a new instance of this class using the parameter.
486  *
487  * @param data the device data
488  */
489 public this (DeviceData data) {
490     super (data);
491     synchronizer = new Synchronizer (this);
492     idleLock = new Object();
493     flushRect = new GdkRectangle ();
494     exposeEvent = new XExposeEvent ();
495     visibilityEvent = new XVisibilityEvent ();
496     cursors = new Cursor [SWT.CURSOR_HAND + 1];
497 }
498 
499 /**
500  * Adds the listener to the collection of listeners who will
501  * be notified when an event of the given type occurs anywhere
502  * in a widget. The event type is one of the event constants
503  * defined in class <code>SWT</code>. When the event does occur,
504  * the listener is notified by sending it the <code>handleEvent()</code>
505  * message.
506  * <p>
507  * Setting the type of an event to <code>SWT.None</code> from
508  * within the <code>handleEvent()</code> method can be used to
509  * change the event type and stop subsequent Java listeners
510  * from running. Because event filters run before other listeners,
511  * event filters can both block other listeners and set arbitrary
512  * fields within an event. For this reason, event filters are both
513  * powerful and dangerous. They should generally be avoided for
514  * performance, debugging and code maintenance reasons.
515  * </p>
516  *
517  * @param eventType the type of event to listen for
518  * @param listener the listener which should be notified when the event occurs
519  *
520  * @exception IllegalArgumentException <ul>
521  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
522  * </ul>
523  * @exception SWTException <ul>
524  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
525  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
526  * </ul>
527  *
528  * @see Listener
529  * @see SWT
530  * @see #removeFilter
531  * @see #removeListener
532  *
533  * @since 3.0
534  */
535 public void addFilter (int eventType, Listener listener) {
536     checkDevice ();
537     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
538     if (filterTable is null) filterTable = new EventTable ();
539     filterTable.hook (eventType, listener);
540 }
541 
542 void addGdkEvent (GdkEvent* event) {
543     if (gdkEvents is null) {
544         int length = GROW_SIZE;
545         gdkEvents.length = length;
546         gdkEventWidgets.length = length;
547         gdkEventCount = 0;
548     }
549     if (gdkEventCount is gdkEvents.length) {
550         int length = gdkEventCount + GROW_SIZE;
551         GdkEvent* [] newEvents = new GdkEvent* [length];
552         SimpleType!(GdkEvent*).arraycopy (gdkEvents, 0, newEvents, 0, gdkEventCount);
553         gdkEvents = newEvents;
554         Widget [] newWidgets = new Widget [length];
555         System.arraycopy (gdkEventWidgets, 0, newWidgets, 0, gdkEventCount);
556         gdkEventWidgets = newWidgets;
557     }
558     Widget widget = null;
559     GtkWidget* handle = OS.gtk_get_event_widget (event);
560     if (handle !is null) {
561         do {
562             widget = getWidget (handle);
563         } while (widget is null && (handle = OS.gtk_widget_get_parent (handle)) !is null);
564     }
565     gdkEvents [gdkEventCount] = event;
566     gdkEventWidgets [gdkEventCount] = widget;
567     gdkEventCount++;
568 }
569 
570 void addIdleProc() {
571     synchronized (idleLock){
572         this.idleNeeded = true;
573         if (idleHandle is 0) {
574             idleProcCallbackData.display = this;
575             idleProcCallbackData.data = null;
576             idleHandle = OS.g_idle_add ( &idleProcFunc, &idleProcCallbackData );
577         }
578     }
579 }
580 
581 /**
582  * Adds the listener to the collection of listeners who will
583  * be notified when an event of the given type occurs. The event
584  * type is one of the event constants defined in class <code>SWT</code>.
585  * When the event does occur in the display, the listener is notified by
586  * sending it the <code>handleEvent()</code> message.
587  *
588  * @param eventType the type of event to listen for
589  * @param listener the listener which should be notified when the event occurs
590  *
591  * @exception IllegalArgumentException <ul>
592  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
593  * </ul>
594  * @exception SWTException <ul>
595  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
596  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
597  * </ul>
598  *
599  * @see Listener
600  * @see SWT
601  * @see #removeListener
602  *
603  * @since 2.0
604  */
605 public void addListener (int eventType, Listener listener) {
606     checkDevice ();
607     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
608     if (eventTable is null) eventTable = new EventTable ();
609     eventTable.hook (eventType, listener);
610 }
611 
612 void allChildrenCollect( GtkWidget* widget, int recurse ){
613     allChildrenProcCallbackData.display = this;
614     allChildrenProcCallbackData.data = cast(void*)recurse;
615     OS.gtk_container_forall (cast(GtkContainer*)widget, cast(GtkCallback)&allChildrenProcFunc, &allChildrenProcCallbackData);
616 }
617 private static extern(C) ptrdiff_t allChildrenProcFunc (GtkWidget* handle, void* user_data) {
618     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
619     CallbackData* cbdata = cast(CallbackData*)user_data;
620     return cbdata.display.allChildrenProc( cast(GtkWidget*)handle, cast(int)cbdata.data );
621 }
622 ptrdiff_t allChildrenProc (GtkWidget* widget, ptrdiff_t recurse) {
623     allChildren = OS.g_list_append (allChildren, widget);
624     if (recurse !is 0 && OS.GTK_IS_CONTAINER (cast(GTypeInstance*)widget)) {
625         allChildrenProcCallbackData.display = this;
626         allChildrenProcCallbackData.data = cast(void*)recurse;
627         OS.gtk_container_forall (cast(GtkContainer*)widget, cast(GtkCallback)&allChildrenProcFunc, &allChildrenProcCallbackData);
628     }
629     return 0;
630 }
631 
632 void addMouseHoverTimeout (GtkWidget* handle) {
633     if (mouseHoverId !is 0) OS.gtk_timeout_remove (mouseHoverId);
634     mouseHoverProcCallbackData.display = this;
635     mouseHoverProcCallbackData.data = cast(void*)handle;
636     mouseHoverId = OS.gtk_timeout_add (400, &mouseHoverProcFunc, &mouseHoverProcCallbackData);
637     mouseHoverHandle = handle;
638 }
639 
640 void addPopup (Menu menu) {
641     if (popups is null) popups = new Menu [4];
642     ptrdiff_t length = popups.length;
643     for (int i=0; i<length; i++) {
644         if (popups [i] is menu) return;
645     }
646     int index = 0;
647     while (index < length) {
648         if (popups [index] is null) break;
649         index++;
650     }
651     if (index is length) {
652         Menu [] newPopups = new Menu [length + 4];
653         System.arraycopy (popups, 0, newPopups, 0, length);
654         popups = newPopups;
655     }
656     popups [index] = menu;
657 }
658 
659 void addWidget (GtkWidget* handle, Widget widget) {
660     if (handle is null) return;
661     if (freeSlot is -1) {
662         ptrdiff_t len = freeSlot = indexTable.length + GROW_SIZE;
663         ptrdiff_t[] newIndexTable = new ptrdiff_t[len];
664         Widget[] newWidgetTable = new Widget [len];
665         System.arraycopy (indexTable, 0, newIndexTable, 0, freeSlot);
666         System.arraycopy (widgetTable, 0, newWidgetTable, 0, freeSlot);
667         for (ptrdiff_t i = freeSlot; i < len - 1; i++) {
668             newIndexTable[i] = i + 1;
669         }
670         newIndexTable[len - 1] = -1;
671         indexTable = newIndexTable;
672         widgetTable = newWidgetTable;
673     }
674     ptrdiff_t index = freeSlot + 1;
675     OS.g_object_set_qdata (cast(GObject*)handle, SWT_OBJECT_INDEX, cast(void*)index);
676     ptrdiff_t oldSlot = freeSlot;
677     freeSlot = indexTable[oldSlot];
678     indexTable [oldSlot] = -2;
679     widgetTable [oldSlot] = widget;
680 }
681 
682 /**
683  * Causes the <code>run()</code> method of the runnable to
684  * be invoked by the user-interface thread at the next
685  * reasonable opportunity. The caller of this method continues
686  * to run in parallel, and is not notified when the
687  * runnable has completed.  Specifying <code>null</code> as the
688  * runnable simply wakes the user-interface thread when run.
689  * <p>
690  * Note that at the time the runnable is invoked, widgets
691  * that have the receiver as their display may have been
692  * disposed. Therefore, it is necessary to check for this
693  * case inside the runnable before accessing the widget.
694  * </p>
695  *
696  * @param runnable code to run on the user-interface thread or <code>null</code>
697  *
698  * @exception SWTException <ul>
699  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
700  * </ul>
701  *
702  * @see #syncExec
703  */
704 public void asyncExec (Runnable runnable) {
705     synchronized (Device.classinfo) {
706         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
707         synchronized (idleLock) {
708             if (idleNeeded && idleHandle is 0) {
709                 //NOTE: calling unlocked function in OS
710                 idleHandle = OS.g_idle_add (&idleProcFunc, cast(void*) this);
711             }
712         }
713         synchronizer.asyncExec (runnable);
714     }
715 }
716 
717 /**
718  * Causes the system hardware to emit a short sound
719  * (if it supports this capability).
720  *
721  * @exception SWTException <ul>
722  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
723  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
724  * </ul>
725  */
726 public void beep () {
727     if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
728     OS.gdk_beep();
729     if (!OS.GDK_WINDOWING_X11 ()) {
730         OS.gdk_flush ();
731     } else {
732         void* xDisplay = OS.GDK_DISPLAY ();
733         OS.XFlush (xDisplay);
734     }
735 }
736 
737 void doCellDataProc( GtkWidget* widget, GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer ){
738     cellDataProcCallbackData.display = this;
739     cellDataProcCallbackData.data = widget;
740     OS.gtk_tree_view_column_set_cell_data_func ( tree_column, cell_renderer, &cellDataProcFunc, &cellDataProcCallbackData, null );
741 }
742 
743 private static extern(C) void cellDataProcFunc (
744     GtkTreeViewColumn *tree_column,
745     GtkCellRenderer *cell,
746     GtkTreeModel *tree_model,
747     GtkTreeIter *iter,
748     void* data)
749 {
750     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
751     CallbackData* cbdata = cast(CallbackData*)data;
752     return cbdata.display.cellDataProc( tree_column, cell, tree_model, iter, cbdata.data );
753 }
754 
755 void cellDataProc(
756     GtkTreeViewColumn *tree_column,
757     GtkCellRenderer *cell,
758     GtkTreeModel *tree_model,
759     GtkTreeIter *iter,
760     void* data)
761 {
762     Widget widget = getWidget (cast(GtkWidget*)data);
763     if (widget is null) return;
764     widget.cellDataProc (tree_column, cell, tree_model, iter, data);
765 }
766 
767 protected override void checkDevice () {
768     if (thread is null) error (SWT.ERROR_WIDGET_DISPOSED);
769     if (thread !is Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
770     if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
771 }
772 
773 static void checkDisplay (Thread thread, bool multiple) {
774     synchronized (Device.classinfo) {
775         for (int i=0; i<Displays.length; i++) {
776             if (Displays [i] !is null) {
777                 if (!multiple) SWT.error (SWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]"); //$NON-NLS-1$
778                 if (Displays [i].thread is thread) SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS);
779             }
780         }
781     }
782 }
783 
784 private static extern(C) int checkIfEventProcFunc (void* display, XEvent* xEvent, char* userData) {
785     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
786     auto disp = cast(Display)userData;
787     return disp.checkIfEventProcMeth( display, xEvent );
788 }
789 
790 int checkIfEventProcMeth (void* display, XEvent* xEvent) {
791     ptrdiff_t type = xEvent.type;
792     switch (type) {
793         case OS.VisibilityNotify:
794         case OS.Expose:
795         case OS.GraphicsExpose:
796             break;
797         default:
798             return 0;
799     }
800     GdkWindow* window = OS.gdk_window_lookup ( cast(void*)xEvent.xany.window );
801     if (window is null) return 0;
802     if (flushWindow !is null) {
803         if (flushAll) {
804             auto tempWindow = window;
805             do {
806                 if (tempWindow is flushWindow) break;
807             } while ((tempWindow = OS.gdk_window_get_parent (tempWindow)) !is null);
808             if (tempWindow !is flushWindow) return 0;
809         } else {
810             if (window !is flushWindow) return 0;
811         }
812     }
813     *exposeEvent = *cast(XExposeEvent*)xEvent;
814     Widget widget = null;
815     GtkWidget* handle = null;
816     switch (type) {
817         case OS.Expose:
818         case OS.GraphicsExpose: {
819             flushRect.x = exposeEvent.x;
820             flushRect.y = exposeEvent.y;
821             flushRect.width = exposeEvent.width;
822             flushRect.height = exposeEvent.height;
823             OS.gdk_window_invalidate_rect (window, flushRect, true);
824             exposeEvent.type = -1;
825             OS.memmove (xEvent, exposeEvent, XExposeEvent.sizeof);
826             break;
827         }
828         case OS.VisibilityNotify: {
829             OS.memmove (visibilityEvent, xEvent, XVisibilityEvent.sizeof);
830             OS.gdk_window_get_user_data (window, cast(void**) & handle);
831             widget = handle !is null ? getWidget (handle) : null;
832             if (auto control = cast(Control)widget ) {
833                 if (window is control.paintWindow ()) {
834                     if (visibilityEvent.state is OS.VisibilityFullyObscured) {
835                         control.state |= Widget.OBSCURED;
836                     } else {
837                         control.state &= ~Widget.OBSCURED;
838                     }
839                 }
840             }
841             break;
842         default:
843         }
844     }
845     return 0;
846 }
847 
848 /**
849  * Checks that this class can be subclassed.
850  * <p>
851  * IMPORTANT: See the comment in <code>Widget.checkSubclass()</code>.
852  * </p>
853  *
854  * @exception SWTException <ul>
855  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
856  * </ul>
857  *
858  * @see Widget#checkSubclass
859  */
860 protected void checkSubclass () {
861 //PORTING_TODO  if (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
862 }
863 
864 void clearModal (Shell shell) {
865     if (modalShells is null) return;
866     ptrdiff_t index = 0, length_ = modalShells.length;
867     while (index < length_) {
868         if (modalShells [index] is shell) break;
869         if (modalShells [index] is null) return;
870         index++;
871     }
872     if (index is length_) return;
873     System.arraycopy (modalShells, index + 1, modalShells, index, --length_ - index);
874     modalShells [length_] = null;
875     if (index is 0 && modalShells [0] is null) modalShells = null;
876     Shell [] shells = getShells ();
877     for (int i=0; i<shells.length; i++) shells [i].updateModal ();
878 }
879 
880 /**
881  * Requests that the connection between SWT and the underlying
882  * operating system be closed.
883  *
884  * @exception SWTException <ul>
885  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
886  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
887  * </ul>
888  *
889  * @see Device#dispose
890  *
891  * @since 2.0
892  */
893 public void close () {
894     checkDevice ();
895     Event event = new Event ();
896     sendEvent (SWT.Close, event);
897     if (event.doit) dispose ();
898 }
899 
900 /**
901  * Creates the device in the operating system.  If the device
902  * does not have a handle, this method may do nothing depending
903  * on the device.
904  * <p>
905  * This method is called before <code>init</code>.
906  * </p>
907  *
908  * @param data the DeviceData which describes the receiver
909  *
910  * @see #init
911  */
912 protected override void create (DeviceData data) {
913     checkSubclass ();
914     checkDisplay(thread = Thread.currentThread (), false);
915     createDisplay (data);
916     register (this);
917     if (Default is null) Default = this;
918 }
919 
920 private static extern(C) int XErrorHandler( void*, XErrorEvent* ){
921     getDwtLogger().error ( __FILE__, __LINE__, "*** XError" );
922     byte* p;
923     *p = 3;
924     return 0;
925 }
926 
927 void createDisplay (DeviceData data) {
928     /* Required for g_main_context_wakeup */
929     if (!OS.g_thread_supported ()) {
930         OS.g_thread_init (null);
931     }
932     OS.gtk_set_locale();
933     int cnt = 2;
934     auto args = [ "name".ptr, "--sync".ptr, "".ptr ];
935     auto a = args.ptr;
936     if (!OS.gtk_init_check (&cnt, &a )) {
937     }
938     assert( cnt is 1 );
939     if (OS.GDK_WINDOWING_X11 ()) xDisplay = cast(void*) OS.GDK_DISPLAY ();
940 
941     OS.XSetErrorHandler( &Display.XErrorHandler );
942     char* ptr = OS.gtk_check_version (MAJOR, MINOR, MICRO);
943     if (ptr !is null) {
944         char [] buffer = fromStringz(ptr);
945         getDwtLogger().warn (__FILE__, __LINE__,"***WARNING: {}", buffer );
946         getDwtLogger().warn (__FILE__, __LINE__,"***WARNING: SWT requires GTK {}.{}.{}", MAJOR, MINOR, MICRO );
947         ptrdiff_t major = OS.gtk_major_version (), minor = OS.gtk_minor_version (), micro = OS.gtk_micro_version ();
948         getDwtLogger().warn (__FILE__, __LINE__,"***WARNING: Detected: {}.{}.{}", major, minor, micro);
949     }
950     if (fixed_type is 0) {
951         GTypeInfo* fixed_info = new GTypeInfo ();
952         fixed_info.class_size = GtkFixedClass.sizeof;
953         fixed_info.class_init = & fixedClassInitProcFunc;
954         fixed_info.instance_size = GtkFixed.sizeof;
955         fixed_type = OS.g_type_register_static (OS.GTK_TYPE_FIXED (), "SwtFixed".ptr, fixed_info, 0);
956     }
957     if (text_renderer_type is 0) {
958         GTypeInfo* renderer_info = new GTypeInfo ();
959         renderer_info.class_size = GtkCellRendererTextClass.sizeof;
960         renderer_info.class_init = & rendererClassInitProcFunc;
961         renderer_info.instance_size = GtkCellRendererText.sizeof;
962         text_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_TEXT (), "SwtTextRenderer".ptr, renderer_info, 0);
963     }
964     if (pixbuf_renderer_type is 0) {
965         GTypeInfo* renderer_info = new GTypeInfo ();
966         renderer_info.class_size = GtkCellRendererPixbufClass.sizeof;
967         renderer_info.class_init = & rendererClassInitProcFunc;
968         renderer_info.instance_size = GtkCellRendererPixbuf.sizeof;
969         pixbuf_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_PIXBUF (), "SwtPixbufRenderer".ptr, renderer_info, 0);
970     }
971     if (toggle_renderer_type is 0) {
972         GTypeInfo* renderer_info = new GTypeInfo ();
973         renderer_info.class_size = GtkCellRendererToggleClass.sizeof;
974         renderer_info.class_init = & rendererClassInitProcFunc;
975         renderer_info.instance_size = GtkCellRendererToggle.sizeof;
976         toggle_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_TOGGLE (), "SwtToggleRenderer".ptr, renderer_info, 0);
977     }
978 
979     OS.gtk_widget_set_default_direction (OS.GTK_TEXT_DIR_LTR);
980     OS.gdk_rgb_init ();
981     char* p = toStringz(APP_NAME);
982     OS.g_set_prgname (p);
983     OS.gdk_set_program_class (p);
984     OS.gtk_rc_parse_string ("style \"swt-flat\" { GtkToolbar::shadow-type = none } widget \"*.swt-toolbar-flat\" style : highest \"swt-flat\"".ptr);
985 
986     /* Initialize the hidden shell */
987     shellHandle = OS.gtk_window_new (OS.GTK_WINDOW_TOPLEVEL);
988     if (shellHandle is null) SWT.error (SWT.ERROR_NO_HANDLES);
989     OS.gtk_widget_realize (shellHandle);
990 
991     /* Initialize the filter and event callback */
992     OS.gdk_event_handler_set (&eventProcFunc, cast(void*)this, null);
993     //filterProcCallbackData.display = this;
994     //filterProcCallbackData.data = null;
995     //OS.gdk_window_add_filter  (null, &filterProcFunc, cast(void*)&filterProcCallbackData );
996     doWindowAddFilter( &filterProcCallbackData, null, null );
997 }
998 
999 /*
1000  * Used by Shell
1001  */
1002 package void doWindowAddFilter( CallbackData* cbdata, GdkWindow* window, GtkWidget* widget ){
1003     cbdata.display = this;
1004     cbdata.data = widget;
1005     OS.gdk_window_add_filter (window, &filterProcFunc, cbdata );
1006 }
1007 
1008 package void doWindowRemoveFilter( CallbackData* cbdata, GdkWindow* window, GtkWidget* widget ){
1009     cbdata.display = this;
1010     cbdata.data = widget;
1011     OS.gdk_window_remove_filter(window, &filterProcFunc, cbdata );
1012 }
1013 
1014 Image createImage (String name) {
1015     auto style = OS.gtk_widget_get_default_style ();
1016     String buffer = name;
1017     auto pixbuf = OS.gtk_icon_set_render_icon (
1018         OS.gtk_icon_factory_lookup_default (buffer.ptr), style,
1019         OS.GTK_TEXT_DIR_NONE,
1020         OS.GTK_STATE_NORMAL,
1021         OS.GTK_ICON_SIZE_DIALOG, null, null );
1022     if (pixbuf is null) return null;
1023     int width = OS.gdk_pixbuf_get_width (pixbuf);
1024     int height = OS.gdk_pixbuf_get_height (pixbuf);
1025     int stride = OS.gdk_pixbuf_get_rowstride (pixbuf);
1026     bool hasAlpha = cast(bool)OS.gdk_pixbuf_get_has_alpha (pixbuf);
1027     char* pixels = OS.gdk_pixbuf_get_pixels (pixbuf);
1028     byte [] data = new byte [stride * height];
1029     OS.memmove (data.ptr, pixels, data.length);
1030     OS.g_object_unref (pixbuf);
1031     ImageData imageData = null;
1032     if (hasAlpha) {
1033         PaletteData palette = new PaletteData (0xFF000000, 0xFF0000, 0xFF00);
1034         imageData = new ImageData (width, height, 32, palette);
1035         byte [] alpha = new byte [stride * height];
1036         for (int y=0; y<height; y++) {
1037             for (int x=0; x<width; x++) {
1038                 alpha [y*width+x] = data [y*stride+x*4+3];
1039                 data [y*stride+x*4+3] = 0;
1040             }
1041         }
1042         imageData.setAlphas (0, 0, width * height, alpha, 0);
1043     } else {
1044         PaletteData palette = new PaletteData (0xFF0000, 0xFF00, 0xFF);
1045         imageData = new ImageData (width, height, 24, palette);
1046     }
1047     imageData.data = data;
1048     imageData.bytesPerLine = stride;
1049     return new Image (this, imageData);
1050 }
1051 
1052 static GdkPixbuf* createPixbuf(Image image) {
1053     int w, h;
1054     OS.gdk_drawable_get_size (image.pixmap, &w, &h);
1055     auto colormap = OS.gdk_colormap_get_system ();
1056     GdkPixbuf* pixbuf;
1057     bool hasMask = image.mask !is null && OS.gdk_drawable_get_depth (image.mask) is 1;
1058     if (hasMask) {
1059         pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, true, 8, w, h );
1060         if (pixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES);
1061         OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w, h);
1062         auto maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, w, h);
1063         if (maskPixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES);
1064         OS.gdk_pixbuf_get_from_drawable(maskPixbuf, image.mask, null, 0, 0, 0, 0, w, h);
1065         int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
1066         auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
1067         byte[] line = new byte[stride];
1068         int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf);
1069         auto maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf);
1070         byte[] maskLine = new byte[maskStride];
1071         for (int y=0; y<h; y++) {
1072             auto offset = pixels + (y * stride);
1073             OS.memmove(line.ptr, offset, stride);
1074             auto maskOffset = maskPixels + (y * maskStride);
1075             OS.memmove(maskLine.ptr, maskOffset, maskStride);
1076             for (int x=0; x<w; x++) {
1077                 if (maskLine[x * 3] is 0) {
1078                     line[x * 4 + 3] = 0;
1079                 }
1080             }
1081             OS.memmove(offset, line.ptr, stride);
1082         }
1083         OS.g_object_unref(maskPixbuf);
1084     } else {
1085         ImageData data = image.getImageData ();
1086         bool hasAlpha = data.getTransparencyType () is SWT.TRANSPARENCY_ALPHA;
1087         pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, hasAlpha, 8, w, h);
1088         if (pixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES);
1089         OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w, h);
1090         if (hasAlpha) {
1091             byte [] alpha = data.alphaData;
1092             int stride = OS.gdk_pixbuf_get_rowstride (pixbuf);
1093             auto pixels = OS.gdk_pixbuf_get_pixels (pixbuf);
1094             byte [] line = new byte [stride];
1095             for (int y = 0; y < h; y++) {
1096                 auto offset = pixels + (y * stride);
1097                 OS.memmove (line.ptr, offset, stride);
1098                 for (int x = 0; x < w; x++) {
1099                     line [x*4+3] = alpha [y*w+x];
1100                 }
1101                 OS.memmove (offset, line.ptr, stride);
1102             }
1103         }
1104     }
1105     return pixbuf;
1106 }
1107 
1108 static void deregister (Display display) {
1109     synchronized (Device.classinfo) {
1110         for (int i=0; i<Displays.length; i++) {
1111             if (display is Displays [i]) Displays [i] = null;
1112         }
1113     }
1114 }
1115 
1116 /**
1117  * Destroys the device in the operating system and releases
1118  * the device's handle.  If the device does not have a handle,
1119  * this method may do nothing depending on the device.
1120  * <p>
1121  * This method is called after <code>release</code>.
1122  * </p>
1123  * @see Device#dispose
1124  * @see #release
1125  */
1126 protected override void destroy () {
1127     if (this is Default) Default = null;
1128     deregister (this);
1129     destroyDisplay ();
1130 }
1131 
1132 void destroyDisplay () {
1133 }
1134 
1135 static extern(C) int emissionFunc (GSignalInvocationHint* ihint, uint n_param_values, GValue* param_values, void* data) {
1136     auto cb = cast(CallbackData*)data;
1137     return cb.display.emissionProc( ihint, n_param_values, param_values, cb.data );
1138 }
1139 
1140 int emissionProc (GSignalInvocationHint* ihint, size_t n_param_values, GValue* param_values, void* data) {
1141     if (OS.gtk_widget_get_toplevel (OS.g_value_peek_pointer(param_values)) is data) {
1142         OS.gtk_widget_set_direction (OS.g_value_peek_pointer(param_values), OS.GTK_TEXT_DIR_RTL);
1143     }
1144     return 1;
1145 }
1146 
1147 /**
1148  * Returns the display which the given thread is the
1149  * user-interface thread for, or null if the given thread
1150  * is not a user-interface thread for any display.  Specifying
1151  * <code>null</code> as the thread will return <code>null</code>
1152  * for the display.
1153  *
1154  * @param thread the user-interface thread
1155  * @return the display for the given thread
1156  */
1157 public static Display findDisplay (Thread thread) {
1158     synchronized (Device.classinfo) {
1159         for (int i=0; i<Displays.length; i++) {
1160             Display display = Displays [i];
1161             if (display !is null && display.thread is thread) {
1162                 return display;
1163             }
1164         }
1165         return null;
1166     }
1167 }
1168 
1169 /**
1170  * Causes the <code>run()</code> method of the runnable to
1171  * be invoked by the user-interface thread just before the
1172  * receiver is disposed.  Specifying a <code>null</code> runnable
1173  * is ignored.
1174  *
1175  * @param runnable code to run at dispose time.
1176  *
1177  * @exception SWTException <ul>
1178  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1179  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1180  * </ul>
1181  */
1182 public void disposeExec (Runnable runnable) {
1183     checkDevice ();
1184     if (disposeList is null) disposeList = new Runnable [4];
1185     for (int i=0; i<disposeList.length; i++) {
1186         if (disposeList [i] is null) {
1187             disposeList [i] = runnable;
1188             return;
1189         }
1190     }
1191     Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
1192     SimpleType!(Runnable).arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
1193     newDisposeList [disposeList.length] = runnable;
1194     disposeList = newDisposeList;
1195 }
1196 
1197 /**
1198  * Does whatever display specific cleanup is required, and then
1199  * uses the code in <code>SWTError.error</code> to handle the error.
1200  *
1201  * @param code the descriptive error code
1202  *
1203  * @see SWTError#error
1204  */
1205 void error (int code) {
1206     SWT.error (code);
1207 }
1208 
1209 private static extern(C) void eventProcFunc (GdkEvent* event, void* data) {
1210     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1211     Display disp = cast(Display)data;
1212     disp.eventProcMeth(event);
1213 }
1214 void eventProcMeth (GdkEvent* event) {
1215     /*
1216     * Use gdk_event_get_time() rather than event.time or
1217     * gtk_get_current_event_time().  If the event does not
1218     * have a time stamp, then the field will contain garbage.
1219     * Note that calling gtk_get_current_event_time() from
1220     * outside of gtk_main_do_event() seems to always
1221     * return zero.
1222     */
1223     int time = OS.gdk_event_get_time (event);
1224     if (time !is 0) lastEventTime = time;
1225 
1226     int eventType = OS.GDK_EVENT_TYPE (event);
1227     switch (eventType) {
1228         case OS.GDK_BUTTON_PRESS:
1229         case OS.GDK_KEY_PRESS:
1230             lastUserEventTime = time;
1231             break;
1232         default:
1233             break;
1234     }
1235     bool dispatch = true;
1236     if (dispatchEvents !is null) {
1237         dispatch = false;
1238         for (int i = 0; i < dispatchEvents.length; i++) {
1239             if (eventType is dispatchEvents [i]) {
1240                 dispatch = true;
1241                 break;
1242             }
1243         }
1244     }
1245     if (!dispatch) {
1246         addGdkEvent (OS.gdk_event_copy (event));
1247         return;
1248     }
1249     OS.gtk_main_do_event (event);
1250     if (dispatchEvents is null) putGdkEvents ();
1251 }
1252 
1253 /**
1254  * Given the operating system handle for a widget, returns
1255  * the instance of the <code>Widget</code> subclass which
1256  * represents it in the currently running application, if
1257  * such exists, or null if no matching widget can be found.
1258  * <p>
1259  * <b>IMPORTANT:</b> This method should not be called from
1260  * application code. The arguments are platform-specific.
1261  * </p>
1262  *
1263  * @param handle the handle for the widget
1264  * @return the SWT widget that the handle represents
1265  *
1266  * @exception SWTException <ul>
1267  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1268  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1269  * </ul>
1270  */
1271 public Widget findWidget (GtkWidget* handle) {
1272     checkDevice ();
1273     return getWidget (handle);
1274 }
1275 
1276 /**
1277  * Given the operating system handle for a widget,
1278  * and widget-specific id, returns the instance of
1279  * the <code>Widget</code> subclass which represents
1280  * the handle/id pair in the currently running application,
1281  * if such exists, or null if no matching widget can be found.
1282  * <p>
1283  * <b>IMPORTANT:</b> This method should not be called from
1284  * application code. The arguments are platform-specific.
1285  * </p>
1286  *
1287  * @param handle the handle for the widget
1288  * @param id the id for the subwidget (usually an item)
1289  * @return the SWT widget that the handle/id pair represents
1290  *
1291  * @exception SWTException <ul>
1292  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1293  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1294  * </ul>
1295  *
1296  * @since 3.1
1297  */
1298 public Widget findWidget (GtkWidget* handle, int id) {
1299     checkDevice ();
1300     return null;
1301 }
1302 
1303 /**
1304  * Given a widget and a widget-specific id, returns the
1305  * instance of the <code>Widget</code> subclass which represents
1306  * the widget/id pair in the currently running application,
1307  * if such exists, or null if no matching widget can be found.
1308  *
1309  * @param widget the widget
1310  * @param id the id for the subwidget (usually an item)
1311  * @return the SWT subwidget (usually an item) that the widget/id pair represents
1312  *
1313  * @exception SWTException <ul>
1314  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1315  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1316  * </ul>
1317  *
1318  * @since 3.3
1319  */
1320 public Widget findWidget (Widget widget, ptrdiff_t id) {
1321     checkDevice ();
1322     return null;
1323 }
1324 
1325 private static extern(C) void fixedClassInitProcFunc (void* g_class, void* class_data) {
1326     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1327     GtkWidgetClass* klass = cast(GtkWidgetClass*)g_class;
1328     klass.map = &fixedMapProcFunc;
1329     oldFixedSizeAllocateProc = klass.size_allocate;
1330     klass.size_allocate = &fixedSizeAllocateProc;
1331 }
1332 
1333 private static extern(C) void fixedMapProcFunc (GtkWidget * handle) {
1334     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1335     Display display = getCurrent ();
1336     Widget widget = display.getWidget (handle);
1337     if (widget !is null) widget.fixedMapProc (handle);
1338 }
1339 
1340 private static extern(C) void fixedSizeAllocateProc (GtkWidget* handle, GtkAllocation* allocation) {
1341     Display display = getCurrent ();
1342     Widget widget = display.getWidget (handle);
1343     if (widget !is null) return widget.fixedSizeAllocateProc (handle, allocation);
1344     return oldFixedSizeAllocateProc(handle, allocation);
1345 }
1346 
1347 private static extern(C) void rendererClassInitProcFunc (void* g_class, void* class_data) {
1348     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1349     GtkCellRendererClass* klass = cast(GtkCellRendererClass*)g_class;
1350     klass.render = &rendererRenderProcFunc;
1351     klass.get_size = &rendererGetSizeProcFunc;
1352 
1353 }
1354 private static extern(C) void rendererGetSizeProcFunc(
1355     GtkCellRenderer      *cell,
1356     GtkWidget            *handle,
1357     GdkRectangle         *cell_area,
1358     int                  *x_offset,
1359     int                  *y_offset,
1360     int                  *width,
1361     int                  *height)
1362 {
1363     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1364     Display display = getCurrent ();
1365     Widget widget = display.getWidget (handle);
1366     if (widget !is null) widget.rendererGetSizeProc (cell, handle, cell_area, x_offset, y_offset, width, height);
1367 }
1368 private static extern(C) void rendererRenderProcFunc(GtkCellRenderer * cell, GdkDrawable * window, GtkWidget * handle, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, int flags){
1369     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1370     Display display = getCurrent ();
1371     Widget widget = display.getWidget (handle);
1372     if (widget !is null) widget.rendererRenderProc (cell, window, handle, background_area, cell_area, expose_area, flags);
1373 }
1374 
1375 void flushExposes (GdkWindow* window, bool all) {
1376     OS.gdk_flush ();
1377     OS.gdk_flush ();
1378     if (OS.GDK_WINDOWING_X11 ()) {
1379         this.flushWindow = window;
1380         this.flushAll = all;
1381         auto xDisplay = OS.GDK_DISPLAY ();
1382         auto xEvent = cast(XEvent*)OS.g_malloc (XEvent.sizeof);
1383         OS.XCheckIfEvent (xDisplay, xEvent, &checkIfEventProcFunc, cast(char*)this );
1384         OS.g_free (xEvent);
1385         this.flushWindow = null;
1386     }
1387 }
1388 
1389 /**
1390  * Returns the currently active <code>Shell</code>, or null
1391  * if no shell belonging to the currently running application
1392  * is active.
1393  *
1394  * @return the active shell or null
1395  *
1396  * @exception SWTException <ul>
1397  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1398  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1399  * </ul>
1400  */
1401 public Shell getActiveShell () {
1402     checkDevice ();
1403     return activeShell;
1404 }
1405 
1406 /**
1407  * Returns a rectangle describing the receiver's size and location. Note that
1408  * on multi-monitor systems the origin can be negative.
1409  *
1410  * @return the bounding rectangle
1411  *
1412  * @exception SWTException <ul>
1413  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1414  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1415  * </ul>
1416  */
1417 public override Rectangle getBounds () {
1418     checkDevice ();
1419     return new Rectangle (0, 0, OS.gdk_screen_width (), OS.gdk_screen_height ());
1420 }
1421 
1422 /**
1423  * Returns the display which the currently running thread is
1424  * the user-interface thread for, or null if the currently
1425  * running thread is not a user-interface thread for any display.
1426  *
1427  * @return the current display
1428  */
1429 public static Display getCurrent () {
1430     return findDisplay (Thread.currentThread ());
1431 }
1432 
1433 int getCaretBlinkTime () {
1434 //  checkDevice ();
1435     auto settings = OS.gtk_settings_get_default ();
1436     if (settings is null) return 500;
1437     int  buffer;
1438     OS.g_object_get1 (settings, OS.gtk_cursor_blink.ptr, &buffer );
1439     if (buffer  is 0) return 0;
1440     OS.g_object_get1 (settings, OS.gtk_cursor_blink_time.ptr, &buffer);
1441     if (buffer  is 0) return 500;
1442     /*
1443     * By experimentation, GTK application don't use the whole
1444     * blink cycle time.  Instead, they divide up the time, using
1445     * an effective blink rate of about 1/2 the total time.
1446     */
1447     return buffer / 2;
1448 }
1449 
1450 /**
1451  * Returns the control which the on-screen pointer is currently
1452  * over top of, or null if it is not currently over one of the
1453  * controls built by the currently running application.
1454  *
1455  * @return the control under the cursor
1456  *
1457  * @exception SWTException <ul>
1458  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1459  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1460  * </ul>
1461  */
1462 public Control getCursorControl () {
1463     checkDevice();
1464     int x, y;
1465     GtkWidget* handle;
1466     GtkWidget* user_data;
1467     auto window = OS.gdk_window_at_pointer (&x, &y);
1468     if (window !is null) {
1469         OS.gdk_window_get_user_data (window, cast(void**)&user_data);
1470         handle = user_data;
1471     } else {
1472         /*
1473         * Feature in GTK. gdk_window_at_pointer() will not return a window
1474         * if the pointer is over a foreign embedded window. The fix is to use
1475         * XQueryPointer to find the containing GDK window.
1476         */
1477         if (!OS.GDK_WINDOWING_X11 ()) return null;
1478         OS.gdk_error_trap_push ();
1479         int unusedInt;
1480         uint unusedUInt;
1481         size_t unusedPtr;
1482         size_t buffer;
1483         size_t xWindow, xParent = OS.XDefaultRootWindow (xDisplay);
1484         do {
1485             if (OS.XQueryPointer (xDisplay, xParent, &unusedPtr, &buffer, &unusedInt, &unusedInt, &unusedInt, &unusedInt, &unusedUInt) is 0) {
1486                 handle = null;
1487                 break;
1488             }
1489             if ((xWindow = buffer) !is 0) {
1490                 xParent = xWindow;
1491                 auto gdkWindow = OS.gdk_window_lookup (cast(void*)xWindow);
1492                 if (gdkWindow !is null) {
1493                     OS.gdk_window_get_user_data (gdkWindow, cast(void**)&user_data);
1494                     if (user_data !is null) handle = user_data;
1495                 }
1496             }
1497         } while (xWindow !is 0);
1498         OS.gdk_error_trap_pop ();
1499     }
1500     if (handle is null) return null;
1501     do {
1502         Widget widget = getWidget (handle);
1503         if (widget !is null && (null !is cast(Control)widget)) {
1504             Control control = cast(Control) widget;
1505             if (control.isEnabled ()) return control;
1506         }
1507     } while ((handle = OS.gtk_widget_get_parent (handle)) !is null);
1508     return null;
1509 }
1510 
1511 bool filterEvent (Event event) {
1512     if (filterTable !is null) filterTable.sendEvent (event);
1513     return false;
1514 }
1515 
1516 bool filters (int eventType) {
1517     if (filterTable is null) return false;
1518     return filterTable.hooks (eventType);
1519 }
1520 
1521 private static extern(C) int filterProcFunc (GdkXEvent* xEvent, GdkEvent* gdkEvent, void* data) {
1522     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1523     auto callbackdata = cast(CallbackData*)data;
1524     auto disp = callbackdata.display;
1525     if( disp is null ) return 0;
1526     auto res =  disp.filterProcMeth(xEvent,gdkEvent,callbackdata);
1527     return res;
1528 }
1529 
1530 int filterProcMeth (GdkXEvent* xEvent, GdkEvent* gdkEvent, CallbackData* callbackData) {
1531     if( callbackData.data is null ){
1532         /*
1533          * Feature in GTK.  When button 4, 5, 6, or 7 is released, GTK
1534          * does not deliver a corresponding GTK event.  Button 6 and 7
1535          * are mapped to buttons 4 and 5 in SWT.  The fix is to change
1536          * the button number of the event to a negative number so that
1537          * it gets dispatched by GTK.  SWT has been modified to look
1538          * for negative button numbers.
1539          */
1540         XButtonEvent* mouseEvent = cast(XButtonEvent*) xEvent;
1541         if (mouseEvent.type is OS.ButtonRelease) {
1542             switch (mouseEvent.button) {
1543                 case 6:
1544                 case 7:
1545                     mouseEvent.button = -mouseEvent.button;
1546                     break;
1547                 default:
1548             }
1549         }
1550     }
1551     Widget widget = getWidget (cast(GtkWidget*)callbackData.data);
1552     if (widget is null) return 0;
1553     return widget.filterProc (cast(XEvent*)xEvent, gdkEvent, callbackData.data);
1554 }
1555 
1556 /**
1557  * Returns the location of the on-screen pointer relative
1558  * to the top left corner of the screen.
1559  *
1560  * @return the cursor location
1561  *
1562  * @exception SWTException <ul>
1563  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1564  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1565  * </ul>
1566  */
1567 public Point getCursorLocation () {
1568     checkDevice ();
1569     int x, y;
1570     OS.gdk_window_get_pointer (null, &x, &y, null);
1571     return new Point (x, y);
1572 }
1573 
1574 /**
1575  * Returns an array containing the recommended cursor sizes.
1576  *
1577  * @return the array of cursor sizes
1578  *
1579  * @exception SWTException <ul>
1580  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1581  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1582  * </ul>
1583  *
1584  * @since 3.0
1585  */
1586 public Point [] getCursorSizes () {
1587     checkDevice ();
1588     return [new Point (16, 16), new Point (32, 32)];
1589 }
1590 
1591 /**
1592  * Returns the application defined property of the receiver
1593  * with the specified name, or null if it has not been set.
1594  * <p>
1595  * Applications may have associated arbitrary objects with the
1596  * receiver in this fashion. If the objects stored in the
1597  * properties need to be notified when the display is disposed
1598  * of, it is the application's responsibility to provide a
1599  * <code>disposeExec()</code> handler which does so.
1600  * </p>
1601  *
1602  * @param key the name of the property
1603  * @return the value of the property or null if it has not been set
1604  *
1605  * @exception SWTException <ul>
1606  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1607  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1608  * </ul>
1609  *
1610  * @see #setData(String, Object)
1611  * @see #disposeExec(Runnable)
1612  */
1613 public Object getData (String key) {
1614     checkDevice ();
1615     // SWT extension: allow null for zero length string
1616     //if (key is null) error (SWT.ERROR_NULL_ARGUMENT);
1617     if (key.equals (DISPATCH_EVENT_KEY)) {
1618         return new ArrayWrapperInt(dispatchEvents);
1619     }
1620     if (key.equals (GET_MODAL_DIALOG)) {
1621         return modalDialog;
1622     }
1623     if (key.equals (GET_DIRECTION_PROC_KEY)) {
1624         return new LONG (cast(int) &setDirectionProcFunc);
1625     }
1626     if (key.equals (GET_EMISSION_PROC_KEY)) {
1627         return new LONG (cast(int) &emissionFunc);
1628     }
1629     if (keys is null) return null;
1630     for (int i=0; i<keys.length; i++) {
1631         if (keys [i].equals(key)) return values [i];
1632     }
1633     return null;
1634 }
1635 
1636 /**
1637  * Returns the application defined, display specific data
1638  * associated with the receiver, or null if it has not been
1639  * set. The <em>display specific data</em> is a single,
1640  * unnamed field that is stored with every display.
1641  * <p>
1642  * Applications may put arbitrary objects in this field. If
1643  * the object stored in the display specific data needs to
1644  * be notified when the display is disposed of, it is the
1645  * application's responsibility to provide a
1646  * <code>disposeExec()</code> handler which does so.
1647  * </p>
1648  *
1649  * @return the display specific data
1650  *
1651  * @exception SWTException <ul>
1652  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1653  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1654  * </ul>
1655  *
1656  * @see #setData(Object)
1657  * @see #disposeExec(Runnable)
1658  */
1659 public Object getData () {
1660     checkDevice ();
1661     return data;
1662 }
1663 
1664 /**
1665  * Returns a point whose x coordinate is the horizontal
1666  * dots per inch of the display, and whose y coordinate
1667  * is the vertical dots per inch of the display.
1668  *
1669  * @return the horizontal and vertical DPI
1670  *
1671  * @exception SWTException <ul>
1672  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1673  * </ul>
1674  */
1675 public override Point getDPI () {
1676     checkDevice ();
1677     int widthMM = OS.gdk_screen_width_mm ();
1678     int width = OS.gdk_screen_width ();
1679     int dpi = Compatibility.round (254 * width, widthMM * 10);
1680     return new Point (dpi, dpi);
1681 }
1682 
1683 ptrdiff_t gtk_fixed_get_type () {
1684     return fixed_type;
1685 }
1686 
1687 ptrdiff_t gtk_cell_renderer_text_get_type () {
1688     return text_renderer_type;
1689 }
1690 
1691 ptrdiff_t gtk_cell_renderer_pixbuf_get_type () {
1692     return pixbuf_renderer_type;
1693 }
1694 
1695 ptrdiff_t gtk_cell_renderer_toggle_get_type () {
1696     return toggle_renderer_type;
1697 }
1698 
1699 /**
1700  * Returns the default display. One is created (making the
1701  * thread that invokes this method its user-interface thread)
1702  * if it did not already exist.
1703  *
1704  * @return the default display
1705  */
1706 public static Display getDefault () {
1707     synchronized (Device.classinfo) {
1708         if (Default is null) Default = new Display ();
1709         return Default;
1710     }
1711 }
1712 
1713 // /+static bool isValidClass (Class clazz) {
1714 // //PORTING_TODO   String name = clazz.getName ();
1715 // //PORTING_TODO   int index = name.lastIndexOf ('.');
1716 // //PORTING_TODO   return name.substring (0, index + 1)==/*eq*/ PACKAGE_PREFIX;
1717 //     return true;
1718 // }+/
1719 
1720 /**
1721  * Returns the button dismissal alignment, one of <code>LEFT</code> or <code>RIGHT</code>.
1722  * The button dismissal alignment is the ordering that should be used when positioning the
1723  * default dismissal button for a dialog.  For example, in a dialog that contains an OK and
1724  * CANCEL button, on platforms where the button dismissal alignment is <code>LEFT</code>, the
1725  * button ordering should be OK/CANCEL.  When button dismissal alignment is <code>RIGHT</code>,
1726  * the button ordering should be CANCEL/OK.
1727  *
1728  * @return the button dismissal order
1729  *
1730  * @exception SWTException <ul>
1731  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1732  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1733  * </ul>
1734  *
1735  * @since 2.1
1736  */
1737 public int getDismissalAlignment () {
1738     checkDevice ();
1739     return SWT.RIGHT;
1740 }
1741 
1742 /**
1743  * Returns the longest duration, in milliseconds, between
1744  * two mouse button clicks that will be considered a
1745  * <em>double click</em> by the underlying operating system.
1746  *
1747  * @return the double click time
1748  *
1749  * @exception SWTException <ul>
1750  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1751  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1752  * </ul>
1753  */
1754 public int getDoubleClickTime () {
1755     checkDevice ();
1756     auto settings = OS.gtk_settings_get_default ();
1757     int buffer;
1758     OS.g_object_get1 (settings, OS.gtk_double_click_time.ptr, &buffer);
1759     return buffer;
1760 }
1761 
1762 /**
1763  * Returns the control which currently has keyboard focus,
1764  * or null if keyboard events are not currently going to
1765  * any of the controls built by the currently running
1766  * application.
1767  *
1768  * @return the control under the cursor
1769  *
1770  * @exception SWTException <ul>
1771  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1772  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1773  * </ul>
1774  */
1775 public Control getFocusControl () {
1776     checkDevice ();
1777     if (focusControl !is null && !focusControl.isDisposed ()) {
1778         return focusControl;
1779     }
1780     if (activeShell is null) return null;
1781     auto shellHandle = activeShell.shellHandle;
1782     auto handle = OS.gtk_window_get_focus (cast(GtkWindow*)shellHandle);
1783     if (handle is null) return null;
1784     do {
1785         Widget widget = getWidget (handle);
1786         if (widget !is null && (null !is cast(Control)widget)) {
1787             Control control = cast(Control) widget;
1788             return control.isEnabled () ? control : null;
1789         }
1790     } while ((handle = OS.gtk_widget_get_parent (handle)) !is null);
1791     return null;
1792 }
1793 
1794 /**
1795  * Returns true when the high contrast mode is enabled.
1796  * Otherwise, false is returned.
1797  * <p>
1798  * Note: This operation is a hint and is not supported on
1799  * platforms that do not have this concept.
1800  * </p>
1801  *
1802  * @return the high contrast mode
1803  *
1804  * @exception SWTException <ul>
1805  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1806  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1807  * </ul>
1808  *
1809  * @since 3.0
1810  */
1811 public bool getHighContrast () {
1812     checkDevice ();
1813     return false;
1814 }
1815 
1816 public override int getDepth () {
1817     checkDevice ();
1818     auto visual = OS.gdk_visual_get_system();
1819     return visual.depth;
1820 }
1821 
1822 /**
1823  * Returns the maximum allowed depth of icons on this display, in bits per pixel.
1824  * On some platforms, this may be different than the actual depth of the display.
1825  *
1826  * @return the maximum icon depth
1827  *
1828  * @exception SWTException <ul>
1829  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1830  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1831  * </ul>
1832  *
1833  * @see Device#getDepth
1834  */
1835 public int getIconDepth () {
1836     checkDevice ();
1837     return getDepth ();
1838 }
1839 
1840 /**
1841  * Returns an array containing the recommended icon sizes.
1842  *
1843  * @return the array of icon sizes
1844  *
1845  * @exception SWTException <ul>
1846  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1847  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1848  * </ul>
1849  *
1850  * @see Decorations#setImages(Image[])
1851  *
1852  * @since 3.0
1853  */
1854 public Point [] getIconSizes () {
1855     checkDevice ();
1856     return [new Point (16, 16), new Point (32, 32)];
1857 }
1858 
1859 int getLastEventTime () {
1860     return lastEventTime;
1861 }
1862 
1863 int getMessageCount () {
1864     return synchronizer.getMessageCount ();
1865 }
1866 
1867 Dialog getModalDialog () {
1868     return modalDialog;
1869 }
1870 
1871 /**
1872  * Returns the work area, an EWMH property to store the size
1873  * and position of the screen not covered by dock and panel
1874  * windows.  See http://freedesktop.org/Standards/wm-spec.
1875  */
1876 Rectangle getWorkArea() {
1877     auto atom = OS.gdk_atom_intern ("_NET_WORKAREA".ptr, true);
1878     if (atom is null/*OS.GDK_NONE*/) return null;
1879     void* actualType;
1880     int actualFormat;
1881     int actualLength;
1882     char* data;
1883     if (!OS.gdk_property_get (cast(GdkDrawable*)OS.GDK_ROOT_PARENT (), atom, null/*OS.GDK_NONE*/, 0, 16, 0, &actualType, &actualFormat, &actualLength, &data)) {
1884         return null;
1885     }
1886     Rectangle result = null;
1887     if (data !is null) {
1888         if (actualLength is 16) {
1889             int[] values = (cast(int*)data)[0..4];
1890             result = new Rectangle (values [0],values [1],values [2],values [3]);
1891         } else if (actualLength is 32) {
1892             long[] values = (cast(long*)data)[0..4];
1893             result = new Rectangle (cast(int)values [0],cast(int)values [1],cast(int)values [2],cast(int)values [3]);
1894         }
1895         OS.g_free (data);
1896     }
1897     return result;
1898 }
1899 
1900 /**
1901  * Returns an array of monitors attached to the device.
1902  *
1903  * @return the array of monitors
1904  *
1905  * @since 3.0
1906  */
1907 public org.eclipse.swt.widgets.Monitor.Monitor [] getMonitors () {
1908     checkDevice ();
1909     org.eclipse.swt.widgets.Monitor.Monitor [] monitors = null;
1910     Rectangle workArea = getWorkArea();
1911     auto screen = OS.gdk_screen_get_default ();
1912     if (screen !is null) {
1913         int monitorCount = OS.gdk_screen_get_n_monitors (screen);
1914         if (monitorCount > 0) {
1915             monitors = new org.eclipse.swt.widgets.Monitor.Monitor [monitorCount];
1916             GdkRectangle* dest = new GdkRectangle ();
1917             for (int i = 0; i < monitorCount; i++) {
1918                 OS.gdk_screen_get_monitor_geometry (screen, i, dest);
1919                 auto monitor = new org.eclipse.swt.widgets.Monitor.Monitor ();
1920                 monitor.handle = i;
1921                 monitor.x = dest.x;
1922                 monitor.y = dest.y;
1923                 monitor.width = dest.width;
1924                 monitor.height = dest.height;
1925                 if (i is 0 && workArea !is null) {
1926                     monitor.clientX = workArea.x;
1927                     monitor.clientY = workArea.y;
1928                     monitor.clientWidth = workArea.width;
1929                     monitor.clientHeight = workArea.height;
1930                 } else {
1931                     monitor.clientX = monitor.x;
1932                     monitor.clientY = monitor.y;
1933                     monitor.clientWidth = monitor.width;
1934                     monitor.clientHeight = monitor.height;
1935                 }
1936                 monitors [i] = monitor;
1937             }
1938         }
1939     }
1940     if (monitors is null) {
1941         /* No multimonitor support detected, default to one monitor */
1942         auto monitor = new org.eclipse.swt.widgets.Monitor.Monitor ();
1943         Rectangle bounds = getBounds ();
1944         monitor.x = bounds.x;
1945         monitor.y = bounds.y;
1946         monitor.width = bounds.width;
1947         monitor.height = bounds.height;
1948         if (workArea !is null) {
1949             monitor.clientX = workArea.x;
1950             monitor.clientY = workArea.y;
1951             monitor.clientWidth = workArea.width;
1952             monitor.clientHeight = workArea.height;
1953         } else {
1954             monitor.clientX = monitor.x;
1955             monitor.clientY = monitor.y;
1956             monitor.clientWidth = monitor.width;
1957             monitor.clientHeight = monitor.height;
1958         }
1959         monitors = [ monitor ];
1960     }
1961     return monitors;
1962 }
1963 
1964 /**
1965  * Returns the primary monitor for that device.
1966  *
1967  * @return the primary monitor
1968  *
1969  * @since 3.0
1970  */
1971 public org.eclipse.swt.widgets.Monitor.Monitor getPrimaryMonitor () {
1972     checkDevice ();
1973     auto monitors = getMonitors ();
1974     return monitors [0];
1975 }
1976 
1977 /**
1978  * Returns a (possibly empty) array containing all shells which have
1979  * not been disposed and have the receiver as their display.
1980  *
1981  * @return the receiver's shells
1982  *
1983  * @exception SWTException <ul>
1984  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1985  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1986  * </ul>
1987  */
1988 public Shell [] getShells () {
1989     checkDevice ();
1990     int index = 0;
1991     Shell [] result = new Shell [16];
1992     for (int i = 0; i < widgetTable.length; i++) {
1993         Widget widget = widgetTable [i];
1994         if (widget !is null && (null !is cast(Shell)widget)) {
1995             int j = 0;
1996             while (j < index) {
1997                 if (result [j] is widget) break;
1998                 j++;
1999             }
2000             if (j is index) {
2001                 if (index is result.length) {
2002                     Shell [] newResult = new Shell [index + 16];
2003                     System.arraycopy (result, 0, newResult, 0, index);
2004                     result = newResult;
2005                 }
2006                 result [index++] = cast(Shell) widget;
2007             }
2008         }
2009     }
2010     if (index is result.length) return result;
2011     Shell [] newResult = new Shell [index];
2012     System.arraycopy (result, 0, newResult, 0, index);
2013     return newResult;
2014 }
2015 
2016 /**
2017  * Gets the synchronizer used by the display.
2018  *
2019  * @return the receiver's synchronizer
2020  *
2021  * @exception SWTException <ul>
2022  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2023  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2024  * </ul>
2025  *
2026  * @since 3.4
2027  */
2028 public Synchronizer getSynchronizer () {
2029     checkDevice ();
2030     return synchronizer;
2031 }
2032 
2033 /**
2034  * Returns the thread that has invoked <code>syncExec</code>
2035  * or null if no such runnable is currently being invoked by
2036  * the user-interface thread.
2037  * <p>
2038  * Note: If a runnable invoked by asyncExec is currently
2039  * running, this method will return null.
2040  * </p>
2041  *
2042  * @return the receiver's sync-interface thread
2043  *
2044  * @exception SWTException <ul>
2045  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2046  * </ul>
2047  */
2048 public Thread getSyncThread () {
2049     synchronized (Device.classinfo) {
2050         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2051         return synchronizer.syncThread;
2052     }
2053 }
2054 
2055 /**
2056  * Returns the matching standard color for the given
2057  * constant, which should be one of the color constants
2058  * specified in class <code>SWT</code>. Any value other
2059  * than one of the SWT color constants which is passed
2060  * in will result in the color black. This color should
2061  * not be free'd because it was allocated by the system,
2062  * not the application.
2063  *
2064  * @param id the color constant
2065  * @return the matching color
2066  *
2067  * @exception SWTException <ul>
2068  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2069  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2070  * </ul>
2071  *
2072  * @see SWT
2073  */
2074 public override Color getSystemColor (int id) {
2075     checkDevice ();
2076     GdkColor* gdkColor = null;
2077     switch (id) {
2078         case SWT.COLOR_INFO_FOREGROUND:                     gdkColor = COLOR_INFO_FOREGROUND; break;
2079         case SWT.COLOR_INFO_BACKGROUND:                     gdkColor = COLOR_INFO_BACKGROUND; break;
2080         case SWT.COLOR_TITLE_FOREGROUND:                    gdkColor = COLOR_TITLE_FOREGROUND; break;
2081         case SWT.COLOR_TITLE_BACKGROUND:                    gdkColor = COLOR_TITLE_BACKGROUND; break;
2082         case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:           gdkColor = COLOR_TITLE_BACKGROUND_GRADIENT; break;
2083         case SWT.COLOR_TITLE_INACTIVE_FOREGROUND:           gdkColor = COLOR_TITLE_INACTIVE_FOREGROUND; break;
2084         case SWT.COLOR_TITLE_INACTIVE_BACKGROUND:           gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND; break;
2085         case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:  gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT; break;
2086         case SWT.COLOR_WIDGET_DARK_SHADOW:                  gdkColor = COLOR_WIDGET_DARK_SHADOW; break;
2087         case SWT.COLOR_WIDGET_NORMAL_SHADOW:                gdkColor = COLOR_WIDGET_NORMAL_SHADOW; break;
2088         case SWT.COLOR_WIDGET_LIGHT_SHADOW:                 gdkColor = COLOR_WIDGET_LIGHT_SHADOW; break;
2089         case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW:             gdkColor = COLOR_WIDGET_HIGHLIGHT_SHADOW; break;
2090         case SWT.COLOR_WIDGET_BACKGROUND:                   gdkColor = COLOR_WIDGET_BACKGROUND; break;
2091         case SWT.COLOR_WIDGET_FOREGROUND:                   gdkColor = COLOR_WIDGET_FOREGROUND; break;
2092         case SWT.COLOR_WIDGET_BORDER:                       gdkColor = COLOR_WIDGET_BORDER; break;
2093         case SWT.COLOR_LIST_FOREGROUND:                     gdkColor = COLOR_LIST_FOREGROUND; break;
2094         case SWT.COLOR_LIST_BACKGROUND:                     gdkColor = COLOR_LIST_BACKGROUND; break;
2095         case SWT.COLOR_LIST_SELECTION:                      gdkColor = COLOR_LIST_SELECTION; break;
2096         case SWT.COLOR_LIST_SELECTION_TEXT:                 gdkColor = COLOR_LIST_SELECTION_TEXT; break;
2097         default:
2098             return super.getSystemColor (id);
2099     }
2100     if (gdkColor is null) return super.getSystemColor (SWT.COLOR_BLACK);
2101     return Color.gtk_new (this, gdkColor);
2102 }
2103 
2104 /**
2105  * Returns the matching standard platform cursor for the given
2106  * constant, which should be one of the cursor constants
2107  * specified in class <code>SWT</code>. This cursor should
2108  * not be free'd because it was allocated by the system,
2109  * not the application.  A value of <code>null</code> will
2110  * be returned if the supplied constant is not an SWT cursor
2111  * constant.
2112  *
2113  * @param id the SWT cursor constant
2114  * @return the corresponding cursor or <code>null</code>
2115  *
2116  * @exception SWTException <ul>
2117  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2118  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2119  * </ul>
2120  *
2121  * @see SWT#CURSOR_ARROW
2122  * @see SWT#CURSOR_WAIT
2123  * @see SWT#CURSOR_CROSS
2124  * @see SWT#CURSOR_APPSTARTING
2125  * @see SWT#CURSOR_HELP
2126  * @see SWT#CURSOR_SIZEALL
2127  * @see SWT#CURSOR_SIZENESW
2128  * @see SWT#CURSOR_SIZENS
2129  * @see SWT#CURSOR_SIZENWSE
2130  * @see SWT#CURSOR_SIZEWE
2131  * @see SWT#CURSOR_SIZEN
2132  * @see SWT#CURSOR_SIZES
2133  * @see SWT#CURSOR_SIZEE
2134  * @see SWT#CURSOR_SIZEW
2135  * @see SWT#CURSOR_SIZENE
2136  * @see SWT#CURSOR_SIZESE
2137  * @see SWT#CURSOR_SIZESW
2138  * @see SWT#CURSOR_SIZENW
2139  * @see SWT#CURSOR_UPARROW
2140  * @see SWT#CURSOR_IBEAM
2141  * @see SWT#CURSOR_NO
2142  * @see SWT#CURSOR_HAND
2143  *
2144  * @since 3.0
2145  */
2146 public Cursor getSystemCursor (int id) {
2147     checkDevice ();
2148     if (!(0 <= id && id < cursors.length)) return null;
2149     if (cursors [id] is null) {
2150         cursors [id] = new Cursor (this, id);
2151     }
2152     return cursors [id];
2153 }
2154 
2155 /**
2156  * Returns the matching standard platform image for the given
2157  * constant, which should be one of the icon constants
2158  * specified in class <code>SWT</code>. This image should
2159  * not be free'd because it was allocated by the system,
2160  * not the application.  A value of <code>null</code> will
2161  * be returned either if the supplied constant is not an
2162  * SWT icon constant or if the platform does not define an
2163  * image that corresponds to the constant.
2164  *
2165  * @param id the SWT icon constant
2166  * @return the corresponding image or <code>null</code>
2167  *
2168  * @exception SWTException <ul>
2169  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2170  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2171  * </ul>
2172  *
2173  * @see SWT#ICON_ERROR
2174  * @see SWT#ICON_INFORMATION
2175  * @see SWT#ICON_QUESTION
2176  * @see SWT#ICON_WARNING
2177  * @see SWT#ICON_WORKING
2178  *
2179  * @since 3.0
2180  */
2181 public Image getSystemImage (int id) {
2182     checkDevice ();
2183     switch (id) {
2184         case SWT.ICON_ERROR:
2185             if (errorImage is null) {
2186                 errorImage = createImage ("gtk-dialog-error"); //$NON-NLS-1$
2187             }
2188             return errorImage;
2189         case SWT.ICON_INFORMATION:
2190         case SWT.ICON_WORKING:
2191             if (infoImage is null) {
2192                 infoImage = createImage ("gtk-dialog-info"); //$NON-NLS-1$
2193             }
2194             return infoImage;
2195         case SWT.ICON_QUESTION:
2196             if (questionImage is null) {
2197                 questionImage = createImage ("gtk-dialog-question"); //$NON-NLS-1$
2198             }
2199             return questionImage;
2200         case SWT.ICON_WARNING:
2201             if (warningImage is null) {
2202                 warningImage = createImage ("gtk-dialog-warning"); //$NON-NLS-1$
2203             }
2204             return warningImage;
2205         default:
2206     }
2207     return null;
2208 }
2209 
2210 void initializeSystemColors () {
2211     GdkColor* gdkColor;
2212 
2213     /* Get Tooltip resources */
2214     auto tooltipShellHandle = OS.gtk_window_new (OS.GTK_WINDOW_POPUP);
2215     if (tooltipShellHandle is null) SWT.error (SWT.ERROR_NO_HANDLES);
2216 //  byte[] gtk_tooltips = Converter.wcsToMbcs (null, "gtk-tooltips", true);
2217     OS.gtk_widget_set_name (tooltipShellHandle, "gtk-tooltips".ptr );
2218     OS.gtk_widget_realize (tooltipShellHandle);
2219     auto tooltipStyle = OS.gtk_widget_get_style (tooltipShellHandle);
2220     gdkColor = new GdkColor();
2221     OS.gtk_style_get_fg (tooltipStyle, OS.GTK_STATE_NORMAL, gdkColor);
2222     COLOR_INFO_FOREGROUND = gdkColor;
2223     gdkColor = new GdkColor();
2224     OS.gtk_style_get_bg (tooltipStyle, OS.GTK_STATE_NORMAL, gdkColor);
2225     COLOR_INFO_BACKGROUND = gdkColor;
2226     OS.gtk_widget_destroy (tooltipShellHandle);
2227 
2228     /* Get Shell resources */
2229     auto style = OS.gtk_widget_get_style (shellHandle);
2230     gdkColor = new GdkColor();
2231     OS.gtk_style_get_black (style, gdkColor);
2232     COLOR_WIDGET_DARK_SHADOW = gdkColor;
2233     gdkColor = new GdkColor();
2234     OS.gtk_style_get_dark (style, OS.GTK_STATE_NORMAL, gdkColor);
2235     COLOR_WIDGET_NORMAL_SHADOW = gdkColor;
2236     gdkColor = new GdkColor();
2237     OS.gtk_style_get_bg (style, OS.GTK_STATE_NORMAL, gdkColor);
2238     COLOR_WIDGET_LIGHT_SHADOW = gdkColor;
2239     gdkColor = new GdkColor();
2240     OS.gtk_style_get_light (style, OS.GTK_STATE_NORMAL, gdkColor);
2241     COLOR_WIDGET_HIGHLIGHT_SHADOW = gdkColor;
2242     gdkColor = new GdkColor();
2243     OS.gtk_style_get_fg (style, OS.GTK_STATE_NORMAL, gdkColor);
2244     COLOR_WIDGET_FOREGROUND = gdkColor;
2245     gdkColor = new GdkColor();
2246     OS.gtk_style_get_bg (style, OS.GTK_STATE_NORMAL, gdkColor);
2247     COLOR_WIDGET_BACKGROUND = gdkColor;
2248     //gdkColor = new GdkColor();
2249     //OS.gtk_style_get_text (style, OS.GTK_STATE_NORMAL, gdkColor);
2250     //COLOR_TEXT_FOREGROUND = gdkColor;
2251     //gdkColor = new GdkColor();
2252     //OS.gtk_style_get_base (style, OS.GTK_STATE_NORMAL, gdkColor);
2253     //COLOR_TEXT_BACKGROUND = gdkColor;
2254     gdkColor = new GdkColor();
2255     OS.gtk_style_get_text (style, OS.GTK_STATE_NORMAL, gdkColor);
2256     COLOR_LIST_FOREGROUND = gdkColor;
2257     gdkColor = new GdkColor();
2258     OS.gtk_style_get_base (style, OS.GTK_STATE_NORMAL, gdkColor);
2259     COLOR_LIST_BACKGROUND = gdkColor;
2260     gdkColor = new GdkColor();
2261     OS.gtk_style_get_text (style, OS.GTK_STATE_SELECTED, gdkColor);
2262     COLOR_LIST_SELECTION_TEXT = gdkColor;
2263     gdkColor = new GdkColor();
2264     OS.gtk_style_get_base (style, OS.GTK_STATE_SELECTED, gdkColor);
2265     COLOR_LIST_SELECTION = gdkColor;
2266     gdkColor = new GdkColor();
2267     OS.gtk_style_get_bg (style, OS.GTK_STATE_SELECTED, gdkColor);
2268     COLOR_TITLE_BACKGROUND = gdkColor;
2269     gdkColor = new GdkColor();
2270     OS.gtk_style_get_fg (style, OS.GTK_STATE_SELECTED, gdkColor);
2271     COLOR_TITLE_FOREGROUND = gdkColor;
2272     gdkColor = new GdkColor();
2273     OS.gtk_style_get_light (style, OS.GTK_STATE_SELECTED, gdkColor);
2274     COLOR_TITLE_BACKGROUND_GRADIENT = gdkColor;
2275     gdkColor = new GdkColor();
2276     OS.gtk_style_get_bg (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
2277     COLOR_TITLE_INACTIVE_BACKGROUND = gdkColor;
2278     gdkColor = new GdkColor();
2279     OS.gtk_style_get_fg (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
2280     COLOR_TITLE_INACTIVE_FOREGROUND = gdkColor;
2281     gdkColor = new GdkColor();
2282     OS.gtk_style_get_light (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
2283     COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT = gdkColor;
2284 }
2285 
2286 /**
2287  * Returns a reasonable font for applications to use.
2288  * On some platforms, this will match the "default font"
2289  * or "system font" if such can be found.  This font
2290  * should not be free'd because it was allocated by the
2291  * system, not the application.
2292  * <p>
2293  * Typically, applications which want the default look
2294  * should simply not set the font on the widgets they
2295  * create. Widgets are always created with the correct
2296  * default font for the class of user-interface component
2297  * they represent.
2298  * </p>
2299  *
2300  * @return a font
2301  *
2302  * @exception SWTException <ul>
2303  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2304  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2305  * </ul>
2306  */
2307 public override Font getSystemFont () {
2308     checkDevice ();
2309     if (systemFont !is null) return systemFont;
2310     auto style = OS.gtk_widget_get_style (shellHandle);
2311     auto defaultFont = OS.pango_font_description_copy (OS.gtk_style_get_font_desc (style));
2312     return systemFont = Font.gtk_new (this, defaultFont);
2313 }
2314 
2315 /**
2316  * Returns the single instance of the system tray or null
2317  * when there is no system tray available for the platform.
2318  *
2319  * @return the system tray or <code>null</code>
2320  *
2321  * @exception SWTException <ul>
2322  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2323  * </ul>
2324  *
2325  * @since 3.0
2326  */
2327 public Tray getSystemTray () {
2328     checkDevice ();
2329     if (tray !is null) return tray;
2330     return tray = new Tray (this, SWT.NONE);
2331 }
2332 
2333 /**
2334  * Returns the user-interface thread for the receiver.
2335  *
2336  * @return the receiver's user-interface thread
2337  *
2338  * @exception SWTException <ul>
2339  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2340  * </ul>
2341  */
2342 public Thread getThread () {
2343     synchronized (Device.classinfo) {
2344         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2345         return thread;
2346     }
2347 }
2348 
2349 Widget getWidget (GtkWidget* handle) {
2350     if (handle is null) return null;
2351     if (lastWidget !is null && lastHandle is handle) return lastWidget;
2352     auto index = cast(ptrdiff_t)OS.g_object_get_qdata ( cast(GObject*)handle, SWT_OBJECT_INDEX) - 1;
2353     if (0 <= index && index < widgetTable.length) {
2354         lastHandle = handle;
2355         return lastWidget = widgetTable [index];
2356     }
2357     return null;
2358 }
2359 
2360 private static extern(C) int idleProcFunc (void* data) {
2361     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
2362     auto dbdata = cast(CallbackData*)data;
2363     return dbdata.display.idleProc();
2364 }
2365 private int idleProc () {
2366     bool result = runAsyncMessages (false);
2367     if (!result) {
2368         synchronized (idleLock) {
2369             idleHandle = 0;
2370         }
2371     }
2372     return result ? 1 : 0;
2373     return 0;
2374 }
2375 
2376 /**
2377  * Initializes any internal resources needed by the
2378  * device.
2379  * <p>
2380  * This method is called after <code>create</code>.
2381  * </p>
2382  *
2383  * @see #create
2384  */
2385 protected override void init_ () {
2386     super.init_ ();
2387     initializeCallbacks ();
2388     initializeSystemColors ();
2389     initializeSystemSettings ();
2390     initializeWidgetTable ();
2391     initializeWindowManager ();
2392 }
2393 
2394 void initializeCallbacks () {
2395     closures = new GClosure* [Widget.LAST_SIGNAL];
2396     signalIds = new int [Widget.LAST_SIGNAL];
2397 
2398     /* Cache signals for GtkWidget */
2399     signalIds [Widget.BUTTON_PRESS_EVENT] = OS.g_signal_lookup (OS.button_press_event.ptr, OS.GTK_TYPE_WIDGET ());
2400     signalIds [Widget.BUTTON_RELEASE_EVENT] = OS.g_signal_lookup (OS.button_release_event.ptr, OS.GTK_TYPE_WIDGET ());
2401     signalIds [Widget.CONFIGURE_EVENT] = OS.g_signal_lookup (OS.configure_event.ptr, OS.GTK_TYPE_WIDGET ());
2402     signalIds [Widget.DELETE_EVENT] = OS.g_signal_lookup (OS.delete_event.ptr, OS.GTK_TYPE_WIDGET ());
2403     signalIds [Widget.ENTER_NOTIFY_EVENT] = OS.g_signal_lookup (OS.enter_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2404     signalIds [Widget.EVENT] = OS.g_signal_lookup (OS.event.ptr, OS.GTK_TYPE_WIDGET ());
2405     signalIds [Widget.EVENT_AFTER] = OS.g_signal_lookup (OS.event_after.ptr, OS.GTK_TYPE_WIDGET ());
2406     signalIds [Widget.EXPOSE_EVENT] = OS.g_signal_lookup (OS.expose_event.ptr, OS.GTK_TYPE_WIDGET ());
2407     signalIds [Widget.FOCUS] = OS.g_signal_lookup (OS.focus.ptr, OS.GTK_TYPE_WIDGET ());
2408     signalIds [Widget.FOCUS_IN_EVENT] = OS.g_signal_lookup (OS.focus_in_event.ptr, OS.GTK_TYPE_WIDGET ());
2409     signalIds [Widget.FOCUS_OUT_EVENT] = OS.g_signal_lookup (OS.focus_out_event.ptr, OS.GTK_TYPE_WIDGET ());
2410     signalIds [Widget.GRAB_FOCUS] = OS.g_signal_lookup (OS.grab_focus.ptr, OS.GTK_TYPE_WIDGET ());
2411     signalIds [Widget.HIDE] = OS.g_signal_lookup (OS.hide.ptr, OS.GTK_TYPE_WIDGET ());
2412     signalIds [Widget.KEY_PRESS_EVENT] = OS.g_signal_lookup (OS.key_press_event.ptr, OS.GTK_TYPE_WIDGET ());
2413     signalIds [Widget.KEY_RELEASE_EVENT] = OS.g_signal_lookup (OS.key_release_event.ptr, OS.GTK_TYPE_WIDGET ());
2414     signalIds [Widget.LEAVE_NOTIFY_EVENT] = OS.g_signal_lookup (OS.leave_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2415     signalIds [Widget.MAP] = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET ());
2416     signalIds [Widget.MAP_EVENT] = OS.g_signal_lookup (OS.map_event.ptr, OS.GTK_TYPE_WIDGET ());
2417     signalIds [Widget.MNEMONIC_ACTIVATE] = OS.g_signal_lookup (OS.mnemonic_activate.ptr, OS.GTK_TYPE_WIDGET ());
2418     signalIds [Widget.MOTION_NOTIFY_EVENT] = OS.g_signal_lookup (OS.motion_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2419     signalIds [Widget.POPUP_MENU] = OS.g_signal_lookup (OS.popup_menu.ptr, OS.GTK_TYPE_WIDGET ());
2420     signalIds [Widget.REALIZE] = OS.g_signal_lookup (OS.realize.ptr, OS.GTK_TYPE_WIDGET ());
2421     signalIds [Widget.SCROLL_EVENT] = OS.g_signal_lookup (OS.scroll_event.ptr, OS.GTK_TYPE_WIDGET ());
2422     signalIds [Widget.SHOW] = OS.g_signal_lookup (OS.show.ptr, OS.GTK_TYPE_WIDGET ());
2423     signalIds [Widget.SHOW_HELP] = OS.g_signal_lookup (OS.show_help.ptr, OS.GTK_TYPE_WIDGET ());
2424     signalIds [Widget.SIZE_ALLOCATE] = OS.g_signal_lookup (OS.size_allocate.ptr, OS.GTK_TYPE_WIDGET ());
2425     signalIds [Widget.STYLE_SET] = OS.g_signal_lookup (OS.style_set.ptr, OS.GTK_TYPE_WIDGET ());
2426     signalIds [Widget.UNMAP] = OS.g_signal_lookup (OS.unmap.ptr, OS.GTK_TYPE_WIDGET ());
2427     signalIds [Widget.UNMAP_EVENT] = OS.g_signal_lookup (OS.unmap_event.ptr, OS.GTK_TYPE_WIDGET ());
2428     signalIds [Widget.UNREALIZE] = OS.g_signal_lookup (OS.realize.ptr, OS.GTK_TYPE_WIDGET ());
2429     signalIds [Widget.VISIBILITY_NOTIFY_EVENT] = OS.g_signal_lookup (OS.visibility_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2430     signalIds [Widget.WINDOW_STATE_EVENT] = OS.g_signal_lookup (OS.window_state_event.ptr, OS.GTK_TYPE_WIDGET ());
2431 
2432     GClosure* do_cclosure_new( GCallback cb, int value, ptrdiff_t notify ){
2433         CallbackData* res= new CallbackData;
2434         res.display = this;
2435         res.data = cast(void*)value;
2436         windowProcCallbackDatas[ value ] = res;
2437         return OS.g_cclosure_new( cb, cast(void*)res, cast(GClosureNotify)notify );
2438     }
2439 
2440     GCallback windowProc2 = cast(GCallback)&windowProcFunc2;
2441     closures [Widget.ACTIVATE] = do_cclosure_new (windowProc2, Widget.ACTIVATE, 0);
2442     closures [Widget.ACTIVATE_INVERSE] = do_cclosure_new (windowProc2, Widget.ACTIVATE_INVERSE, 0);
2443     closures [Widget.CHANGED] = do_cclosure_new (windowProc2, Widget.CHANGED, 0);
2444     closures [Widget.CLICKED] = do_cclosure_new (windowProc2, Widget.CLICKED, 0);
2445     closures [Widget.DAY_SELECTED] = do_cclosure_new (windowProc2, Widget.DAY_SELECTED, 0);
2446     closures [Widget.HIDE] = do_cclosure_new (windowProc2, Widget.HIDE, 0);
2447     closures [Widget.GRAB_FOCUS] = do_cclosure_new (windowProc2, Widget.GRAB_FOCUS, 0);
2448     closures [Widget.MAP] = do_cclosure_new (windowProc2, Widget.MAP, 0);
2449     closures [Widget.MONTH_CHANGED] = do_cclosure_new (windowProc2, Widget.MONTH_CHANGED, 0);
2450     closures [Widget.OUTPUT] = do_cclosure_new (windowProc2, Widget.OUTPUT, 0);
2451     closures [Widget.POPUP_MENU] = do_cclosure_new (windowProc2, Widget.POPUP_MENU, 0);
2452     closures [Widget.PREEDIT_CHANGED] = do_cclosure_new (windowProc2, Widget.PREEDIT_CHANGED, 0);
2453     closures [Widget.REALIZE] = do_cclosure_new (windowProc2, Widget.REALIZE, 0);
2454     closures [Widget.SELECT] = do_cclosure_new (windowProc2, Widget.SELECT, 0);
2455     closures [Widget.SHOW] = do_cclosure_new (windowProc2, Widget.SHOW, 0);
2456     closures [Widget.VALUE_CHANGED] = do_cclosure_new (windowProc2, Widget.VALUE_CHANGED, 0);
2457     closures [Widget.UNMAP] = do_cclosure_new (windowProc2, Widget.UNMAP, 0);
2458     closures [Widget.UNREALIZE] = do_cclosure_new (windowProc2, Widget.UNREALIZE, 0);
2459 
2460     GCallback windowProc3 = cast(GCallback)&windowProcFunc3;
2461     closures [Widget.BUTTON_PRESS_EVENT] = do_cclosure_new (windowProc3, Widget.BUTTON_PRESS_EVENT, 0);
2462     closures [Widget.BUTTON_PRESS_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.BUTTON_PRESS_EVENT_INVERSE, 0);
2463     closures [Widget.BUTTON_RELEASE_EVENT] = do_cclosure_new (windowProc3, Widget.BUTTON_RELEASE_EVENT, 0);
2464     closures [Widget.BUTTON_RELEASE_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.BUTTON_RELEASE_EVENT_INVERSE, 0);
2465     closures [Widget.COMMIT] = do_cclosure_new (windowProc3, Widget.COMMIT, 0);
2466     closures [Widget.CONFIGURE_EVENT] = do_cclosure_new (windowProc3, Widget.CONFIGURE_EVENT, 0);
2467     closures [Widget.DELETE_EVENT] = do_cclosure_new (windowProc3, Widget.DELETE_EVENT, 0);
2468     closures [Widget.ENTER_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.ENTER_NOTIFY_EVENT, 0);
2469     closures [Widget.EVENT] = do_cclosure_new (windowProc3, Widget.EVENT, 0);
2470     closures [Widget.EVENT_AFTER] = do_cclosure_new (windowProc3, Widget.EVENT_AFTER, 0);
2471     closures [Widget.EXPOSE_EVENT] = do_cclosure_new (windowProc3, Widget.EXPOSE_EVENT, 0);
2472     closures [Widget.EXPOSE_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.EXPOSE_EVENT_INVERSE, 0);
2473     closures [Widget.FOCUS] = do_cclosure_new (windowProc3, Widget.FOCUS, 0);
2474     closures [Widget.FOCUS_IN_EVENT] = do_cclosure_new (windowProc3, Widget.FOCUS_IN_EVENT, 0);
2475     closures [Widget.FOCUS_OUT_EVENT] = do_cclosure_new (windowProc3, Widget.FOCUS_OUT_EVENT, 0);
2476     closures [Widget.KEY_PRESS_EVENT] = do_cclosure_new (windowProc3, Widget.KEY_PRESS_EVENT, 0);
2477     closures [Widget.KEY_RELEASE_EVENT] = do_cclosure_new (windowProc3, Widget.KEY_RELEASE_EVENT, 0);
2478     closures [Widget.INPUT] = do_cclosure_new (windowProc3, Widget.INPUT, 0);
2479     closures [Widget.LEAVE_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.LEAVE_NOTIFY_EVENT, 0);
2480     closures [Widget.MAP_EVENT] = do_cclosure_new (windowProc3, Widget.MAP_EVENT, 0);
2481     closures [Widget.MNEMONIC_ACTIVATE] = do_cclosure_new (windowProc3, Widget.MNEMONIC_ACTIVATE, 0);
2482     closures [Widget.MOTION_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT, 0);
2483     closures [Widget.MOTION_NOTIFY_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT_INVERSE, 0);
2484     closures [Widget.MOVE_FOCUS] = do_cclosure_new (windowProc3, Widget.MOVE_FOCUS, 0);
2485     closures [Widget.POPULATE_POPUP] = do_cclosure_new (windowProc3, Widget.POPULATE_POPUP, 0);
2486     closures [Widget.SCROLL_EVENT] = do_cclosure_new (windowProc3, Widget.SCROLL_EVENT, 0);
2487     closures [Widget.SHOW_HELP] = do_cclosure_new (windowProc3, Widget.SHOW_HELP, 0);
2488     closures [Widget.SIZE_ALLOCATE] = do_cclosure_new (windowProc3, Widget.SIZE_ALLOCATE, 0);
2489     closures [Widget.STYLE_SET] = do_cclosure_new (windowProc3, Widget.STYLE_SET, 0);
2490     closures [Widget.TOGGLED] = do_cclosure_new (windowProc3, Widget.TOGGLED, 0);
2491     closures [Widget.UNMAP_EVENT] = do_cclosure_new (windowProc3, Widget.UNMAP_EVENT, 0);
2492     closures [Widget.VISIBILITY_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.VISIBILITY_NOTIFY_EVENT, 0);
2493     closures [Widget.WINDOW_STATE_EVENT] = do_cclosure_new (windowProc3, Widget.WINDOW_STATE_EVENT, 0);
2494 
2495     GCallback windowProc4 = cast(GCallback)&windowProcFunc4;
2496     closures [Widget.DELETE_RANGE] = do_cclosure_new (windowProc4, Widget.DELETE_RANGE, 0);
2497     closures [Widget.DELETE_TEXT] = do_cclosure_new (windowProc4, Widget.DELETE_TEXT, 0);
2498     closures [Widget.ROW_ACTIVATED] = do_cclosure_new (windowProc4, Widget.ROW_ACTIVATED, 0);
2499     closures [Widget.SCROLL_CHILD] = do_cclosure_new (windowProc4, Widget.SCROLL_CHILD, 0);
2500     closures [Widget.SWITCH_PAGE] = do_cclosure_new (windowProc4, Widget.SWITCH_PAGE, 0);
2501     closures [Widget.TEST_COLLAPSE_ROW] = do_cclosure_new (windowProc4, Widget.TEST_COLLAPSE_ROW, 0);
2502     closures [Widget.TEST_EXPAND_ROW] = do_cclosure_new (windowProc4, Widget.TEST_EXPAND_ROW, 0);
2503 
2504     GCallback windowProc5 = cast(GCallback)&windowProcFunc5;
2505     closures [Widget.EXPAND_COLLAPSE_CURSOR_ROW] = do_cclosure_new (windowProc5, Widget.EXPAND_COLLAPSE_CURSOR_ROW, 0);
2506     closures [Widget.INSERT_TEXT] = do_cclosure_new (windowProc5, Widget.INSERT_TEXT, 0);
2507     closures [Widget.TEXT_BUFFER_INSERT_TEXT] = do_cclosure_new (windowProc5, Widget.TEXT_BUFFER_INSERT_TEXT, 0);
2508 
2509     GCallback windowChangeValueProc = cast(GCallback)&windowProcChangeValueFunc;
2510     closures [Widget.CHANGE_VALUE] = do_cclosure_new (windowChangeValueProc, Widget.CHANGE_VALUE, 0);
2511 
2512     for (int i = 0; i < Widget.LAST_SIGNAL; i++) {
2513         if (closures [i] !is null) OS.g_closure_ref (closures [i]);
2514     }
2515     shellMapProcCallbackData.display = this;
2516     shellMapProcCallbackData.data = null;
2517     shellMapProcClosure = OS.g_cclosure_new (cast(GCallback)&shellMapProcFunc, &shellMapProcCallbackData, cast(GClosureNotify)0);
2518     OS.g_closure_ref (shellMapProcClosure);
2519 }
2520 
2521 void* getWindowProcUserData( int value ){
2522     return windowProcCallbackDatas[ value ];
2523 
2524 }
2525 
2526 void initializeSystemSettings () {
2527     styleSetProcCallbackData.display = this;
2528     styleSetProcCallbackData.data = null;
2529     OS.g_signal_connect (shellHandle, OS.style_set.ptr, cast(GCallback)&styleSetProcFunc, &styleSetProcCallbackData);
2530 
2531     /*
2532     * Feature in GTK.  Despite the fact that the
2533     * gtk-entry-select-on-focus property is a global
2534     * setting, it is initialized when the GtkEntry
2535     * is initialized.  This means that it cannot be
2536     * accessed before a GtkEntry is created.  The
2537     * fix is to for the initializaion by creating
2538     * a temporary GtkEntry.
2539     */
2540     auto entry = OS.gtk_entry_new ();
2541     OS.gtk_widget_destroy (entry);
2542     int buffer2;
2543     auto settings = OS.gtk_settings_get_default ();
2544     OS.g_object_get1 (settings, OS.gtk_entry_select_on_focus.ptr, &buffer2);
2545     entrySelectOnFocus = buffer2 !is 0;
2546 }
2547 
2548 void initializeWidgetTable () {
2549     indexTable = new ptrdiff_t [GROW_SIZE];
2550     widgetTable = new Widget [GROW_SIZE];
2551     for (int i=0; i<GROW_SIZE-1; i++) indexTable [i] = i + 1;
2552     indexTable [GROW_SIZE - 1] = -1;
2553 }
2554 
2555 void initializeWindowManager () {
2556     /* Get the window manager name */
2557     windowManager = ""; //$NON-NLS-1$
2558     if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 0)) {
2559         auto screen = OS.gdk_screen_get_default ();
2560         if (screen !is null) {
2561             auto ptr2 = OS.gdk_x11_screen_get_window_manager_name (screen);
2562             windowManager = fromStringz( ptr2 )._idup();
2563         }
2564     }
2565 }
2566 
2567 /**
2568  * Invokes platform specific functionality to dispose a GC handle.
2569  * <p>
2570  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
2571  * API for <code>Display</code>. It is marked public only so that it
2572  * can be shared within the packages provided by SWT. It is not
2573  * available on all platforms, and should never be called from
2574  * application code.
2575  * </p>
2576  *
2577  * @param hDC the platform specific GC handle
2578  * @param data the platform specific GC data
2579  */
2580 public override void internal_dispose_GC (GdkGC* gdkGC, GCData data) {
2581     OS.g_object_unref (gdkGC);
2582 }
2583 
2584 /**
2585  * Invokes platform specific functionality to allocate a new GC handle.
2586  * <p>
2587  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
2588  * API for <code>Display</code>. It is marked public only so that it
2589  * can be shared within the packages provided by SWT. It is not
2590  * available on all platforms, and should never be called from
2591  * application code.
2592  * </p>
2593  *
2594  * @param data the platform specific GC data
2595  * @return the platform specific GC handle
2596  *
2597  * @exception SWTException <ul>
2598  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2599  * </ul>
2600  * @exception SWTError <ul>
2601  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for gc creation</li>
2602  * </ul>
2603  */
2604 public override GdkGC* internal_new_GC (GCData data) {
2605     if (isDisposed()) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
2606     auto root = cast(GdkDrawable *) OS.GDK_ROOT_PARENT ();
2607     auto gdkGC = OS.gdk_gc_new (root);
2608     if (gdkGC is null) SWT.error (SWT.ERROR_NO_HANDLES);
2609     OS.gdk_gc_set_subwindow (gdkGC, OS.GDK_INCLUDE_INFERIORS);
2610     if (data !is null) {
2611         int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
2612         if ((data.style & mask) is 0) {
2613             data.style |= SWT.LEFT_TO_RIGHT;
2614         }
2615         data.device = this;
2616         data.drawable = root;
2617         data.background = getSystemColor (SWT.COLOR_WHITE).handle;
2618         data.foreground = getSystemColor (SWT.COLOR_BLACK).handle;
2619         data.font = getSystemFont ();
2620     }
2621     return gdkGC;
2622     return null;
2623 }
2624 
2625 bool isValidThread () {
2626     return thread is Thread.currentThread ();
2627 }
2628 
2629 /**
2630  * Maps a point from one coordinate system to another.
2631  * When the control is null, coordinates are mapped to
2632  * the display.
2633  * <p>
2634  * NOTE: On right-to-left platforms where the coordinate
2635  * systems are mirrored, special care needs to be taken
2636  * when mapping coordinates from one control to another
2637  * to ensure the result is correctly mirrored.
2638  *
2639  * Mapping a point that is the origin of a rectangle and
2640  * then adding the width and height is not equivalent to
2641  * mapping the rectangle.  When one control is mirrored
2642  * and the other is not, adding the width and height to a
2643  * point that was mapped causes the rectangle to extend
2644  * in the wrong direction.  Mapping the entire rectangle
2645  * instead of just one point causes both the origin and
2646  * the corner of the rectangle to be mapped.
2647  * </p>
2648  *
2649  * @param from the source <code>Control</code> or <code>null</code>
2650  * @param to the destination <code>Control</code> or <code>null</code>
2651  * @param point to be mapped
2652  * @return point with mapped coordinates
2653  *
2654  * @exception IllegalArgumentException <ul>
2655  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
2656  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2657  * </ul>
2658  * @exception SWTException <ul>
2659  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2660  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2661  * </ul>
2662  *
2663  * @since 2.1.2
2664  */
2665 public Point map (Control from, Control to, Point point) {
2666     checkDevice ();
2667     if (point is null) error (SWT.ERROR_NULL_ARGUMENT);
2668     return map (from, to, point.x, point.y);
2669 }
2670 
2671 /**
2672  * Maps a point from one coordinate system to another.
2673  * When the control is null, coordinates are mapped to
2674  * the display.
2675  * <p>
2676  * NOTE: On right-to-left platforms where the coordinate
2677  * systems are mirrored, special care needs to be taken
2678  * when mapping coordinates from one control to another
2679  * to ensure the result is correctly mirrored.
2680  *
2681  * Mapping a point that is the origin of a rectangle and
2682  * then adding the width and height is not equivalent to
2683  * mapping the rectangle.  When one control is mirrored
2684  * and the other is not, adding the width and height to a
2685  * point that was mapped causes the rectangle to extend
2686  * in the wrong direction.  Mapping the entire rectangle
2687  * instead of just one point causes both the origin and
2688  * the corner of the rectangle to be mapped.
2689  * </p>
2690  *
2691  * @param from the source <code>Control</code> or <code>null</code>
2692  * @param to the destination <code>Control</code> or <code>null</code>
2693  * @param x coordinates to be mapped
2694  * @param y coordinates to be mapped
2695  * @return point with mapped coordinates
2696  *
2697  * @exception IllegalArgumentException <ul>
2698  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2699  * </ul>
2700  * @exception SWTException <ul>
2701  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2702  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2703  * </ul>
2704  *
2705  * @since 2.1.2
2706  */
2707 public Point map (Control from, Control to, int x, int y) {
2708     checkDevice ();
2709     if (from !is null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2710     if (to !is null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2711     Point point = new Point (x, y);
2712     if (from is to) return point;
2713     if (from !is null) {
2714         auto window = from.eventWindow ();
2715         int origin_x, origin_y;
2716         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2717         if ((from.style & SWT.MIRRORED) !is 0) point.x = from.getClientWidth () - point.x;
2718         point.x += origin_x;
2719         point.y += origin_y;
2720     }
2721     if (to !is null) {
2722         auto window = to.eventWindow ();
2723         int origin_x, origin_y;
2724         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2725         point.x -= origin_x;
2726         point.y -= origin_y;
2727         if ((to.style & SWT.MIRRORED) !is 0) point.x = to.getClientWidth () - point.x;
2728     }
2729     return point;
2730 }
2731 
2732 /**
2733  * Maps a point from one coordinate system to another.
2734  * When the control is null, coordinates are mapped to
2735  * the display.
2736  * <p>
2737  * NOTE: On right-to-left platforms where the coordinate
2738  * systems are mirrored, special care needs to be taken
2739  * when mapping coordinates from one control to another
2740  * to ensure the result is correctly mirrored.
2741  *
2742  * Mapping a point that is the origin of a rectangle and
2743  * then adding the width and height is not equivalent to
2744  * mapping the rectangle.  When one control is mirrored
2745  * and the other is not, adding the width and height to a
2746  * point that was mapped causes the rectangle to extend
2747  * in the wrong direction.  Mapping the entire rectangle
2748  * instead of just one point causes both the origin and
2749  * the corner of the rectangle to be mapped.
2750  * </p>
2751  *
2752  * @param from the source <code>Control</code> or <code>null</code>
2753  * @param to the destination <code>Control</code> or <code>null</code>
2754  * @param rectangle to be mapped
2755  * @return rectangle with mapped coordinates
2756  *
2757  * @exception IllegalArgumentException <ul>
2758  *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
2759  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2760  * </ul>
2761  * @exception SWTException <ul>
2762  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2763  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2764  * </ul>
2765  *
2766  * @since 2.1.2
2767  */
2768 public Rectangle map (Control from, Control to, Rectangle rectangle) {
2769     checkDevice();
2770     if (rectangle is null) error (SWT.ERROR_NULL_ARGUMENT);
2771     return map (from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
2772 }
2773 
2774 static wchar mbcsToWcs (wchar ch) {
2775     int key = ch & 0xFFFF;
2776     if (key <= 0x7F) return ch;
2777     char [] buffer;
2778     if (key <= 0xFF) {
2779         buffer = new char [1];
2780         buffer [0] = cast(char) key;
2781     } else {
2782         buffer = new char [2];
2783         buffer [0] = cast(char) ((key >> 8) & 0xFF);
2784         buffer [1] = cast(char) (key & 0xFF);
2785     }
2786     wchar [] result = Converter.mbcsToWcs (null, buffer);
2787     if (result.length is 0) return 0;
2788     return result [0];
2789 }
2790 
2791 
2792 package void doMenuPositionProc( GtkMenu* window, bool hasLocation ){
2793     /*
2794     * Bug in GTK.  The timestamp passed into gtk_menu_popup is used
2795     * to perform an X pointer grab.  It cannot be zero, else the grab
2796     * will fail.  The fix is to ensure that the timestamp of the last
2797     * event processed is used.
2798     */
2799     OS.gtk_menu_popup (window, null, null,
2800         hasLocation ? &menuPositionProcFunc : null,
2801         cast(void*)this, 0, getLastEventTime() );
2802 }
2803 
2804 private static extern(C) void menuPositionProcFunc (GtkMenu* menu, int* x, int* y, int* push_in, void* user_data) {
2805     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
2806     auto display = cast(Display)user_data;
2807     display.menuPositionProc( menu, x, y, push_in, null );
2808 }
2809 
2810 void menuPositionProc (GtkMenu* menu, int* x, int* y, int* push_in, void* user_data) {
2811     Widget widget = getWidget (cast(GtkWidget*)menu);
2812     if (widget is null) return;
2813     widget.menuPositionProc (menu, x, y, push_in, user_data);
2814 }
2815 
2816 /**
2817  * Maps a point from one coordinate system to another.
2818  * When the control is null, coordinates are mapped to
2819  * the display.
2820  * <p>
2821  * NOTE: On right-to-left platforms where the coordinate
2822  * systems are mirrored, special care needs to be taken
2823  * when mapping coordinates from one control to another
2824  * to ensure the result is correctly mirrored.
2825  *
2826  * Mapping a point that is the origin of a rectangle and
2827  * then adding the width and height is not equivalent to
2828  * mapping the rectangle.  When one control is mirrored
2829  * and the other is not, adding the width and height to a
2830  * point that was mapped causes the rectangle to extend
2831  * in the wrong direction.  Mapping the entire rectangle
2832  * instead of just one point causes both the origin and
2833  * the corner of the rectangle to be mapped.
2834  * </p>
2835  *
2836  * @param from the source <code>Control</code> or <code>null</code>
2837  * @param to the destination <code>Control</code> or <code>null</code>
2838  * @param x coordinates to be mapped
2839  * @param y coordinates to be mapped
2840  * @param width coordinates to be mapped
2841  * @param height coordinates to be mapped
2842  * @return rectangle with mapped coordinates
2843  *
2844  * @exception IllegalArgumentException <ul>
2845  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2846  * </ul>
2847  * @exception SWTException <ul>
2848  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2849  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2850  * </ul>
2851  *
2852  * @since 2.1.2
2853  */
2854 public Rectangle map (Control from, Control to, int x, int y, int width, int height) {
2855     checkDevice();
2856     if (from !is null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2857     if (to !is null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2858     Rectangle rect = new Rectangle (x, y, width, height);
2859     if (from is to) return rect;
2860     bool fromRTL = false, toRTL = false;
2861     if (from !is null) {
2862         auto window = from.eventWindow ();
2863         int origin_x, origin_y;
2864         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2865         fromRTL = (from.style & SWT.MIRRORED) !is 0;
2866         if (fromRTL) rect.x = from.getClientWidth() - rect.x;
2867         rect.x += origin_x;
2868         rect.y += origin_y;
2869     }
2870     if (to !is null) {
2871         auto window = to.eventWindow ();
2872         int origin_x, origin_y;
2873         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2874         rect.x -= origin_x;
2875         rect.y -= origin_y;
2876         toRTL = (to.style & SWT.MIRRORED) !is 0;
2877         if (toRTL) rect.x = to.getClientWidth () - rect.x;
2878     }
2879     if (fromRTL !is toRTL) rect.x -= rect.width;
2880     return rect;
2881 }
2882 
2883 private static extern(C) int mouseHoverProcFunc ( void* user_data) {
2884     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
2885     CallbackData* cbdata = cast(CallbackData*)user_data;
2886     return cbdata.display.mouseHoverProc( cast(GtkWidget*)cbdata.data );
2887 }
2888 int mouseHoverProc (GtkWidget* handle) {
2889     Widget widget = getWidget (handle);
2890     if (widget is null) return 0;
2891     return widget.hoverProc (handle);
2892 }
2893 
2894 /**
2895  * Generate a low level system event.
2896  *
2897  * <code>post</code> is used to generate low level keyboard
2898  * and mouse events. The intent is to enable automated UI
2899  * testing by simulating the input from the user.  Most
2900  * SWT applications should never need to call this method.
2901  * <p>
2902  * Note that this operation can fail when the operating system
2903  * fails to generate the event for any reason.  For example,
2904  * this can happen when there is no such key or mouse button
2905  * or when the system event queue is full.
2906  * </p>
2907  * <p>
2908  * <b>Event Types:</b>
2909  * <p>KeyDown, KeyUp
2910  * <p>The following fields in the <code>Event</code> apply:
2911  * <ul>
2912  * <li>(in) type KeyDown or KeyUp</li>
2913  * <p> Either one of:
2914  * <li>(in) character a character that corresponds to a keyboard key</li>
2915  * <li>(in) keyCode the key code of the key that was typed,
2916  *          as defined by the key code constants in class <code>SWT</code></li>
2917  * </ul>
2918  * <p>MouseDown, MouseUp</p>
2919  * <p>The following fields in the <code>Event</code> apply:
2920  * <ul>
2921  * <li>(in) type MouseDown or MouseUp
2922  * <li>(in) button the button that is pressed or released
2923  * </ul>
2924  * <p>MouseMove</p>
2925  * <p>The following fields in the <code>Event</code> apply:
2926  * <ul>
2927  * <li>(in) type MouseMove
2928  * <li>(in) x the x coordinate to move the mouse pointer to in screen coordinates
2929  * <li>(in) y the y coordinate to move the mouse pointer to in screen coordinates
2930  * </ul>
2931  * </dl>
2932  *
2933  * @param event the event to be generated
2934  *
2935  * @return true if the event was generated or false otherwise
2936  *
2937  * @exception IllegalArgumentException <ul>
2938  *    <li>ERROR_NULL_ARGUMENT - if the event is null</li>
2939  * </ul>
2940  * @exception SWTException <ul>
2941  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2942  * </ul>
2943  *
2944  * @since 3.0
2945  *
2946  */
2947 public bool post (Event event) {
2948     synchronized (Device.classinfo) {
2949         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2950         if (event is null) error (SWT.ERROR_NULL_ARGUMENT);
2951         if (!OS.GDK_WINDOWING_X11()) return false;
2952         auto xDisplay = OS.GDK_DISPLAY ();
2953         int type = event.type;
2954         switch (type) {
2955             case SWT.KeyDown:
2956             case SWT.KeyUp: {
2957                 int keyCode = 0;
2958                 auto keysym = untranslateKey (event.keyCode);
2959                 if (keysym !is 0) keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
2960                 if (keyCode is 0) {
2961                     char key = cast(char) event.character;
2962                     switch (key) {
2963                         case SWT.BS: keysym = OS.GDK_BackSpace; break;
2964                         case SWT.CR: keysym = OS.GDK_Return; break;
2965                         case SWT.DEL: keysym = OS.GDK_Delete; break;
2966                         case SWT.ESC: keysym = OS.GDK_Escape; break;
2967                         case SWT.TAB: keysym = OS.GDK_Tab; break;
2968                         case SWT.LF: keysym = OS.GDK_Linefeed; break;
2969                         default:
2970                             keysym = key;
2971                     }
2972                     keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
2973                     if (keyCode is 0) return false;
2974                 }
2975                 OS.XTestFakeKeyEvent (xDisplay, keyCode, type is SWT.KeyDown, 0);
2976                 return true;
2977             }
2978             case SWT.MouseDown:
2979             case SWT.MouseMove:
2980             case SWT.MouseUp: {
2981                 if (type is SWT.MouseMove) {
2982                     OS.XTestFakeMotionEvent (xDisplay, -1, event.x, event.y, 0);
2983                 } else {
2984                     int button = event.button;
2985                     switch (button) {
2986                         case 1:
2987                         case 2:
2988                         case 3: break;
2989                         case 4: button = 6; break;
2990                         case 5: button = 7; break;
2991                         default: return false;
2992                     }
2993                     OS.XTestFakeButtonEvent (xDisplay, button, type is SWT.MouseDown, 0);
2994                 }
2995                 return true;
2996         default:
2997             }
2998             /*
2999             * This code is intentionally commented. After posting a
3000             * mouse wheel event the system may respond unpredictably
3001             * to subsequent mouse actions.
3002             */
3003 //          case SWT.MouseWheel: {
3004 //              if (event.count is 0) return false;
3005 //              int button = event.count < 0 ? 5 : 4;
3006 //              OS.XTestFakeButtonEvent (xDisplay, button, type is SWT.MouseWheel, 0);
3007 //          }
3008         }
3009         return false;
3010     }
3011 }
3012 
3013 void postEvent (Event event) {
3014     /*
3015     * Place the event at the end of the event queue.
3016     * This code is always called in the Display's
3017     * thread so it must be re-enterant but does not
3018     * need to be synchronized.
3019     */
3020     if (eventQueue is null) eventQueue = new Event [4];
3021     ptrdiff_t index = 0;
3022     ptrdiff_t length = eventQueue.length;
3023     while (index < length) {
3024         if (eventQueue [index] is null) break;
3025         index++;
3026     }
3027     if (index is length) {
3028         Event [] newQueue = new Event [length + 4];
3029         System.arraycopy (eventQueue, 0, newQueue, 0, length);
3030         eventQueue = newQueue;
3031     }
3032     eventQueue [index] = event;
3033 }
3034 
3035 void putGdkEvents () {
3036     if (gdkEventCount !is 0) {
3037         for (int i = 0; i < gdkEventCount; i++) {
3038             auto event = gdkEvents [i];
3039             Widget widget = gdkEventWidgets [i];
3040             if (widget is null || !widget.isDisposed ()) {
3041                 OS.gdk_event_put (event);
3042             }
3043             OS.gdk_event_free (event);
3044             gdkEvents [i] = null;
3045             gdkEventWidgets [i] = null;
3046         }
3047         gdkEventCount = 0;
3048     }
3049 }
3050 
3051 /**
3052  * Reads an event from the operating system's event queue,
3053  * dispatches it appropriately, and returns <code>true</code>
3054  * if there is potentially more work to do, or <code>false</code>
3055  * if the caller can sleep until another event is placed on
3056  * the event queue.
3057  * <p>
3058  * In addition to checking the system event queue, this method also
3059  * checks if any inter-thread messages (created by <code>syncExec()</code>
3060  * or <code>asyncExec()</code>) are waiting to be processed, and if
3061  * so handles them before returning.
3062  * </p>
3063  *
3064  * @return <code>false</code> if the caller can sleep upon return from this method
3065  *
3066  * @exception SWTException <ul>
3067  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3068  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3069  *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
3070  * </ul>
3071  *
3072  * @see #sleep
3073  * @see #wake
3074  */
3075 public bool readAndDispatch () {
3076     checkDevice ();
3077     bool events = false;
3078     events |= runSettings ();
3079     events |= runPopups ();
3080     events |= cast(bool)OS.g_main_context_iteration (null, false);
3081     if (events) {
3082         runDeferredEvents ();
3083         return true;
3084     }
3085     return runAsyncMessages (false);
3086 }
3087 
3088 static void register (Display display) {
3089     synchronized (Device.classinfo) {
3090         for (int i=0; i<Displays.length; i++) {
3091             if (Displays [i] is null) {
3092                 Displays [i] = display;
3093                 return;
3094             }
3095         }
3096         Display [] newDisplays = new Display [Displays.length + 4];
3097         System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
3098         newDisplays [Displays.length] = display;
3099         Displays = newDisplays;
3100     }
3101 }
3102 
3103 /**
3104  * Releases any internal resources back to the operating
3105  * system and clears all fields except the device handle.
3106  * <p>
3107  * Disposes all shells which are currently open on the display.
3108  * After this method has been invoked, all related related shells
3109  * will answer <code>true</code> when sent the message
3110  * <code>isDisposed()</code>.
3111  * </p><p>
3112  * When a device is destroyed, resources that were acquired
3113  * on behalf of the programmer need to be returned to the
3114  * operating system.  For example, if the device allocated a
3115  * font to be used as the system font, this font would be
3116  * freed in <code>release</code>.  Also,to assist the garbage
3117  * collector and minimize the amount of memory that is not
3118  * reclaimed when the programmer keeps a reference to a
3119  * disposed device, all fields except the handle are zero'd.
3120  * The handle is needed by <code>destroy</code>.
3121  * </p>
3122  * This method is called before <code>destroy</code>.
3123  *
3124  * @see Device#dispose
3125  * @see #destroy
3126  */
3127 protected override void release () {
3128     sendEvent (SWT.Dispose, new Event ());
3129     Shell [] shells = getShells ();
3130     for (int i=0; i<shells.length; i++) {
3131         Shell shell = shells [i];
3132         if (!shell.isDisposed ())  shell.dispose ();
3133     }
3134     if (tray !is null) tray.dispose ();
3135     tray = null;
3136     while (readAndDispatch ()) {}
3137     if (disposeList !is null) {
3138         for (int i=0; i<disposeList.length; i++) {
3139             if (disposeList [i] !is null) disposeList [i].run ();
3140         }
3141     }
3142     disposeList = null;
3143     synchronizer.releaseSynchronizer ();
3144     synchronizer = null;
3145     releaseDisplay ();
3146     super.release ();
3147 }
3148 
3149 void releaseDisplay () {
3150 
3151     /* Dispose xfilter callback */
3152     OS.gdk_window_remove_filter(null, &filterProcFunc, null);
3153 
3154     /* Dispose checkIfEvent callback */
3155 
3156     /* Dispose preedit window */
3157     if (preeditWindow !is null) OS.gtk_widget_destroy ( &preeditWindow.bin.container.widget);
3158     imControl = null;
3159 
3160     /* Dispose the menu callback */
3161 
3162     /* Dispose the tooltip map callback */
3163 
3164     /* Dispose the shell map callback */
3165 
3166     /* Dispose the run async messages callback */
3167     if (idleHandle !is 0) OS.g_source_remove (idleHandle);
3168     idleHandle = 0;
3169 
3170     /* Dispose GtkTreeView callbacks */
3171 
3172     /* Dispose the set direction callback */
3173 
3174     /* Dispose the emission proc callback */
3175 
3176     /* Dispose the set direction callback */
3177 
3178     /* Dispose the caret callback */
3179     if (caretId !is 0) OS.gtk_timeout_remove (caretId);
3180     caretId = 0;
3181 
3182     /* Release closures */
3183     for (int i = 0; i < Widget.LAST_SIGNAL; i++) {
3184         if (closures [i] !is null) OS.g_closure_unref (closures [i]);
3185     }
3186     if (shellMapProcClosure !is null) OS.g_closure_unref (shellMapProcClosure);
3187 
3188     /* Dispose the timer callback */
3189     if (timerIds !is null) {
3190         for (int i=0; i<timerIds.length; i++) {
3191             if (timerIds [i] !is 0) OS.gtk_timeout_remove (timerIds [i]);
3192         }
3193     }
3194     timerIds = null;
3195     timerList = null;
3196 
3197     /* Dispose mouse hover callback */
3198     if (mouseHoverId !is 0) OS.gtk_timeout_remove (mouseHoverId);
3199     mouseHoverId = 0;
3200     mouseHoverHandle = null;
3201 
3202     /* Dispose the default font */
3203     if (systemFont !is null) systemFont.dispose ();
3204     systemFont = null;
3205 
3206     /* Dispose the System Images */
3207     if (errorImage !is null) errorImage.dispose();
3208     if (infoImage !is null) infoImage.dispose();
3209     if (questionImage !is null) questionImage.dispose();
3210     if (warningImage !is null) warningImage.dispose();
3211     errorImage = infoImage = questionImage = warningImage = null;
3212 
3213     /* Release the System Cursors */
3214     for (int i = 0; i < cursors.length; i++) {
3215         if (cursors [i] !is null) cursors [i].dispose ();
3216     }
3217     cursors = null;
3218 
3219     /* Release Acquired Resources */
3220     if (resources !is null) {
3221         for (int i=0; i<resources.length; i++) {
3222             if (resources [i] !is null) resources [i].dispose ();
3223         }
3224         resources = null;
3225     }
3226 
3227     /* Release the System Colors */
3228     COLOR_WIDGET_DARK_SHADOW = COLOR_WIDGET_NORMAL_SHADOW = COLOR_WIDGET_LIGHT_SHADOW =
3229     COLOR_WIDGET_HIGHLIGHT_SHADOW = COLOR_WIDGET_BACKGROUND = COLOR_WIDGET_BORDER =
3230     COLOR_LIST_FOREGROUND = COLOR_LIST_BACKGROUND = COLOR_LIST_SELECTION = COLOR_LIST_SELECTION_TEXT =
3231     COLOR_WIDGET_FOREGROUND = COLOR_TITLE_FOREGROUND = COLOR_TITLE_BACKGROUND = COLOR_TITLE_BACKGROUND_GRADIENT =
3232     COLOR_TITLE_INACTIVE_FOREGROUND = COLOR_TITLE_INACTIVE_BACKGROUND = COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT =
3233     COLOR_INFO_BACKGROUND = COLOR_INFO_FOREGROUND = null;
3234 
3235     /* Dispose the event callback */
3236     OS.gdk_event_handler_set (null, null, null);
3237 
3238     /* Dispose the hidden shell */
3239     if (shellHandle !is null) OS.gtk_widget_destroy (shellHandle);
3240     shellHandle = null;
3241 
3242     /* Dispose the settings callback */
3243 
3244     /* Release the sleep resources */
3245     max_priority = 0;
3246     timeout = 0;
3247     if (fds !is null) OS.g_free (fds.ptr);
3248     fds = null;
3249 
3250     /* Release references */
3251     popups = null;
3252     thread = null;
3253     lastWidget = activeShell = null;
3254     //flushData = null;
3255     closures = null;
3256     indexTable = null;
3257     signalIds = null;
3258     treeSelection = null;
3259     widgetTable = null;
3260     modalShells = null;
3261     data = null;
3262     values = null;
3263     keys = null;
3264     windowManager = null;
3265     eventTable = filterTable = null;
3266     modalDialog = null;
3267     flushRect = null;
3268     exposeEvent = null;
3269     visibilityEvent = null;
3270     idleLock = null;
3271 }
3272 
3273 /**
3274  * Removes the listener from the collection of listeners who will
3275  * be notified when an event of the given type occurs anywhere in
3276  * a widget. The event type is one of the event constants defined
3277  * in class <code>SWT</code>.
3278  *
3279  * @param eventType the type of event to listen for
3280  * @param listener the listener which should no longer be notified when the event occurs
3281  *
3282  * @exception IllegalArgumentException <ul>
3283  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3284  * </ul>
3285  * @exception SWTException <ul>
3286  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3287  * </ul>
3288  *
3289  * @see Listener
3290  * @see SWT
3291  * @see #addFilter
3292  * @see #addListener
3293  *
3294  * @since 3.0
3295  */
3296 public void removeFilter (int eventType, Listener listener) {
3297     checkDevice ();
3298     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
3299     if (filterTable is null) return;
3300     filterTable.unhook (eventType, listener);
3301     if (filterTable.size () is 0) filterTable = null;
3302 }
3303 
3304 GdkEvent* removeGdkEvent () {
3305     if (gdkEventCount is 0) return null;
3306     auto event = gdkEvents [0];
3307     --gdkEventCount;
3308     SimpleType!(GdkEvent*).arraycopy (gdkEvents, 1, gdkEvents, 0, gdkEventCount);
3309     System.arraycopy (gdkEventWidgets, 1, gdkEventWidgets, 0, gdkEventCount);
3310     gdkEvents [gdkEventCount] = null;
3311     gdkEventWidgets [gdkEventCount] = null;
3312     if (gdkEventCount is 0) {
3313         gdkEvents = null;
3314         gdkEventWidgets = null;
3315     }
3316     return event;
3317 }
3318 
3319 void removeIdleProc () {
3320     synchronized (idleLock) {
3321         if (idleHandle !is 0) OS.g_source_remove (idleHandle);
3322         idleNeeded = false;
3323         idleHandle = 0;
3324     }
3325 }
3326 /**
3327  * Removes the listener from the collection of listeners who will
3328  * be notified when an event of the given type occurs. The event type
3329  * is one of the event constants defined in class <code>SWT</code>.
3330  *
3331  * @param eventType the type of event to listen for
3332  * @param listener the listener which should no longer be notified
3333  *
3334  * @exception IllegalArgumentException <ul>
3335  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3336  * </ul>
3337  * @exception SWTException <ul>
3338  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3339  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3340  * </ul>
3341  *
3342  * @see Listener
3343  * @see SWT
3344  * @see #addListener
3345  *
3346  * @since 2.0
3347  */
3348 public void removeListener (int eventType, Listener listener) {
3349     checkDevice ();
3350     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
3351     if (eventTable is null) return;
3352     eventTable.unhook (eventType, listener);
3353 }
3354 
3355 void removeMouseHoverTimeout (void* handle) {
3356     if (handle !is mouseHoverHandle) return;
3357     if (mouseHoverId !is 0) OS.gtk_timeout_remove (mouseHoverId);
3358     mouseHoverId = 0;
3359     mouseHoverHandle = null;
3360 }
3361 
3362 void removePopup (Menu menu) {
3363     if (popups is null) return;
3364     for (int i=0; i<popups.length; i++) {
3365         if (popups [i] is menu) {
3366             popups [i] = null;
3367             return;
3368         }
3369     }
3370 }
3371 
3372 Widget removeWidget (GtkWidget* handle) {
3373     if (handle is null) return null;
3374     lastWidget = null;
3375     Widget widget = null;
3376     auto index = cast(ptrdiff_t)OS.g_object_get_qdata (cast(GObject*)handle, SWT_OBJECT_INDEX) - 1;
3377     if (0 <= index && index < widgetTable.length) {
3378         widget = widgetTable [index];
3379         widgetTable [index] = null;
3380         indexTable [index] = freeSlot;
3381         freeSlot = index;
3382         OS.g_object_set_qdata (cast(GObject*)handle, SWT_OBJECT_INDEX, null);
3383     }
3384     return widget;
3385 }
3386 
3387 bool runAsyncMessages (bool all) {
3388     return synchronizer.runAsyncMessages (all);
3389 }
3390 
3391 bool runDeferredEvents () {
3392     /*
3393     * Run deferred events.  This code is always
3394     * called in the Display's thread so it must
3395     * be re-enterant but need not be synchronized.
3396     */
3397     while (eventQueue !is null) {
3398 
3399         /* Take an event off the queue */
3400         Event event = eventQueue [0];
3401         if (event is null) break;
3402         ptrdiff_t len = eventQueue.length;
3403         System.arraycopy (eventQueue, 1, eventQueue, 0, --len);
3404         eventQueue [len] = null;
3405 
3406         /* Run the event */
3407         Widget widget = event.widget;
3408         if (widget !is null && !widget.isDisposed ()) {
3409             Widget item = event.item;
3410             if (item is null || !item.isDisposed ()) {
3411                 widget.sendEvent (event);
3412             }
3413         }
3414 
3415         /*
3416         * At this point, the event queue could
3417         * be null due to a recursive invokation
3418         * when running the event.
3419         */
3420     }
3421 
3422     /* Clear the queue */
3423     eventQueue = null;
3424     return true;
3425 }
3426 
3427 bool runPopups () {
3428     if (popups is null) return false;
3429     bool result = false;
3430     while (popups !is null) {
3431         Menu menu = popups [0];
3432         if (menu is null) break;
3433         ptrdiff_t len = popups.length;
3434         System.arraycopy (popups, 1, popups, 0, --len);
3435         popups [len] = null;
3436         runDeferredEvents ();
3437         if (!menu.isDisposed ()) menu._setVisible (true);
3438         result = true;
3439     }
3440     popups = null;
3441     return result;
3442 }
3443 
3444 bool runSettings () {
3445     if (!runSettingsFld) return false;
3446     runSettingsFld = false;
3447     saveResources ();
3448     initializeSystemColors ();
3449     sendEvent (SWT.Settings, null);
3450     Shell [] shells = getShells ();
3451     for (int i=0; i<shells.length; i++) {
3452         Shell shell = shells [i];
3453         if (!shell.isDisposed ()) {
3454             shell.fixStyle ();
3455             shell.redraw (true);
3456             shell.layout (true, true);
3457         }
3458     }
3459     return true;
3460 }
3461 
3462 /**
3463  * On platforms which support it, sets the application name
3464  * to be the argument. On Motif, for example, this can be used
3465  * to set the name used for resource lookup.  Specifying
3466  * <code>null</code> for the name clears it.
3467  *
3468  * @param name the new app name or <code>null</code>
3469  */
3470 public static void setAppName (String name) {
3471     APP_NAME = name;
3472 }
3473 
3474 /**
3475  * Sets the location of the on-screen pointer relative to the top left corner
3476  * of the screen.  <b>Note: It is typically considered bad practice for a
3477  * program to move the on-screen pointer location.</b>
3478  *
3479  * @param x the new x coordinate for the cursor
3480  * @param y the new y coordinate for the cursor
3481  *
3482  * @exception SWTException <ul>
3483  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3484  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3485  * </ul>
3486  *
3487  * @since 2.1
3488  */
3489 public void setCursorLocation (int x, int y) {
3490     checkDevice ();
3491     if (OS.GDK_WINDOWING_X11 ()) {
3492         auto xDisplay = OS.GDK_DISPLAY ();
3493         auto xWindow = OS.XDefaultRootWindow (xDisplay);
3494         OS.XWarpPointer (xDisplay, OS.None, xWindow, 0, 0, 0, 0, x, y);
3495     }
3496 }
3497 
3498 /**
3499  * Sets the location of the on-screen pointer relative to the top left corner
3500  * of the screen.  <b>Note: It is typically considered bad practice for a
3501  * program to move the on-screen pointer location.</b>
3502  *
3503  * @param point new position
3504  *
3505  * @exception SWTException <ul>
3506  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3507  *    <li>ERROR_NULL_ARGUMENT - if the point is null
3508  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3509  * </ul>
3510  *
3511  * @since 2.0
3512  */
3513 public void setCursorLocation (Point point) {
3514     checkDevice ();
3515     if (point is null) error (SWT.ERROR_NULL_ARGUMENT);
3516     setCursorLocation (point.x, point.y);
3517 }
3518 
3519 /**
3520  * Sets the application defined property of the receiver
3521  * with the specified name to the given argument.
3522  * <p>
3523  * Applications may have associated arbitrary objects with the
3524  * receiver in this fashion. If the objects stored in the
3525  * properties need to be notified when the display is disposed
3526  * of, it is the application's responsibility provide a
3527  * <code>disposeExec()</code> handler which does so.
3528  * </p>
3529  *
3530  * @param key the name of the property
3531  * @param value the new value for the property
3532  *
3533  * @exception SWTException <ul>
3534  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3535  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3536  * </ul>
3537  *
3538  * @see #getData(String)
3539  * @see #disposeExec(Runnable)
3540  */
3541 public void setData (String key, Object value) {
3542     checkDevice ();
3543     // SWT extension: allow null for zero length string
3544     //if (key is null) error (SWT.ERROR_NULL_ARGUMENT);
3545 
3546     if (key.equals (DISPATCH_EVENT_KEY)) {
3547         ArrayWrapperInt wrappedValue;
3548         if (value is null || (null !is (wrappedValue=cast(ArrayWrapperInt)value))) {
3549             if (wrappedValue is null) {
3550                 dispatchEvents = [];
3551             } else {
3552                 dispatchEvents = wrappedValue.array;
3553             }
3554             if (value is null) putGdkEvents ();
3555             return;
3556         }
3557     }
3558     if (key.equals (SET_MODAL_DIALOG)) {
3559         setModalDialog (cast(Dialog) data);
3560         return;
3561     }
3562 
3563     if (key.equals (ADD_WIDGET_KEY)) {
3564         auto wrap = cast(ArrayWrapperObject) value;
3565         if( wrap is null ) SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " []");
3566         Object [] data = wrap.array;
3567         auto handle = (cast(LONG) data [0]).intValue;
3568         Widget widget = cast(Widget) data [1];
3569         if (widget !is null) {
3570             addWidget (cast(GtkWidget*)handle, widget);
3571         } else {
3572             removeWidget (cast(GtkWidget*)handle);
3573         }
3574     }
3575 
3576     if (key==/*eq*/ ADD_IDLE_PROC_KEY) {
3577         addIdleProc ();
3578         return;
3579     }
3580     if (key==/*eq*/ REMOVE_IDLE_PROC_KEY) {
3581         removeIdleProc ();
3582         return;
3583     }
3584 
3585     /* Remove the key/value pair */
3586     if (value is null) {
3587         if (keys is null) return;
3588         int index = 0;
3589         while (index < keys.length && keys [index]!=/*!eq*/ key) index++;
3590         if (index is keys.length) return;
3591         if (keys.length is 1) {
3592             keys = null;
3593             values = null;
3594         } else {
3595             String [] newKeys = new String [keys.length - 1];
3596             Object [] newValues = new Object [values.length - 1];
3597             System.arraycopy (keys, 0, newKeys, 0, index);
3598             System.arraycopy (keys, index + 1, newKeys, index, newKeys.length - index);
3599             System.arraycopy (values, 0, newValues, 0, index);
3600             System.arraycopy (values, index + 1, newValues, index, newValues.length - index);
3601             keys = newKeys;
3602             values = newValues;
3603         }
3604         return;
3605     }
3606 
3607     /* Add the key/value pair */
3608     if (keys is null) {
3609         keys = [key];
3610         values = [value];
3611         return;
3612     }
3613     for (int i=0; i<keys.length; i++) {
3614         if (keys [i]==/*eq*/ key) {
3615             values [i] = value;
3616             return;
3617         }
3618     }
3619     String [] newKeys = new String [keys.length + 1];
3620     Object [] newValues = new Object [values.length + 1];
3621     System.arraycopy (keys, 0, newKeys, 0, keys.length);
3622     System.arraycopy (values, 0, newValues, 0, values.length);
3623     newKeys [keys.length] = key;
3624     newValues [values.length] = value;
3625     keys = newKeys;
3626     values = newValues;
3627 }
3628 
3629 /**
3630  * Sets the application defined, display specific data
3631  * associated with the receiver, to the argument.
3632  * The <em>display specific data</em> is a single,
3633  * unnamed field that is stored with every display.
3634  * <p>
3635  * Applications may put arbitrary objects in this field. If
3636  * the object stored in the display specific data needs to
3637  * be notified when the display is disposed of, it is the
3638  * application's responsibility provide a
3639  * <code>disposeExec()</code> handler which does so.
3640  * </p>
3641  *
3642  * @param data the new display specific data
3643  *
3644  * @exception SWTException <ul>
3645  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3646  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3647  * </ul>
3648  *
3649  * @see #getData()
3650  * @see #disposeExec(Runnable)
3651  */
3652 public void setData (Object data) {
3653     checkDevice ();
3654     this.data = data;
3655 }
3656 
3657 
3658 void doSetDirectionProc( GtkWidget* widget, int direction ){
3659     setDirectionProcCallbackData.display = this;
3660     setDirectionProcCallbackData.data = cast(void*)direction;
3661     OS.gtk_container_forall (cast(GtkContainer*)widget, cast(GtkCallback)&setDirectionProcFunc, &setDirectionProcCallbackData);
3662 }
3663 
3664 package static extern(C) ptrdiff_t setDirectionProcFunc (GtkWidget* widget, void* data) {
3665     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3666     CallbackData* cbdata = cast(CallbackData*)data;
3667     return cbdata.display.setDirectionProc( widget, cast(int)cbdata.data );
3668 }
3669 ptrdiff_t setDirectionProc (GtkWidget* widget, int direction) {
3670     OS.gtk_widget_set_direction (widget,  direction);
3671     if (OS.GTK_IS_MENU_ITEM (widget)) {
3672         auto submenu = OS.gtk_menu_item_get_submenu (widget);
3673         if (submenu !is null) {
3674             OS.gtk_widget_set_direction (submenu, direction);
3675             OS.gtk_container_forall (cast(GtkContainer*)submenu, cast(GtkCallback)&setDirectionProcFunc, cast(void*)direction);
3676         }
3677     }
3678     if (OS.GTK_IS_CONTAINER (cast(GTypeInstance*)widget)) {
3679         OS.gtk_container_forall (cast(GtkContainer*)widget, cast(GtkCallback)&setDirectionProcFunc, cast(void*)direction);
3680     }
3681     return 0;
3682 }
3683 
3684 void setModalDialog (Dialog modalDailog) {
3685     this.modalDialog = modalDailog;
3686     Shell [] shells = getShells ();
3687     for (int i=0; i<shells.length; i++) shells [i].updateModal ();
3688 }
3689 
3690 void setModalShell (Shell shell) {
3691     if (modalShells is null) modalShells = new Shell [4];
3692     ptrdiff_t index = 0, length = modalShells.length;
3693     while (index < length) {
3694         if (modalShells [index] is shell) return;
3695         if (modalShells [index] is null) break;
3696         index++;
3697     }
3698     if (index is length) {
3699         Shell [] newModalShells = new Shell [length + 4];
3700         System.arraycopy (modalShells, 0, newModalShells, 0, length);
3701         modalShells = newModalShells;
3702     }
3703     modalShells [index] = shell;
3704     Shell [] shells = getShells ();
3705     for (int i=0; i<shells.length; i++) shells [i].updateModal ();
3706 }
3707 
3708 /**
3709  * Sets the synchronizer used by the display to be
3710  * the argument, which can not be null.
3711  *
3712  * @param synchronizer the new synchronizer for the display (must not be null)
3713  *
3714  * @exception IllegalArgumentException <ul>
3715  *    <li>ERROR_NULL_ARGUMENT - if the synchronizer is null</li>
3716  * </ul>
3717  * @exception SWTException <ul>
3718  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3719  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3720  *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
3721  * </ul>
3722  */
3723 public void setSynchronizer (Synchronizer synchronizer) {
3724     checkDevice ();
3725     if (synchronizer is null) error (SWT.ERROR_NULL_ARGUMENT);
3726     if (synchronizer is this.synchronizer) return;
3727     Synchronizer oldSynchronizer;
3728     synchronized (Device.classinfo) {
3729         oldSynchronizer = this.synchronizer;
3730         this.synchronizer = synchronizer;
3731     }
3732     if (oldSynchronizer !is null) {
3733         oldSynchronizer.runAsyncMessages(true);
3734     }
3735 }
3736 
3737 void showIMWindow (Control control) {
3738     imControl = control;
3739     if (preeditWindow is null) {
3740         preeditWindow = cast(GtkWindow*)OS.gtk_window_new (OS.GTK_WINDOW_POPUP);
3741         if (preeditWindow is null) error (SWT.ERROR_NO_HANDLES);
3742         preeditLabel = cast(GtkLabel*) OS.gtk_label_new (null);
3743         if (preeditLabel is null) error (SWT.ERROR_NO_HANDLES);
3744         OS.gtk_container_add (cast(GtkContainer*)preeditWindow, cast(GtkWidget*) preeditLabel);
3745         OS.gtk_widget_show (cast(GtkWidget*)preeditLabel);
3746     }
3747     char* preeditString;
3748     PangoAttrList* pangoAttrs;
3749     auto imHandle = control.imHandle ();
3750     OS.gtk_im_context_get_preedit_string (imHandle, &preeditString, &pangoAttrs, null);
3751     if (preeditString !is null && OS.strlen (preeditString) > 0) {
3752         Control widget = control.findBackgroundControl ();
3753         if (widget is null) widget = control;
3754         OS.gtk_widget_modify_bg (cast(GtkWidget*)preeditWindow, OS.GTK_STATE_NORMAL, widget.getBackgroundColor ());
3755         widget.setForegroundColor (cast(GtkWidget*)preeditLabel, control.getForegroundColor());
3756         OS.gtk_widget_modify_font (cast(GtkWidget*)preeditLabel, control.getFontDescription ());
3757         if (pangoAttrs !is null) OS.gtk_label_set_attributes (preeditLabel, pangoAttrs);
3758         OS.gtk_label_set_text (preeditLabel, preeditString);
3759         Point point = control.toDisplay (control.getIMCaretPos ());
3760         OS.gtk_window_move (preeditWindow, point.x, point.y);
3761         GtkRequisition requisition;
3762         OS.gtk_widget_size_request (cast(GtkWidget*)preeditLabel, &requisition);
3763         OS.gtk_window_resize (preeditWindow, requisition.width, requisition.height);
3764         OS.gtk_widget_show (cast(GtkWidget*)preeditWindow);
3765     } else {
3766         OS.gtk_widget_hide (cast(GtkWidget*)preeditWindow);
3767     }
3768     if (preeditString !is null) OS.g_free (preeditString);
3769     if (pangoAttrs !is null) OS.pango_attr_list_unref (pangoAttrs);
3770 }
3771 
3772 /**
3773  * Causes the user-interface thread to <em>sleep</em> (that is,
3774  * to be put in a state where it does not consume CPU cycles)
3775  * until an event is received or it is otherwise awakened.
3776  *
3777  * @return <code>true</code> if an event requiring dispatching was placed on the queue.
3778  *
3779  * @exception SWTException <ul>
3780  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3781  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3782  * </ul>
3783  *
3784  * @see #wake
3785  */
3786 public bool sleep () {
3787     checkDevice ();
3788     if (gdkEventCount is 0) {
3789         gdkEvents = null;
3790         gdkEventWidgets = null;
3791     }
3792     if (settingsChanged) {
3793         settingsChanged = false;
3794         runSettingsFld = true;
3795         return false;
3796     }
3797     if (getMessageCount () !is 0) return true;
3798     if (fds is null) {
3799         allocated_nfds = 2;
3800         GPollFD* ptr = cast(GPollFD*) OS.g_malloc( GPollFD.sizeof * allocated_nfds );
3801         fds = ptr[ 0 .. allocated_nfds ];
3802     }
3803     max_priority = timeout = 0;
3804     auto context = OS.g_main_context_default ();
3805     bool result = false;
3806     do {
3807         if (OS.g_main_context_acquire (context)) {
3808             result = cast(bool)OS.g_main_context_prepare (context, &max_priority);
3809             int nfds;
3810             while ((nfds = OS.g_main_context_query (context, max_priority, &timeout, fds.ptr, allocated_nfds)) > allocated_nfds) {
3811                 OS.g_free (fds.ptr);
3812                 allocated_nfds = nfds;
3813                 GPollFD* ptr = cast(GPollFD*) OS.g_malloc( GPollFD.sizeof * allocated_nfds );
3814                 fds = ptr[ 0 .. allocated_nfds ];
3815             }
3816             GPollFunc poll = OS.g_main_context_get_poll_func (context);
3817             if (poll !is null) {
3818                 if (nfds > 0 || timeout !is 0) {
3819                     /*
3820                     * Bug in GTK. For some reason, g_main_context_wakeup() may
3821                     * fail to wake up the UI thread from the polling function.
3822                     * The fix is to sleep for a maximum of 50 milliseconds.
3823                     */
3824                     if (timeout < 0) timeout = 50;
3825 
3826                     /* Exit the OS lock to allow other threads to enter GTK */
3827                     Lock lock = OS.lock;
3828                     int count = lock.lock ();
3829                     for (int i = 0; i < count; i++) lock.unlock ();
3830                     try {
3831                         wake_state = false;
3832                         poll( fds.ptr, nfds, timeout);
3833                     } finally {
3834                         for (int i = 0; i < count; i++) lock.lock ();
3835                         lock.unlock ();
3836                     }
3837                 }
3838             }
3839             OS.g_main_context_check (context, max_priority, fds.ptr, nfds);
3840             OS.g_main_context_release (context);
3841         }
3842     } while (!result && getMessageCount () is 0 && !wake_state);
3843     wake_state = false;
3844     return true;
3845 }
3846 
3847 /**
3848  * Causes the <code>run()</code> method of the runnable to
3849  * be invoked by the user-interface thread after the specified
3850  * number of milliseconds have elapsed. If milliseconds is less
3851  * than zero, the runnable is not executed.
3852  * <p>
3853  * Note that at the time the runnable is invoked, widgets
3854  * that have the receiver as their display may have been
3855  * disposed. Therefore, it is necessary to check for this
3856  * case inside the runnable before accessing the widget.
3857  * </p>
3858  *
3859  * @param milliseconds the delay before running the runnable
3860  * @param runnable code to run on the user-interface thread
3861  *
3862  * @exception IllegalArgumentException <ul>
3863  *    <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
3864  * </ul>
3865  * @exception SWTException <ul>
3866  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3867  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3868  * </ul>
3869  *
3870  * @see #asyncExec
3871  */
3872 public void timerExec (int milliseconds, Runnable runnable) {
3873     checkDevice ();
3874     if (runnable is null) error (SWT.ERROR_NULL_ARGUMENT);
3875     if (timerList is null) timerList = new Runnable [4];
3876     if (timerIds is null) timerIds = new int [4];
3877     int index = 0;
3878     while (index < timerList.length) {
3879         if (timerList [index] is runnable) break;
3880         index++;
3881     }
3882     if (index !is timerList.length) {
3883         OS.gtk_timeout_remove (timerIds [index]);
3884         timerList [index] = null;
3885         timerIds [index] = 0;
3886         if (milliseconds < 0) return;
3887     } else {
3888         if (milliseconds < 0) return;
3889         index = 0;
3890         while (index < timerList.length) {
3891             if (timerList [index] is null) break;
3892             index++;
3893         }
3894         if (index is timerList.length) {
3895             Runnable [] newTimerList = new Runnable [timerList.length + 4];
3896             SimpleType!(Runnable).arraycopy (timerList, 0, newTimerList, 0, timerList.length);
3897             timerList = newTimerList;
3898             int [] newTimerIds = new int [timerIds.length + 4];
3899             System.arraycopy (timerIds, 0, newTimerIds, 0, timerIds.length);
3900             timerIds = newTimerIds;
3901         }
3902     }
3903     timerProcCallbackData.display = this;
3904     timerProcCallbackData.data = cast(void*)index;
3905     int timerId = OS.gtk_timeout_add (milliseconds, &timerProcFunc, &timerProcCallbackData);
3906     if (timerId !is 0) {
3907         timerIds [index] = timerId;
3908         timerList [index] = runnable;
3909     }
3910 }
3911 
3912 
3913 private static extern(C) int timerProcFunc ( void * data ) {
3914     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3915     CallbackData* cbdata = cast( CallbackData* ) data;
3916     return cbdata.display.timerProc( cast(int) cbdata.data );
3917 }
3918 
3919 int timerProc (int i) {
3920     if (timerList is null) return 0;
3921     int index = i;
3922     if (0 <= index && index < timerList.length) {
3923         Runnable runnable = timerList [index];
3924         timerList [index] = null;
3925         timerIds [index] = 0;
3926         if (runnable !is null) runnable.run ();
3927     }
3928     return 0;
3929 }
3930 
3931 private static extern(C) int caretProcFunc ( void * data ) {
3932     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3933     CallbackData* cbdata = cast( CallbackData* ) data;
3934     return cbdata.display.caretProc( cast(int) cbdata.data );
3935 }
3936 int caretProc (ptrdiff_t clientData) {
3937     caretId = 0;
3938     if (currentCaret is null) {
3939         return 0;
3940     }
3941     if (currentCaret.blinkCaret()) {
3942         int blinkRate = currentCaret.blinkRate;
3943         if (blinkRate is 0) return 0;
3944         caretProcCallbackData.display = this;
3945         caretProcCallbackData.data = cast(void*)0;
3946         caretId = OS.gtk_timeout_add (blinkRate, &caretProcFunc, &caretProcCallbackData);
3947     } else {
3948         currentCaret = null;
3949     }
3950     return 0;
3951 }
3952 
3953 
3954 package ptrdiff_t doSizeAllocateConnect( CallbackData* cbdata, GtkWidget* window, GtkWidget* widget ){
3955     cbdata.display = this;
3956     cbdata.data = cast(void*)widget;
3957     return OS.g_signal_connect (cast(void*)window, OS.size_allocate.ptr, cast(GCallback)&sizeAllocateProcFunc, cast(void*)&cbdata);
3958 }
3959 
3960 private static extern(C) void sizeAllocateProcFunc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
3961     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3962     auto cbdata = cast(CallbackData*)user_data;
3963     cbdata.display.sizeAllocateProc( cast(GtkWidget*)handle, arg0, cast(int)cbdata.data );
3964 }
3965 
3966 void sizeAllocateProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
3967     Widget widget = getWidget ( cast(GtkWidget*)user_data);
3968     if (widget is null) return;
3969     widget.sizeAllocateProc (handle, arg0, user_data);
3970 }
3971 
3972 
3973 package ptrdiff_t doSizeRequestConnect( CallbackData* cbdata, GtkWidget* window, GtkWidget* widget ){
3974     cbdata.display = this;
3975     cbdata.data = cast(void*)widget;
3976     return OS.g_signal_connect (cast(void*)window, OS.size_request.ptr, cast(GCallback)&sizeRequestProcFunc, cast(void*)&cbdata );
3977 }
3978 
3979 private static extern(C) void  sizeRequestProcFunc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
3980     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3981     auto cbdata = cast(CallbackData*)user_data;
3982     cbdata.display.sizeRequestProcMeth( cast(GtkWidget*)handle, arg0, cast(int)cbdata.data );
3983 }
3984 
3985 ptrdiff_t sizeRequestProcMeth (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
3986     Widget widget = getWidget (cast(GtkWidget*)user_data);
3987     if (widget is null) return 0;
3988     return widget.sizeRequestProc (handle, arg0, user_data);
3989 }
3990 
3991 package void doTreeSelectionProcConnect( CallbackData* cbdata, GtkWidget* widget, GtkTreeSelection* selection ){
3992     cbdata.display = this;
3993     cbdata.data = cast(void*)widget;
3994     OS.gtk_tree_selection_selected_foreach (selection, &treeSelectionProcFunc, widget);
3995 }
3996 
3997 private static extern(C) void  treeSelectionProcFunc (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void* data) {
3998     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3999     auto cbdata = cast(CallbackData*)data;
4000     cbdata.display.treeSelectionProcMeth( model, path, iter, cbdata.data );
4001 }
4002 
4003 void treeSelectionProcMeth (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void* data) {
4004     Widget widget = getWidget (cast(GtkWidget*)data);
4005     if (widget is null) return;
4006     widget.treeSelectionProc (model, path, iter, treeSelection, treeSelectionLength++);
4007 }
4008 
4009 void saveResources () {
4010     ptrdiff_t resourceCount = 0;
4011     if (resources is null) {
4012         resources = new Resource [RESOURCE_SIZE];
4013     } else {
4014         resourceCount = resources.length;
4015         Resource [] newResources = new Resource [resourceCount + RESOURCE_SIZE];
4016         System.arraycopy (resources, 0, newResources, 0, resourceCount);
4017         resources = newResources;
4018     }
4019     if (systemFont !is null) {
4020         resources [resourceCount++] = systemFont;
4021         systemFont = null;
4022     }
4023     if (errorImage !is null) resources [resourceCount++] = errorImage;
4024     if (infoImage !is null) resources [resourceCount++] = infoImage;
4025     if (questionImage !is null) resources [resourceCount++] = questionImage;
4026     if (warningImage !is null) resources [resourceCount++] = warningImage;
4027     errorImage = infoImage = questionImage = warningImage = null;
4028     for (int i=0; i<cursors.length; i++) {
4029         if (cursors [i] !is null) resources [resourceCount++] = cursors [i];
4030         cursors [i] = null;
4031     }
4032     if (resourceCount < RESOURCE_SIZE) {
4033         Resource [] newResources = new Resource [resourceCount];
4034         System.arraycopy (resources, 0, newResources, 0, resourceCount);
4035         resources = newResources;
4036     }
4037 }
4038 
4039 void sendEvent (int eventType, Event event) {
4040     if (eventTable is null && filterTable is null) {
4041         return;
4042     }
4043     if (event is null) event = new Event ();
4044     event.display = this;
4045     event.type = eventType;
4046     if (event.time is 0) event.time = getLastEventTime ();
4047     if (!filterEvent (event)) {
4048         if (eventTable !is null) eventTable.sendEvent (event);
4049     }
4050 }
4051 
4052 void setCurrentCaret (Caret caret) {
4053     if (caretId !is 0) OS.gtk_timeout_remove(caretId);
4054     caretId = 0;
4055     currentCaret = caret;
4056     if (caret is null) return;
4057     int blinkRate = currentCaret.blinkRate;
4058     caretProcCallbackData.display = this;
4059     caretProcCallbackData.data = cast(void*)0;
4060     caretId = OS.gtk_timeout_add (blinkRate, &caretProcFunc, &caretProcCallbackData);
4061 }
4062 
4063 private static extern(C) int shellMapProcFunc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4064     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4065     auto cbdata = cast(CallbackData*)user_data;
4066     return cbdata.display.shellMapProc( cast(GtkWidget*)handle, arg0, cast(int)cbdata.data );
4067 }
4068 
4069 int shellMapProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4070     Widget widget = getWidget (cast(GtkWidget*)handle);
4071     if (widget is null) return 0;
4072     return widget.shellMapProc (handle, arg0, user_data);
4073 }
4074 
4075 private static extern(C) int styleSetProcFunc (ptrdiff_t gobject, ptrdiff_t arg1, ptrdiff_t user_data) {
4076     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4077     auto cbdata = cast(CallbackData*)user_data;
4078     return cbdata.display.styleSetProcMeth( gobject, arg1, cast(int)cbdata.data );
4079 }
4080 int styleSetProcMeth (ptrdiff_t gobject, ptrdiff_t arg1, ptrdiff_t user_data) {
4081     settingsChanged = true;
4082     return 0;
4083 }
4084 
4085 /**
4086  * Causes the <code>run()</code> method of the runnable to
4087  * be invoked by the user-interface thread at the next
4088  * reasonable opportunity. The thread which calls this method
4089  * is suspended until the runnable completes.  Specifying <code>null</code>
4090  * as the runnable simply wakes the user-interface thread.
4091  * <p>
4092  * Note that at the time the runnable is invoked, widgets
4093  * that have the receiver as their display may have been
4094  * disposed. Therefore, it is necessary to check for this
4095  * case inside the runnable before accessing the widget.
4096  * </p>
4097  *
4098  * @param runnable code to run on the user-interface thread or <code>null</code>
4099  *
4100  * @exception SWTException <ul>
4101  *    <li>ERROR_FAILED_EXEC - if an exception occurred when executing the runnable</li>
4102  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4103  * </ul>
4104  *
4105  * @see #asyncExec
4106  */
4107 public void syncExec (Runnable runnable) {
4108     Synchronizer synchronizer;
4109     synchronized (Device.classinfo) {
4110         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
4111         synchronizer = this.synchronizer;
4112         synchronized (idleLock) {
4113             if (idleNeeded && idleHandle is 0) {
4114                 //NOTE: calling unlocked function in OS
4115             idleProcCallbackData.display = this;
4116             idleProcCallbackData.data = cast(void*)0;
4117             //PORTING_TODO: was _g_idle_add, calling directly
4118             idleHandle = OS.g_idle_add (&idleProcFunc, &idleProcCallbackData);
4119             }
4120         }
4121     }
4122     synchronizer.syncExec (runnable);
4123 }
4124 
4125 static int translateKey (int key) {
4126     for (int i=0; i<KeyTable.length; i++) {
4127         if (KeyTable [i] [0] is key) return KeyTable [i] [1];
4128     }
4129     return 0;
4130 }
4131 
4132 static int untranslateKey (int key) {
4133     for (int i=0; i<KeyTable.length; i++) {
4134         if (KeyTable [i] [1] is key) return KeyTable [i] [0];
4135     }
4136     return 0;
4137 }
4138 
4139 /**
4140  * Forces all outstanding paint requests for the display
4141  * to be processed before this method returns.
4142  *
4143  * @exception SWTException <ul>
4144  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4145  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4146  * </ul>
4147  *
4148  * @see Control#update()
4149  */
4150 public void update () {
4151     checkDevice ();
4152     flushExposes (null, true);
4153     OS.gdk_window_process_all_updates ();
4154 }
4155 
4156 /**
4157  * If the receiver's user-interface thread was <code>sleep</code>ing,
4158  * causes it to be awakened and start running again. Note that this
4159  * method may be called from any thread.
4160  *
4161  * @exception SWTException <ul>
4162  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4163  * </ul>
4164  *
4165  * @see #sleep
4166  */
4167 public void wake () {
4168     synchronized (Device.classinfo) {
4169         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
4170         if (thread is Thread.currentThread ()) return;
4171         wakeThread ();
4172     }
4173 }
4174 
4175 void wakeThread () {
4176     OS.g_main_context_wakeup (null);
4177     wake_state = true;
4178 }
4179 
4180 static dchar wcsToMbcs (char ch) {
4181     //PORTING_TODO not sure about this
4182     int key = ch & 0xFFFF;
4183     if (key <= 0x7F) return ch;
4184     char [] buffer = Converter.wcsToMbcs (null,[ch], false);
4185     if (buffer.length is 1) return '\0';
4186     if (buffer.length is 2) {
4187         return cast(char) (((buffer [0] & 0xFF) << 8) | (buffer [1] & 0xFF));
4188     }
4189     return '\0';
4190 }
4191 
4192 private static extern(C) int windowProcFunc2 (GtkWidget* handle, ptrdiff_t user_data) {
4193     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4194     CallbackData* cbdata = cast(CallbackData*)user_data;
4195     return cbdata.display.windowProc( handle, cast(ptrdiff_t)cbdata.data );
4196 }
4197 int windowProc (GtkWidget* handle, ptrdiff_t user_data) {
4198     Widget widget = getWidget (handle);
4199     if (widget is null) return 0;
4200     return widget.windowProc (handle, user_data);
4201 }
4202 
4203 private static extern(C) int windowProcFunc3 (ptrdiff_t handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4204     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4205     CallbackData* cbdata = cast(CallbackData*)user_data;
4206     return cbdata.display.windowProc( cast(GtkWidget*)handle, arg0, cast(ptrdiff_t)cbdata.data );
4207 }
4208 int windowProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4209     Widget widget = getWidget (handle);
4210     if (widget is null) return 0;
4211     return widget.windowProc (handle, arg0, user_data);
4212 }
4213 
4214 private static extern(C) int windowProcFunc4 (ptrdiff_t handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t user_data) {
4215     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4216     CallbackData* cbdata = cast(CallbackData*)user_data;
4217     return cbdata.display.windowProc( cast(GtkWidget*)handle, arg0, arg1, cast(ptrdiff_t)cbdata.data );
4218 }
4219 int windowProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t user_data) {
4220     Widget widget = getWidget (handle);
4221     if (widget is null) return 0;
4222     return widget.windowProc (handle, arg0, arg1, user_data);
4223 }
4224 
4225 private static extern(C) int windowProcFunc5 (ptrdiff_t handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t arg2, ptrdiff_t user_data) {
4226     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4227     CallbackData* cbdata = cast(CallbackData*)user_data;
4228     return cbdata.display.windowProc( cast(GtkWidget*)handle, arg0, arg1, arg2, cast(ptrdiff_t)cbdata.data );
4229 }
4230 int windowProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t arg2, ptrdiff_t user_data) {
4231     Widget widget = getWidget (handle);
4232     if (widget is null) return 0;
4233     return widget.windowProc (handle, arg0, arg1, arg2, user_data);
4234 }
4235 
4236 private static extern(C) int windowProcChangeValueFunc(GtkWidget* handle, int scroll, double value1, void* user_data) {
4237     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4238     CallbackData* cbdata = cast(CallbackData*)user_data;
4239     Widget widget = cbdata.display.getWidget (handle);
4240     if (widget is null) return 0;
4241     return widget.gtk_change_value(handle, scroll, value1, user_data);
4242 }
4243 
4244 package int doWindowTimerAdd( CallbackData* cbdata, int delay, GtkWidget* widget ){
4245     OS.g_object_set_data(cast(GObject*)widget, Display.classinfo.name.ptr, cast(void*)this);
4246     return OS.gtk_timeout_add (delay, &windowTimerProcFunc, widget);
4247 }
4248 private static extern(C) int windowTimerProcFunc (void* user_data) {
4249     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4250     Display d = cast(Display) OS.g_object_get_data(cast(GObject*)user_data, Display.classinfo.name.ptr );
4251     return d.windowTimerProc( cast(GtkWidget*)user_data );
4252 }
4253 
4254 int windowTimerProc (GtkWidget* handle) {
4255     Widget widget = getWidget (handle);
4256     if (widget is null) return 0;
4257     return widget.timerProc (handle);
4258 }
4259 
4260 }
4261 
4262 package struct CallbackData {
4263     Display display;
4264     void* data;
4265 }
4266