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