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 private static extern(C) int XErrorHandler( void*, XErrorEvent* ){
924     getDwtLogger().error ( __FILE__, __LINE__, "*** XError" );
925     byte* p;
926     *p = 3;
927     return 0;
928 }
929 
930 void createDisplay (DeviceData data) {
931     /* Required for g_main_context_wakeup */
932     if (!OS.g_thread_supported ()) {
933         OS.g_thread_init (null);
934     }
935     OS.gtk_set_locale();
936     int cnt = 2;
937     auto args = [ "name".ptr, "--sync".ptr, "".ptr ];
938     auto a = args.ptr;
939     if (!OS.gtk_init_check (&cnt, &a )) {
940     }
941     assert( cnt is 1 );
942     if (OS.GDK_WINDOWING_X11 ()) xDisplay = cast(void*) OS.GDK_DISPLAY ();
943 
944     OS.XSetErrorHandler( &Display.XErrorHandler );
945     char* ptr = OS.gtk_check_version (MAJOR, MINOR, MICRO);
946     if (ptr !is null) {
947         char [] buffer = fromStringz(ptr);
948         getDwtLogger().warn (__FILE__, __LINE__,"***WARNING: {}", buffer );
949         getDwtLogger().warn (__FILE__, __LINE__,"***WARNING: SWT requires GTK {}.{}.{}", MAJOR, MINOR, MICRO );
950         ptrdiff_t major = OS.gtk_major_version (), minor = OS.gtk_minor_version (), micro = OS.gtk_micro_version ();
951         getDwtLogger().warn (__FILE__, __LINE__,"***WARNING: Detected: {}.{}.{}", major, minor, micro);
952     }
953     if (fixed_type is 0) {
954         GTypeInfo* fixed_info = new GTypeInfo ();
955         fixed_info.class_size = GtkFixedClass.sizeof;
956         fixed_info.class_init = & fixedClassInitProcFunc;
957         fixed_info.instance_size = GtkFixed.sizeof;
958         fixed_type = OS.g_type_register_static (OS.GTK_TYPE_FIXED (), "SwtFixed".ptr, fixed_info, 0);
959     }
960     if (text_renderer_type is 0) {
961         GTypeInfo* renderer_info = new GTypeInfo ();
962         renderer_info.class_size = GtkCellRendererTextClass.sizeof;
963         renderer_info.class_init = & rendererClassInitProcFunc;
964         renderer_info.instance_size = GtkCellRendererText.sizeof;
965         text_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_TEXT (), "SwtTextRenderer".ptr, renderer_info, 0);
966     }
967     if (pixbuf_renderer_type is 0) {
968         GTypeInfo* renderer_info = new GTypeInfo ();
969         renderer_info.class_size = GtkCellRendererPixbufClass.sizeof;
970         renderer_info.class_init = & rendererClassInitProcFunc;
971         renderer_info.instance_size = GtkCellRendererPixbuf.sizeof;
972         pixbuf_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_PIXBUF (), "SwtPixbufRenderer".ptr, renderer_info, 0);
973     }
974     if (toggle_renderer_type is 0) {
975         GTypeInfo* renderer_info = new GTypeInfo ();
976         renderer_info.class_size = GtkCellRendererToggleClass.sizeof;
977         renderer_info.class_init = & rendererClassInitProcFunc;
978         renderer_info.instance_size = GtkCellRendererToggle.sizeof;
979         toggle_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_TOGGLE (), "SwtToggleRenderer".ptr, renderer_info, 0);
980     }
981 
982     OS.gtk_widget_set_default_direction (OS.GTK_TEXT_DIR_LTR);
983     OS.gdk_rgb_init ();
984     char* p = toStringz(APP_NAME);
985     OS.g_set_prgname (p);
986     OS.gdk_set_program_class (p);
987     OS.gtk_rc_parse_string ("style \"swt-flat\" { GtkToolbar::shadow-type = none } widget \"*.swt-toolbar-flat\" style : highest \"swt-flat\"".ptr);
988 
989     /* Initialize the hidden shell */
990     shellHandle = OS.gtk_window_new (OS.GTK_WINDOW_TOPLEVEL);
991     if (shellHandle is null) SWT.error (SWT.ERROR_NO_HANDLES);
992     OS.gtk_widget_realize (shellHandle);
993 
994     /* Initialize the filter and event callback */
995     OS.gdk_event_handler_set (&eventProcFunc, cast(void*)this, null);
996     //filterProcCallbackData.display = this;
997     //filterProcCallbackData.data = null;
998     //OS.gdk_window_add_filter  (null, &filterProcFunc, cast(void*)&filterProcCallbackData );
999     doWindowAddFilter( &filterProcCallbackData, null, null );
1000 }
1001 
1002 /*
1003  * Used by Shell
1004  */
1005 package void doWindowAddFilter( CallbackData* cbdata, GdkWindow* window, GtkWidget* widget ){
1006     cbdata.display = this;
1007     cbdata.data = widget;
1008     OS.gdk_window_add_filter (window, &filterProcFunc, cbdata );
1009 }
1010 
1011 package void doWindowRemoveFilter( CallbackData* cbdata, GdkWindow* window, GtkWidget* widget ){
1012     cbdata.display = this;
1013     cbdata.data = widget;
1014     OS.gdk_window_remove_filter(window, &filterProcFunc, cbdata );
1015 }
1016 
1017 Image createImage (String name) {
1018     auto style = OS.gtk_widget_get_default_style ();
1019     String buffer = name;
1020     auto pixbuf = OS.gtk_icon_set_render_icon (
1021         OS.gtk_icon_factory_lookup_default (buffer.ptr), style,
1022         OS.GTK_TEXT_DIR_NONE,
1023         OS.GTK_STATE_NORMAL,
1024         OS.GTK_ICON_SIZE_DIALOG, null, null );
1025     if (pixbuf is null) return null;
1026     int width = OS.gdk_pixbuf_get_width (pixbuf);
1027     int height = OS.gdk_pixbuf_get_height (pixbuf);
1028     int stride = OS.gdk_pixbuf_get_rowstride (pixbuf);
1029     bool hasAlpha = cast(bool)OS.gdk_pixbuf_get_has_alpha (pixbuf);
1030     char* pixels = OS.gdk_pixbuf_get_pixels (pixbuf);
1031     byte [] data = new byte [stride * height];
1032     OS.memmove (data.ptr, pixels, data.length);
1033     OS.g_object_unref (pixbuf);
1034     ImageData imageData = null;
1035     if (hasAlpha) {
1036         PaletteData palette = new PaletteData (0xFF000000, 0xFF0000, 0xFF00);
1037         imageData = new ImageData (width, height, 32, palette);
1038         byte [] alpha = new byte [stride * height];
1039         for (int y=0; y<height; y++) {
1040             for (int x=0; x<width; x++) {
1041                 alpha [y*width+x] = data [y*stride+x*4+3];
1042                 data [y*stride+x*4+3] = 0;
1043             }
1044         }
1045         imageData.setAlphas (0, 0, width * height, alpha, 0);
1046     } else {
1047         PaletteData palette = new PaletteData (0xFF0000, 0xFF00, 0xFF);
1048         imageData = new ImageData (width, height, 24, palette);
1049     }
1050     imageData.data = data;
1051     imageData.bytesPerLine = stride;
1052     return new Image (this, imageData);
1053 }
1054 
1055 static GdkPixbuf* createPixbuf(Image image) {
1056     int w, h;
1057     OS.gdk_drawable_get_size (image.pixmap, &w, &h);
1058     auto colormap = OS.gdk_colormap_get_system ();
1059     GdkPixbuf* pixbuf;
1060     bool hasMask = image.mask !is null && OS.gdk_drawable_get_depth (image.mask) is 1;
1061     if (hasMask) {
1062         pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, true, 8, w, h );
1063         if (pixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES);
1064         OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w, h);
1065         auto maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, w, h);
1066         if (maskPixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES);
1067         OS.gdk_pixbuf_get_from_drawable(maskPixbuf, image.mask, null, 0, 0, 0, 0, w, h);
1068         int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
1069         auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
1070         byte[] line = new byte[stride];
1071         int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf);
1072         auto maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf);
1073         byte[] maskLine = new byte[maskStride];
1074         for (int y=0; y<h; y++) {
1075             auto offset = pixels + (y * stride);
1076             OS.memmove(line.ptr, offset, stride);
1077             auto maskOffset = maskPixels + (y * maskStride);
1078             OS.memmove(maskLine.ptr, maskOffset, maskStride);
1079             for (int x=0; x<w; x++) {
1080                 if (maskLine[x * 3] is 0) {
1081                     line[x * 4 + 3] = 0;
1082                 }
1083             }
1084             OS.memmove(offset, line.ptr, stride);
1085         }
1086         OS.g_object_unref(maskPixbuf);
1087     } else {
1088         ImageData data = image.getImageData ();
1089         bool hasAlpha = data.getTransparencyType () is SWT.TRANSPARENCY_ALPHA;
1090         pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, hasAlpha, 8, w, h);
1091         if (pixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES);
1092         OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w, h);
1093         if (hasAlpha) {
1094             byte [] alpha = data.alphaData;
1095             int stride = OS.gdk_pixbuf_get_rowstride (pixbuf);
1096             auto pixels = OS.gdk_pixbuf_get_pixels (pixbuf);
1097             byte [] line = new byte [stride];
1098             for (int y = 0; y < h; y++) {
1099                 auto offset = pixels + (y * stride);
1100                 OS.memmove (line.ptr, offset, stride);
1101                 for (int x = 0; x < w; x++) {
1102                     line [x*4+3] = alpha [y*w+x];
1103                 }
1104                 OS.memmove (offset, line.ptr, stride);
1105             }
1106         }
1107     }
1108     return pixbuf;
1109 }
1110 
1111 static void deregister (Display display) {
1112     synchronized (Device.classinfo) {
1113         for (int i=0; i<Displays.length; i++) {
1114             if (display is Displays [i]) Displays [i] = null;
1115         }
1116     }
1117 }
1118 
1119 /**
1120  * Destroys the device in the operating system and releases
1121  * the device's handle.  If the device does not have a handle,
1122  * this method may do nothing depending on the device.
1123  * <p>
1124  * This method is called after <code>release</code>.
1125  * </p>
1126  * @see Device#dispose
1127  * @see #release
1128  */
1129 protected override void destroy () {
1130     if (this is Default) Default = null;
1131     deregister (this);
1132     destroyDisplay ();
1133 }
1134 
1135 void destroyDisplay () {
1136 }
1137 
1138 static extern(C) int emissionFunc (GSignalInvocationHint* ihint, uint n_param_values, GValue* param_values, void* data) {
1139     auto cb = cast(CallbackData*)data;
1140     return cb.display.emissionProc( ihint, n_param_values, param_values, cb.data );
1141 }
1142 
1143 int emissionProc (GSignalInvocationHint* ihint, size_t n_param_values, GValue* param_values, void* data) {
1144     if (OS.gtk_widget_get_toplevel (OS.g_value_peek_pointer(param_values)) is data) {
1145         OS.gtk_widget_set_direction (OS.g_value_peek_pointer(param_values), OS.GTK_TEXT_DIR_RTL);
1146     }
1147     return 1;
1148 }
1149 
1150 /**
1151  * Returns the display which the given thread is the
1152  * user-interface thread for, or null if the given thread
1153  * is not a user-interface thread for any display.  Specifying
1154  * <code>null</code> as the thread will return <code>null</code>
1155  * for the display.
1156  *
1157  * @param thread the user-interface thread
1158  * @return the display for the given thread
1159  */
1160 public static Display findDisplay (Thread thread) {
1161     synchronized (Device.classinfo) {
1162         for (int i=0; i<Displays.length; i++) {
1163             Display display = Displays [i];
1164             if (display !is null && display.thread is thread) {
1165                 return display;
1166             }
1167         }
1168         return null;
1169     }
1170 }
1171 
1172 /**
1173  * Causes the <code>run()</code> method of the runnable to
1174  * be invoked by the user-interface thread just before the
1175  * receiver is disposed.  Specifying a <code>null</code> runnable
1176  * is ignored.
1177  *
1178  * @param runnable code to run at dispose time.
1179  *
1180  * @exception SWTException <ul>
1181  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1182  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1183  * </ul>
1184  */
1185 public void disposeExec (Runnable runnable) {
1186     checkDevice ();
1187     if (disposeList is null) disposeList = new Runnable [4];
1188     for (int i=0; i<disposeList.length; i++) {
1189         if (disposeList [i] is null) {
1190             disposeList [i] = runnable;
1191             return;
1192         }
1193     }
1194     Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
1195     SimpleType!(Runnable).arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
1196     newDisposeList [disposeList.length] = runnable;
1197     disposeList = newDisposeList;
1198 }
1199 
1200 /**
1201  * Does whatever display specific cleanup is required, and then
1202  * uses the code in <code>SWTError.error</code> to handle the error.
1203  *
1204  * @param code the descriptive error code
1205  *
1206  * @see SWTError#error
1207  */
1208 void error (int code) {
1209     SWT.error (code);
1210 }
1211 
1212 private static extern(C) void eventProcFunc (GdkEvent* event, void* data) {
1213     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1214     Display disp = cast(Display)data;
1215     disp.eventProcMeth(event);
1216 }
1217 void eventProcMeth (GdkEvent* event) {
1218     /*
1219     * Use gdk_event_get_time() rather than event.time or
1220     * gtk_get_current_event_time().  If the event does not
1221     * have a time stamp, then the field will contain garbage.
1222     * Note that calling gtk_get_current_event_time() from
1223     * outside of gtk_main_do_event() seems to always
1224     * return zero.
1225     */
1226     int time = OS.gdk_event_get_time (event);
1227     if (time !is 0) lastEventTime = time;
1228 
1229     int eventType = OS.GDK_EVENT_TYPE (event);
1230     switch (eventType) {
1231         case OS.GDK_BUTTON_PRESS:
1232         case OS.GDK_KEY_PRESS:
1233             lastUserEventTime = time;
1234             break;
1235         default:
1236             break;
1237     }
1238     bool dispatch = true;
1239     if (dispatchEvents !is null) {
1240         dispatch = false;
1241         for (int i = 0; i < dispatchEvents.length; i++) {
1242             if (eventType is dispatchEvents [i]) {
1243                 dispatch = true;
1244                 break;
1245             }
1246         }
1247     }
1248     if (!dispatch) {
1249         addGdkEvent (OS.gdk_event_copy (event));
1250         return;
1251     }
1252     OS.gtk_main_do_event (event);
1253     if (dispatchEvents is null) putGdkEvents ();
1254 }
1255 
1256 /**
1257  * Given the operating system handle for a widget, returns
1258  * the instance of the <code>Widget</code> subclass which
1259  * represents it in the currently running application, if
1260  * such exists, or null if no matching widget can be found.
1261  * <p>
1262  * <b>IMPORTANT:</b> This method should not be called from
1263  * application code. The arguments are platform-specific.
1264  * </p>
1265  *
1266  * @param handle the handle for the widget
1267  * @return the SWT widget that the handle represents
1268  *
1269  * @exception SWTException <ul>
1270  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1271  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1272  * </ul>
1273  */
1274 public Widget findWidget (GtkWidget* handle) {
1275     checkDevice ();
1276     return getWidget (handle);
1277 }
1278 
1279 /**
1280  * Given the operating system handle for a widget,
1281  * and widget-specific id, returns the instance of
1282  * the <code>Widget</code> subclass which represents
1283  * the handle/id pair in the currently running application,
1284  * if such exists, or null if no matching widget can be found.
1285  * <p>
1286  * <b>IMPORTANT:</b> This method should not be called from
1287  * application code. The arguments are platform-specific.
1288  * </p>
1289  *
1290  * @param handle the handle for the widget
1291  * @param id the id for the subwidget (usually an item)
1292  * @return the SWT widget that the handle/id pair represents
1293  *
1294  * @exception SWTException <ul>
1295  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1296  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1297  * </ul>
1298  *
1299  * @since 3.1
1300  */
1301 public Widget findWidget (GtkWidget* handle, int id) {
1302     checkDevice ();
1303     return null;
1304 }
1305 
1306 /**
1307  * Given a widget and a widget-specific id, returns the
1308  * instance of the <code>Widget</code> subclass which represents
1309  * the widget/id pair in the currently running application,
1310  * if such exists, or null if no matching widget can be found.
1311  *
1312  * @param widget the widget
1313  * @param id the id for the subwidget (usually an item)
1314  * @return the SWT subwidget (usually an item) that the widget/id pair represents
1315  *
1316  * @exception SWTException <ul>
1317  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1318  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1319  * </ul>
1320  *
1321  * @since 3.3
1322  */
1323 public Widget findWidget (Widget widget, ptrdiff_t id) {
1324     checkDevice ();
1325     return null;
1326 }
1327 
1328 private static extern(C) void fixedClassInitProcFunc (void* g_class, void* class_data) {
1329     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1330     GtkWidgetClass* klass = cast(GtkWidgetClass*)g_class;
1331     klass.map = &fixedMapProcFunc;
1332     oldFixedSizeAllocateProc = klass.size_allocate;
1333     klass.size_allocate = &fixedSizeAllocateProc;
1334 }
1335 
1336 private static extern(C) void fixedMapProcFunc (GtkWidget * handle) {
1337     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1338     Display display = getCurrent ();
1339     Widget widget = display.getWidget (handle);
1340     if (widget !is null) widget.fixedMapProc (handle);
1341 }
1342 
1343 private static extern(C) void fixedSizeAllocateProc (GtkWidget* handle, GtkAllocation* allocation) {
1344     Display display = getCurrent ();
1345     Widget widget = display.getWidget (handle);
1346     if (widget !is null) return widget.fixedSizeAllocateProc (handle, allocation);
1347     return oldFixedSizeAllocateProc(handle, allocation);
1348 }
1349 
1350 private static extern(C) void rendererClassInitProcFunc (void* g_class, void* class_data) {
1351     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1352     GtkCellRendererClass* klass = cast(GtkCellRendererClass*)g_class;
1353     klass.render = &rendererRenderProcFunc;
1354     klass.get_size = &rendererGetSizeProcFunc;
1355 
1356 }
1357 private static extern(C) void rendererGetSizeProcFunc(
1358     GtkCellRenderer      *cell,
1359     GtkWidget            *handle,
1360     GdkRectangle         *cell_area,
1361     int                  *x_offset,
1362     int                  *y_offset,
1363     int                  *width,
1364     int                  *height)
1365 {
1366     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1367     Display display = getCurrent ();
1368     Widget widget = display.getWidget (handle);
1369     if (widget !is null) widget.rendererGetSizeProc (cell, handle, cell_area, x_offset, y_offset, width, height);
1370 }
1371 private static extern(C) void rendererRenderProcFunc(GtkCellRenderer * cell, GdkDrawable * window, GtkWidget * handle, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, int flags){
1372     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1373     Display display = getCurrent ();
1374     Widget widget = display.getWidget (handle);
1375     if (widget !is null) widget.rendererRenderProc (cell, window, handle, background_area, cell_area, expose_area, flags);
1376 }
1377 
1378 void flushExposes (GdkWindow* window, bool all) {
1379     OS.gdk_flush ();
1380     OS.gdk_flush ();
1381     if (OS.GDK_WINDOWING_X11 ()) {
1382         this.flushWindow = window;
1383         this.flushAll = all;
1384         auto xDisplay = OS.GDK_DISPLAY ();
1385         auto xEvent = cast(XEvent*)OS.g_malloc (XEvent.sizeof);
1386         OS.XCheckIfEvent (xDisplay, xEvent, &checkIfEventProcFunc, cast(char*)this );
1387         OS.g_free (xEvent);
1388         this.flushWindow = null;
1389     }
1390 }
1391 
1392 /**
1393  * Returns the currently active <code>Shell</code>, or null
1394  * if no shell belonging to the currently running application
1395  * is active.
1396  *
1397  * @return the active shell or null
1398  *
1399  * @exception SWTException <ul>
1400  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1401  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1402  * </ul>
1403  */
1404 public Shell getActiveShell () {
1405     checkDevice ();
1406     return activeShell;
1407 }
1408 
1409 /**
1410  * Returns a rectangle describing the receiver's size and location. Note that
1411  * on multi-monitor systems the origin can be negative.
1412  *
1413  * @return the bounding rectangle
1414  *
1415  * @exception SWTException <ul>
1416  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1417  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1418  * </ul>
1419  */
1420 public override Rectangle getBounds () {
1421     checkDevice ();
1422     return new Rectangle (0, 0, OS.gdk_screen_width (), OS.gdk_screen_height ());
1423 }
1424 
1425 /**
1426  * Returns the display which the currently running thread is
1427  * the user-interface thread for, or null if the currently
1428  * running thread is not a user-interface thread for any display.
1429  *
1430  * @return the current display
1431  */
1432 public static Display getCurrent () {
1433     return findDisplay (Thread.currentThread ());
1434 }
1435 
1436 int getCaretBlinkTime () {
1437 //  checkDevice ();
1438     auto settings = OS.gtk_settings_get_default ();
1439     if (settings is null) return 500;
1440     int  buffer;
1441     OS.g_object_get1 (settings, OS.gtk_cursor_blink.ptr, &buffer );
1442     if (buffer  is 0) return 0;
1443     OS.g_object_get1 (settings, OS.gtk_cursor_blink_time.ptr, &buffer);
1444     if (buffer  is 0) return 500;
1445     /*
1446     * By experimentation, GTK application don't use the whole
1447     * blink cycle time.  Instead, they divide up the time, using
1448     * an effective blink rate of about 1/2 the total time.
1449     */
1450     return buffer / 2;
1451 }
1452 
1453 GClosure* getClosure (int id) {
1454     if (OS.GLIB_VERSION >= OS.buildVERSION(2, 36, 0) && ++closuresCount [id] >= 255) {
1455         if (closures [id] !is null) OS.g_closure_unref (closures [id]);
1456         auto res = windowProcCallbackDatas [id];
1457         closures [id] = OS.g_cclosure_new (closuresProc [id], res, null);
1458         OS.g_closure_ref (closures [id]);
1459         OS.g_closure_sink (closures [id]);
1460         closuresCount [id] = 0;
1461     }
1462     return closures [id];
1463 }
1464 
1465 /**
1466  * Returns the control which the on-screen pointer is currently
1467  * over top of, or null if it is not currently over one of the
1468  * controls built by the currently running application.
1469  *
1470  * @return the control under the cursor
1471  *
1472  * @exception SWTException <ul>
1473  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1474  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1475  * </ul>
1476  */
1477 public Control getCursorControl () {
1478     checkDevice();
1479     int x, y;
1480     GtkWidget* handle;
1481     GtkWidget* user_data;
1482     auto window = OS.gdk_window_at_pointer (&x, &y);
1483     if (window !is null) {
1484         OS.gdk_window_get_user_data (window, cast(void**)&user_data);
1485         handle = user_data;
1486     } else {
1487         /*
1488         * Feature in GTK. gdk_window_at_pointer() will not return a window
1489         * if the pointer is over a foreign embedded window. The fix is to use
1490         * XQueryPointer to find the containing GDK window.
1491         */
1492         if (!OS.GDK_WINDOWING_X11 ()) return null;
1493         OS.gdk_error_trap_push ();
1494         int unusedInt;
1495         uint unusedUInt;
1496         size_t unusedPtr;
1497         size_t buffer;
1498         size_t xWindow, xParent = OS.XDefaultRootWindow (xDisplay);
1499         do {
1500             if (OS.XQueryPointer (xDisplay, xParent, &unusedPtr, &buffer, &unusedInt, &unusedInt, &unusedInt, &unusedInt, &unusedUInt) is 0) {
1501                 handle = null;
1502                 break;
1503             }
1504             if ((xWindow = buffer) !is 0) {
1505                 xParent = xWindow;
1506                 auto gdkWindow = OS.gdk_window_lookup (cast(void*)xWindow);
1507                 if (gdkWindow !is null) {
1508                     OS.gdk_window_get_user_data (gdkWindow, cast(void**)&user_data);
1509                     if (user_data !is null) handle = user_data;
1510                 }
1511             }
1512         } while (xWindow !is 0);
1513         OS.gdk_error_trap_pop ();
1514     }
1515     if (handle is null) return null;
1516     do {
1517         Widget widget = getWidget (handle);
1518         if (widget !is null && (null !is cast(Control)widget)) {
1519             Control control = cast(Control) widget;
1520             if (control.isEnabled ()) return control;
1521         }
1522     } while ((handle = OS.gtk_widget_get_parent (handle)) !is null);
1523     return null;
1524 }
1525 
1526 bool filterEvent (Event event) {
1527     if (filterTable !is null) filterTable.sendEvent (event);
1528     return false;
1529 }
1530 
1531 bool filters (int eventType) {
1532     if (filterTable is null) return false;
1533     return filterTable.hooks (eventType);
1534 }
1535 
1536 private static extern(C) int filterProcFunc (GdkXEvent* xEvent, GdkEvent* gdkEvent, void* data) {
1537     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
1538     auto callbackdata = cast(CallbackData*)data;
1539     auto disp = callbackdata.display;
1540     if( disp is null ) return 0;
1541     auto res =  disp.filterProcMeth(xEvent,gdkEvent,callbackdata);
1542     return res;
1543 }
1544 
1545 int filterProcMeth (GdkXEvent* xEvent, GdkEvent* gdkEvent, CallbackData* callbackData) {
1546     if( callbackData.data is null ){
1547         /*
1548          * Feature in GTK.  When button 4, 5, 6, or 7 is released, GTK
1549          * does not deliver a corresponding GTK event.  Button 6 and 7
1550          * are mapped to buttons 4 and 5 in SWT.  The fix is to change
1551          * the button number of the event to a negative number so that
1552          * it gets dispatched by GTK.  SWT has been modified to look
1553          * for negative button numbers.
1554          */
1555         XButtonEvent* mouseEvent = cast(XButtonEvent*) xEvent;
1556         if (mouseEvent.type is OS.ButtonRelease) {
1557             switch (mouseEvent.button) {
1558                 case 6:
1559                 case 7:
1560                     mouseEvent.button = -mouseEvent.button;
1561                     break;
1562                 default:
1563             }
1564         }
1565     }
1566     Widget widget = getWidget (cast(GtkWidget*)callbackData.data);
1567     if (widget is null) return 0;
1568     return widget.filterProc (cast(XEvent*)xEvent, gdkEvent, callbackData.data);
1569 }
1570 
1571 /**
1572  * Returns the location of the on-screen pointer relative
1573  * to the top left corner of the screen.
1574  *
1575  * @return the cursor location
1576  *
1577  * @exception SWTException <ul>
1578  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1579  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1580  * </ul>
1581  */
1582 public Point getCursorLocation () {
1583     checkDevice ();
1584     int x, y;
1585     OS.gdk_window_get_pointer (null, &x, &y, null);
1586     return new Point (x, y);
1587 }
1588 
1589 /**
1590  * Returns an array containing the recommended cursor sizes.
1591  *
1592  * @return the array of cursor sizes
1593  *
1594  * @exception SWTException <ul>
1595  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1596  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1597  * </ul>
1598  *
1599  * @since 3.0
1600  */
1601 public Point [] getCursorSizes () {
1602     checkDevice ();
1603     return [new Point (16, 16), new Point (32, 32)];
1604 }
1605 
1606 /**
1607  * Returns the application defined property of the receiver
1608  * with the specified name, or null if it has not been set.
1609  * <p>
1610  * Applications may have associated arbitrary objects with the
1611  * receiver in this fashion. If the objects stored in the
1612  * properties need to be notified when the display is disposed
1613  * of, it is the application's responsibility to provide a
1614  * <code>disposeExec()</code> handler which does so.
1615  * </p>
1616  *
1617  * @param key the name of the property
1618  * @return the value of the property or null if it has not been set
1619  *
1620  * @exception SWTException <ul>
1621  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1622  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1623  * </ul>
1624  *
1625  * @see #setData(String, Object)
1626  * @see #disposeExec(Runnable)
1627  */
1628 public Object getData (String key) {
1629     checkDevice ();
1630     // SWT extension: allow null for zero length string
1631     //if (key is null) error (SWT.ERROR_NULL_ARGUMENT);
1632     if (key.equals (DISPATCH_EVENT_KEY)) {
1633         return new ArrayWrapperInt(dispatchEvents);
1634     }
1635     if (key.equals (GET_MODAL_DIALOG)) {
1636         return modalDialog;
1637     }
1638     if (key.equals (GET_DIRECTION_PROC_KEY)) {
1639         return new LONG (cast(int) &setDirectionProcFunc);
1640     }
1641     if (key.equals (GET_EMISSION_PROC_KEY)) {
1642         return new LONG (cast(int) &emissionFunc);
1643     }
1644     if (keys is null) return null;
1645     for (int i=0; i<keys.length; i++) {
1646         if (keys [i].equals(key)) return values [i];
1647     }
1648     return null;
1649 }
1650 
1651 /**
1652  * Returns the application defined, display specific data
1653  * associated with the receiver, or null if it has not been
1654  * set. The <em>display specific data</em> is a single,
1655  * unnamed field that is stored with every display.
1656  * <p>
1657  * Applications may put arbitrary objects in this field. If
1658  * the object stored in the display specific data needs to
1659  * be notified when the display is disposed of, it is the
1660  * application's responsibility to provide a
1661  * <code>disposeExec()</code> handler which does so.
1662  * </p>
1663  *
1664  * @return the display specific data
1665  *
1666  * @exception SWTException <ul>
1667  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1668  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1669  * </ul>
1670  *
1671  * @see #setData(Object)
1672  * @see #disposeExec(Runnable)
1673  */
1674 public Object getData () {
1675     checkDevice ();
1676     return data;
1677 }
1678 
1679 /**
1680  * Returns a point whose x coordinate is the horizontal
1681  * dots per inch of the display, and whose y coordinate
1682  * is the vertical dots per inch of the display.
1683  *
1684  * @return the horizontal and vertical DPI
1685  *
1686  * @exception SWTException <ul>
1687  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1688  * </ul>
1689  */
1690 public override Point getDPI () {
1691     checkDevice ();
1692     int widthMM = OS.gdk_screen_width_mm ();
1693     int width = OS.gdk_screen_width ();
1694     int dpi = Compatibility.round (254 * width, widthMM * 10);
1695     return new Point (dpi, dpi);
1696 }
1697 
1698 ptrdiff_t gtk_fixed_get_type () {
1699     return fixed_type;
1700 }
1701 
1702 ptrdiff_t gtk_cell_renderer_text_get_type () {
1703     return text_renderer_type;
1704 }
1705 
1706 ptrdiff_t gtk_cell_renderer_pixbuf_get_type () {
1707     return pixbuf_renderer_type;
1708 }
1709 
1710 ptrdiff_t gtk_cell_renderer_toggle_get_type () {
1711     return toggle_renderer_type;
1712 }
1713 
1714 /**
1715  * Returns the default display. One is created (making the
1716  * thread that invokes this method its user-interface thread)
1717  * if it did not already exist.
1718  *
1719  * @return the default display
1720  */
1721 public static Display getDefault () {
1722     synchronized (Device.classinfo) {
1723         if (Default is null) Default = new Display ();
1724         return Default;
1725     }
1726 }
1727 
1728 // /+static bool isValidClass (Class clazz) {
1729 // //PORTING_TODO   String name = clazz.getName ();
1730 // //PORTING_TODO   int index = name.lastIndexOf ('.');
1731 // //PORTING_TODO   return name.substring (0, index + 1)==/*eq*/ PACKAGE_PREFIX;
1732 //     return true;
1733 // }+/
1734 
1735 /**
1736  * Returns the button dismissal alignment, one of <code>LEFT</code> or <code>RIGHT</code>.
1737  * The button dismissal alignment is the ordering that should be used when positioning the
1738  * default dismissal button for a dialog.  For example, in a dialog that contains an OK and
1739  * CANCEL button, on platforms where the button dismissal alignment is <code>LEFT</code>, the
1740  * button ordering should be OK/CANCEL.  When button dismissal alignment is <code>RIGHT</code>,
1741  * the button ordering should be CANCEL/OK.
1742  *
1743  * @return the button dismissal order
1744  *
1745  * @exception SWTException <ul>
1746  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1747  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1748  * </ul>
1749  *
1750  * @since 2.1
1751  */
1752 public int getDismissalAlignment () {
1753     checkDevice ();
1754     return SWT.RIGHT;
1755 }
1756 
1757 /**
1758  * Returns the longest duration, in milliseconds, between
1759  * two mouse button clicks that will be considered a
1760  * <em>double click</em> by the underlying operating system.
1761  *
1762  * @return the double click time
1763  *
1764  * @exception SWTException <ul>
1765  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1766  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1767  * </ul>
1768  */
1769 public int getDoubleClickTime () {
1770     checkDevice ();
1771     auto settings = OS.gtk_settings_get_default ();
1772     int buffer;
1773     OS.g_object_get1 (settings, OS.gtk_double_click_time.ptr, &buffer);
1774     return buffer;
1775 }
1776 
1777 /**
1778  * Returns the control which currently has keyboard focus,
1779  * or null if keyboard events are not currently going to
1780  * any of the controls built by the currently running
1781  * application.
1782  *
1783  * @return the control under the cursor
1784  *
1785  * @exception SWTException <ul>
1786  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1787  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1788  * </ul>
1789  */
1790 public Control getFocusControl () {
1791     checkDevice ();
1792     if (focusControl !is null && !focusControl.isDisposed ()) {
1793         return focusControl;
1794     }
1795     if (activeShell is null) return null;
1796     auto shellHandle = activeShell.shellHandle;
1797     auto handle = OS.gtk_window_get_focus (cast(GtkWindow*)shellHandle);
1798     if (handle is null) return null;
1799     do {
1800         Widget widget = getWidget (handle);
1801         if (widget !is null && (null !is cast(Control)widget)) {
1802             Control control = cast(Control) widget;
1803             return control.isEnabled () ? control : null;
1804         }
1805     } while ((handle = OS.gtk_widget_get_parent (handle)) !is null);
1806     return null;
1807 }
1808 
1809 /**
1810  * Returns true when the high contrast mode is enabled.
1811  * Otherwise, false is returned.
1812  * <p>
1813  * Note: This operation is a hint and is not supported on
1814  * platforms that do not have this concept.
1815  * </p>
1816  *
1817  * @return the high contrast mode
1818  *
1819  * @exception SWTException <ul>
1820  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1821  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1822  * </ul>
1823  *
1824  * @since 3.0
1825  */
1826 public bool getHighContrast () {
1827     checkDevice ();
1828     return false;
1829 }
1830 
1831 public override int getDepth () {
1832     checkDevice ();
1833     auto visual = OS.gdk_visual_get_system();
1834     return visual.depth;
1835 }
1836 
1837 /**
1838  * Returns the maximum allowed depth of icons on this display, in bits per pixel.
1839  * On some platforms, this may be different than the actual depth of the display.
1840  *
1841  * @return the maximum icon depth
1842  *
1843  * @exception SWTException <ul>
1844  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1845  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1846  * </ul>
1847  *
1848  * @see Device#getDepth
1849  */
1850 public int getIconDepth () {
1851     checkDevice ();
1852     return getDepth ();
1853 }
1854 
1855 /**
1856  * Returns an array containing the recommended icon sizes.
1857  *
1858  * @return the array of icon sizes
1859  *
1860  * @exception SWTException <ul>
1861  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1862  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1863  * </ul>
1864  *
1865  * @see Decorations#setImages(Image[])
1866  *
1867  * @since 3.0
1868  */
1869 public Point [] getIconSizes () {
1870     checkDevice ();
1871     return [new Point (16, 16), new Point (32, 32)];
1872 }
1873 
1874 int getLastEventTime () {
1875     return lastEventTime;
1876 }
1877 
1878 int getMessageCount () {
1879     return synchronizer.getMessageCount ();
1880 }
1881 
1882 Dialog getModalDialog () {
1883     return modalDialog;
1884 }
1885 
1886 /**
1887  * Returns the work area, an EWMH property to store the size
1888  * and position of the screen not covered by dock and panel
1889  * windows.  See http://freedesktop.org/Standards/wm-spec.
1890  */
1891 Rectangle getWorkArea() {
1892     auto atom = OS.gdk_atom_intern ("_NET_WORKAREA".ptr, true);
1893     if (atom is null/*OS.GDK_NONE*/) return null;
1894     void* actualType;
1895     int actualFormat;
1896     int actualLength;
1897     char* data;
1898     if (!OS.gdk_property_get (cast(GdkDrawable*)OS.GDK_ROOT_PARENT (), atom, null/*OS.GDK_NONE*/, 0, 16, 0, &actualType, &actualFormat, &actualLength, &data)) {
1899         return null;
1900     }
1901     Rectangle result = null;
1902     if (data !is null) {
1903         if (actualLength is 16) {
1904             int[] values = (cast(int*)data)[0..4];
1905             result = new Rectangle (values [0],values [1],values [2],values [3]);
1906         } else if (actualLength is 32) {
1907             long[] values = (cast(long*)data)[0..4];
1908             result = new Rectangle (cast(int)values [0],cast(int)values [1],cast(int)values [2],cast(int)values [3]);
1909         }
1910         OS.g_free (data);
1911     }
1912     return result;
1913 }
1914 
1915 /**
1916  * Returns an array of monitors attached to the device.
1917  *
1918  * @return the array of monitors
1919  *
1920  * @since 3.0
1921  */
1922 public org.eclipse.swt.widgets.Monitor.Monitor [] getMonitors () {
1923     checkDevice ();
1924     org.eclipse.swt.widgets.Monitor.Monitor [] monitors = null;
1925     Rectangle workArea = getWorkArea();
1926     auto screen = OS.gdk_screen_get_default ();
1927     if (screen !is null) {
1928         int monitorCount = OS.gdk_screen_get_n_monitors (screen);
1929         if (monitorCount > 0) {
1930             monitors = new org.eclipse.swt.widgets.Monitor.Monitor [monitorCount];
1931             GdkRectangle* dest = new GdkRectangle ();
1932             for (int i = 0; i < monitorCount; i++) {
1933                 OS.gdk_screen_get_monitor_geometry (screen, i, dest);
1934                 auto monitor = new org.eclipse.swt.widgets.Monitor.Monitor ();
1935                 monitor.handle = i;
1936                 monitor.x = dest.x;
1937                 monitor.y = dest.y;
1938                 monitor.width = dest.width;
1939                 monitor.height = dest.height;
1940                 if (i is 0 && workArea !is null) {
1941                     monitor.clientX = workArea.x;
1942                     monitor.clientY = workArea.y;
1943                     monitor.clientWidth = workArea.width;
1944                     monitor.clientHeight = workArea.height;
1945                 } else {
1946                     monitor.clientX = monitor.x;
1947                     monitor.clientY = monitor.y;
1948                     monitor.clientWidth = monitor.width;
1949                     monitor.clientHeight = monitor.height;
1950                 }
1951                 monitors [i] = monitor;
1952             }
1953         }
1954     }
1955     if (monitors is null) {
1956         /* No multimonitor support detected, default to one monitor */
1957         auto monitor = new org.eclipse.swt.widgets.Monitor.Monitor ();
1958         Rectangle bounds = getBounds ();
1959         monitor.x = bounds.x;
1960         monitor.y = bounds.y;
1961         monitor.width = bounds.width;
1962         monitor.height = bounds.height;
1963         if (workArea !is null) {
1964             monitor.clientX = workArea.x;
1965             monitor.clientY = workArea.y;
1966             monitor.clientWidth = workArea.width;
1967             monitor.clientHeight = workArea.height;
1968         } else {
1969             monitor.clientX = monitor.x;
1970             monitor.clientY = monitor.y;
1971             monitor.clientWidth = monitor.width;
1972             monitor.clientHeight = monitor.height;
1973         }
1974         monitors = [ monitor ];
1975     }
1976     return monitors;
1977 }
1978 
1979 /**
1980  * Returns the primary monitor for that device.
1981  *
1982  * @return the primary monitor
1983  *
1984  * @since 3.0
1985  */
1986 public org.eclipse.swt.widgets.Monitor.Monitor getPrimaryMonitor () {
1987     checkDevice ();
1988     auto monitors = getMonitors ();
1989     return monitors [0];
1990 }
1991 
1992 /**
1993  * Returns a (possibly empty) array containing all shells which have
1994  * not been disposed and have the receiver as their display.
1995  *
1996  * @return the receiver's shells
1997  *
1998  * @exception SWTException <ul>
1999  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2000  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2001  * </ul>
2002  */
2003 public Shell [] getShells () {
2004     checkDevice ();
2005     int index = 0;
2006     Shell [] result = new Shell [16];
2007     for (int i = 0; i < widgetTable.length; i++) {
2008         Widget widget = widgetTable [i];
2009         if (widget !is null && (null !is cast(Shell)widget)) {
2010             int j = 0;
2011             while (j < index) {
2012                 if (result [j] is widget) break;
2013                 j++;
2014             }
2015             if (j is index) {
2016                 if (index is result.length) {
2017                     Shell [] newResult = new Shell [index + 16];
2018                     System.arraycopy (result, 0, newResult, 0, index);
2019                     result = newResult;
2020                 }
2021                 result [index++] = cast(Shell) widget;
2022             }
2023         }
2024     }
2025     if (index is result.length) return result;
2026     Shell [] newResult = new Shell [index];
2027     System.arraycopy (result, 0, newResult, 0, index);
2028     return newResult;
2029 }
2030 
2031 /**
2032  * Gets the synchronizer used by the display.
2033  *
2034  * @return the receiver's synchronizer
2035  *
2036  * @exception SWTException <ul>
2037  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2038  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2039  * </ul>
2040  *
2041  * @since 3.4
2042  */
2043 public Synchronizer getSynchronizer () {
2044     checkDevice ();
2045     return synchronizer;
2046 }
2047 
2048 /**
2049  * Returns the thread that has invoked <code>syncExec</code>
2050  * or null if no such runnable is currently being invoked by
2051  * the user-interface thread.
2052  * <p>
2053  * Note: If a runnable invoked by asyncExec is currently
2054  * running, this method will return null.
2055  * </p>
2056  *
2057  * @return the receiver's sync-interface thread
2058  *
2059  * @exception SWTException <ul>
2060  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2061  * </ul>
2062  */
2063 public Thread getSyncThread () {
2064     synchronized (Device.classinfo) {
2065         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2066         return synchronizer.syncThread;
2067     }
2068 }
2069 
2070 /**
2071  * Returns the matching standard color for the given
2072  * constant, which should be one of the color constants
2073  * specified in class <code>SWT</code>. Any value other
2074  * than one of the SWT color constants which is passed
2075  * in will result in the color black. This color should
2076  * not be free'd because it was allocated by the system,
2077  * not the application.
2078  *
2079  * @param id the color constant
2080  * @return the matching color
2081  *
2082  * @exception SWTException <ul>
2083  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2084  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2085  * </ul>
2086  *
2087  * @see SWT
2088  */
2089 public override Color getSystemColor (int id) {
2090     checkDevice ();
2091     GdkColor* gdkColor = null;
2092     switch (id) {
2093         case SWT.COLOR_INFO_FOREGROUND:                     gdkColor = COLOR_INFO_FOREGROUND; break;
2094         case SWT.COLOR_INFO_BACKGROUND:                     gdkColor = COLOR_INFO_BACKGROUND; break;
2095         case SWT.COLOR_TITLE_FOREGROUND:                    gdkColor = COLOR_TITLE_FOREGROUND; break;
2096         case SWT.COLOR_TITLE_BACKGROUND:                    gdkColor = COLOR_TITLE_BACKGROUND; break;
2097         case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:           gdkColor = COLOR_TITLE_BACKGROUND_GRADIENT; break;
2098         case SWT.COLOR_TITLE_INACTIVE_FOREGROUND:           gdkColor = COLOR_TITLE_INACTIVE_FOREGROUND; break;
2099         case SWT.COLOR_TITLE_INACTIVE_BACKGROUND:           gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND; break;
2100         case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:  gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT; break;
2101         case SWT.COLOR_WIDGET_DARK_SHADOW:                  gdkColor = COLOR_WIDGET_DARK_SHADOW; break;
2102         case SWT.COLOR_WIDGET_NORMAL_SHADOW:                gdkColor = COLOR_WIDGET_NORMAL_SHADOW; break;
2103         case SWT.COLOR_WIDGET_LIGHT_SHADOW:                 gdkColor = COLOR_WIDGET_LIGHT_SHADOW; break;
2104         case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW:             gdkColor = COLOR_WIDGET_HIGHLIGHT_SHADOW; break;
2105         case SWT.COLOR_WIDGET_BACKGROUND:                   gdkColor = COLOR_WIDGET_BACKGROUND; break;
2106         case SWT.COLOR_WIDGET_FOREGROUND:                   gdkColor = COLOR_WIDGET_FOREGROUND; break;
2107         case SWT.COLOR_WIDGET_BORDER:                       gdkColor = COLOR_WIDGET_BORDER; break;
2108         case SWT.COLOR_LIST_FOREGROUND:                     gdkColor = COLOR_LIST_FOREGROUND; break;
2109         case SWT.COLOR_LIST_BACKGROUND:                     gdkColor = COLOR_LIST_BACKGROUND; break;
2110         case SWT.COLOR_LIST_SELECTION:                      gdkColor = COLOR_LIST_SELECTION; break;
2111         case SWT.COLOR_LIST_SELECTION_TEXT:                 gdkColor = COLOR_LIST_SELECTION_TEXT; break;
2112         default:
2113             return super.getSystemColor (id);
2114     }
2115     if (gdkColor is null) return super.getSystemColor (SWT.COLOR_BLACK);
2116     return Color.gtk_new (this, gdkColor);
2117 }
2118 
2119 /**
2120  * Returns the matching standard platform cursor for the given
2121  * constant, which should be one of the cursor constants
2122  * specified in class <code>SWT</code>. This cursor should
2123  * not be free'd because it was allocated by the system,
2124  * not the application.  A value of <code>null</code> will
2125  * be returned if the supplied constant is not an SWT cursor
2126  * constant.
2127  *
2128  * @param id the SWT cursor constant
2129  * @return the corresponding cursor or <code>null</code>
2130  *
2131  * @exception SWTException <ul>
2132  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2133  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2134  * </ul>
2135  *
2136  * @see SWT#CURSOR_ARROW
2137  * @see SWT#CURSOR_WAIT
2138  * @see SWT#CURSOR_CROSS
2139  * @see SWT#CURSOR_APPSTARTING
2140  * @see SWT#CURSOR_HELP
2141  * @see SWT#CURSOR_SIZEALL
2142  * @see SWT#CURSOR_SIZENESW
2143  * @see SWT#CURSOR_SIZENS
2144  * @see SWT#CURSOR_SIZENWSE
2145  * @see SWT#CURSOR_SIZEWE
2146  * @see SWT#CURSOR_SIZEN
2147  * @see SWT#CURSOR_SIZES
2148  * @see SWT#CURSOR_SIZEE
2149  * @see SWT#CURSOR_SIZEW
2150  * @see SWT#CURSOR_SIZENE
2151  * @see SWT#CURSOR_SIZESE
2152  * @see SWT#CURSOR_SIZESW
2153  * @see SWT#CURSOR_SIZENW
2154  * @see SWT#CURSOR_UPARROW
2155  * @see SWT#CURSOR_IBEAM
2156  * @see SWT#CURSOR_NO
2157  * @see SWT#CURSOR_HAND
2158  *
2159  * @since 3.0
2160  */
2161 public Cursor getSystemCursor (int id) {
2162     checkDevice ();
2163     if (!(0 <= id && id < cursors.length)) return null;
2164     if (cursors [id] is null) {
2165         cursors [id] = new Cursor (this, id);
2166     }
2167     return cursors [id];
2168 }
2169 
2170 /**
2171  * Returns the matching standard platform image for the given
2172  * constant, which should be one of the icon constants
2173  * specified in class <code>SWT</code>. This image should
2174  * not be free'd because it was allocated by the system,
2175  * not the application.  A value of <code>null</code> will
2176  * be returned either if the supplied constant is not an
2177  * SWT icon constant or if the platform does not define an
2178  * image that corresponds to the constant.
2179  *
2180  * @param id the SWT icon constant
2181  * @return the corresponding image or <code>null</code>
2182  *
2183  * @exception SWTException <ul>
2184  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2185  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2186  * </ul>
2187  *
2188  * @see SWT#ICON_ERROR
2189  * @see SWT#ICON_INFORMATION
2190  * @see SWT#ICON_QUESTION
2191  * @see SWT#ICON_WARNING
2192  * @see SWT#ICON_WORKING
2193  *
2194  * @since 3.0
2195  */
2196 public Image getSystemImage (int id) {
2197     checkDevice ();
2198     switch (id) {
2199         case SWT.ICON_ERROR:
2200             if (errorImage is null) {
2201                 errorImage = createImage ("gtk-dialog-error"); //$NON-NLS-1$
2202             }
2203             return errorImage;
2204         case SWT.ICON_INFORMATION:
2205         case SWT.ICON_WORKING:
2206             if (infoImage is null) {
2207                 infoImage = createImage ("gtk-dialog-info"); //$NON-NLS-1$
2208             }
2209             return infoImage;
2210         case SWT.ICON_QUESTION:
2211             if (questionImage is null) {
2212                 questionImage = createImage ("gtk-dialog-question"); //$NON-NLS-1$
2213             }
2214             return questionImage;
2215         case SWT.ICON_WARNING:
2216             if (warningImage is null) {
2217                 warningImage = createImage ("gtk-dialog-warning"); //$NON-NLS-1$
2218             }
2219             return warningImage;
2220         default:
2221     }
2222     return null;
2223 }
2224 
2225 void initializeSystemColors () {
2226     GdkColor* gdkColor;
2227 
2228     /* Get Tooltip resources */
2229     auto tooltipShellHandle = OS.gtk_window_new (OS.GTK_WINDOW_POPUP);
2230     if (tooltipShellHandle is null) SWT.error (SWT.ERROR_NO_HANDLES);
2231 //  byte[] gtk_tooltips = Converter.wcsToMbcs (null, "gtk-tooltips", true);
2232     OS.gtk_widget_set_name (tooltipShellHandle, "gtk-tooltips".ptr );
2233     OS.gtk_widget_realize (tooltipShellHandle);
2234     auto tooltipStyle = OS.gtk_widget_get_style (tooltipShellHandle);
2235     gdkColor = new GdkColor();
2236     OS.gtk_style_get_fg (tooltipStyle, OS.GTK_STATE_NORMAL, gdkColor);
2237     COLOR_INFO_FOREGROUND = gdkColor;
2238     gdkColor = new GdkColor();
2239     OS.gtk_style_get_bg (tooltipStyle, OS.GTK_STATE_NORMAL, gdkColor);
2240     COLOR_INFO_BACKGROUND = gdkColor;
2241     OS.gtk_widget_destroy (tooltipShellHandle);
2242 
2243     /* Get Shell resources */
2244     auto style = OS.gtk_widget_get_style (shellHandle);
2245     gdkColor = new GdkColor();
2246     OS.gtk_style_get_black (style, gdkColor);
2247     COLOR_WIDGET_DARK_SHADOW = gdkColor;
2248     gdkColor = new GdkColor();
2249     OS.gtk_style_get_dark (style, OS.GTK_STATE_NORMAL, gdkColor);
2250     COLOR_WIDGET_NORMAL_SHADOW = gdkColor;
2251     gdkColor = new GdkColor();
2252     OS.gtk_style_get_bg (style, OS.GTK_STATE_NORMAL, gdkColor);
2253     COLOR_WIDGET_LIGHT_SHADOW = gdkColor;
2254     gdkColor = new GdkColor();
2255     OS.gtk_style_get_light (style, OS.GTK_STATE_NORMAL, gdkColor);
2256     COLOR_WIDGET_HIGHLIGHT_SHADOW = gdkColor;
2257     gdkColor = new GdkColor();
2258     OS.gtk_style_get_fg (style, OS.GTK_STATE_NORMAL, gdkColor);
2259     COLOR_WIDGET_FOREGROUND = gdkColor;
2260     gdkColor = new GdkColor();
2261     OS.gtk_style_get_bg (style, OS.GTK_STATE_NORMAL, gdkColor);
2262     COLOR_WIDGET_BACKGROUND = gdkColor;
2263     //gdkColor = new GdkColor();
2264     //OS.gtk_style_get_text (style, OS.GTK_STATE_NORMAL, gdkColor);
2265     //COLOR_TEXT_FOREGROUND = gdkColor;
2266     //gdkColor = new GdkColor();
2267     //OS.gtk_style_get_base (style, OS.GTK_STATE_NORMAL, gdkColor);
2268     //COLOR_TEXT_BACKGROUND = gdkColor;
2269     gdkColor = new GdkColor();
2270     OS.gtk_style_get_text (style, OS.GTK_STATE_NORMAL, gdkColor);
2271     COLOR_LIST_FOREGROUND = gdkColor;
2272     gdkColor = new GdkColor();
2273     OS.gtk_style_get_base (style, OS.GTK_STATE_NORMAL, gdkColor);
2274     COLOR_LIST_BACKGROUND = gdkColor;
2275     gdkColor = new GdkColor();
2276     OS.gtk_style_get_text (style, OS.GTK_STATE_SELECTED, gdkColor);
2277     COLOR_LIST_SELECTION_TEXT = gdkColor;
2278     gdkColor = new GdkColor();
2279     OS.gtk_style_get_base (style, OS.GTK_STATE_SELECTED, gdkColor);
2280     COLOR_LIST_SELECTION = gdkColor;
2281     gdkColor = new GdkColor();
2282     OS.gtk_style_get_bg (style, OS.GTK_STATE_SELECTED, gdkColor);
2283     COLOR_TITLE_BACKGROUND = gdkColor;
2284     gdkColor = new GdkColor();
2285     OS.gtk_style_get_fg (style, OS.GTK_STATE_SELECTED, gdkColor);
2286     COLOR_TITLE_FOREGROUND = gdkColor;
2287     gdkColor = new GdkColor();
2288     OS.gtk_style_get_light (style, OS.GTK_STATE_SELECTED, gdkColor);
2289     COLOR_TITLE_BACKGROUND_GRADIENT = gdkColor;
2290     gdkColor = new GdkColor();
2291     OS.gtk_style_get_bg (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
2292     COLOR_TITLE_INACTIVE_BACKGROUND = gdkColor;
2293     gdkColor = new GdkColor();
2294     OS.gtk_style_get_fg (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
2295     COLOR_TITLE_INACTIVE_FOREGROUND = gdkColor;
2296     gdkColor = new GdkColor();
2297     OS.gtk_style_get_light (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
2298     COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT = gdkColor;
2299 }
2300 
2301 /**
2302  * Returns a reasonable font for applications to use.
2303  * On some platforms, this will match the "default font"
2304  * or "system font" if such can be found.  This font
2305  * should not be free'd because it was allocated by the
2306  * system, not the application.
2307  * <p>
2308  * Typically, applications which want the default look
2309  * should simply not set the font on the widgets they
2310  * create. Widgets are always created with the correct
2311  * default font for the class of user-interface component
2312  * they represent.
2313  * </p>
2314  *
2315  * @return a font
2316  *
2317  * @exception SWTException <ul>
2318  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2319  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2320  * </ul>
2321  */
2322 public override Font getSystemFont () {
2323     checkDevice ();
2324     if (systemFont !is null) return systemFont;
2325     auto style = OS.gtk_widget_get_style (shellHandle);
2326     auto defaultFont = OS.pango_font_description_copy (OS.gtk_style_get_font_desc (style));
2327     return systemFont = Font.gtk_new (this, defaultFont);
2328 }
2329 
2330 /**
2331  * Returns the single instance of the system tray or null
2332  * when there is no system tray available for the platform.
2333  *
2334  * @return the system tray or <code>null</code>
2335  *
2336  * @exception SWTException <ul>
2337  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2338  * </ul>
2339  *
2340  * @since 3.0
2341  */
2342 public Tray getSystemTray () {
2343     checkDevice ();
2344     if (tray !is null) return tray;
2345     return tray = new Tray (this, SWT.NONE);
2346 }
2347 
2348 /**
2349  * Returns the user-interface thread for the receiver.
2350  *
2351  * @return the receiver's user-interface thread
2352  *
2353  * @exception SWTException <ul>
2354  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2355  * </ul>
2356  */
2357 public Thread getThread () {
2358     synchronized (Device.classinfo) {
2359         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2360         return thread;
2361     }
2362 }
2363 
2364 Widget getWidget (GtkWidget* handle) {
2365     if (handle is null) return null;
2366     if (lastWidget !is null && lastHandle is handle) return lastWidget;
2367     auto index = cast(ptrdiff_t)OS.g_object_get_qdata ( cast(GObject*)handle, SWT_OBJECT_INDEX) - 1;
2368     if (0 <= index && index < widgetTable.length) {
2369         lastHandle = handle;
2370         return lastWidget = widgetTable [index];
2371     }
2372     return null;
2373 }
2374 
2375 private static extern(C) int idleProcFunc (void* data) {
2376     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
2377     auto dbdata = cast(CallbackData*)data;
2378     return dbdata.display.idleProc();
2379 }
2380 private int idleProc () {
2381     bool result = runAsyncMessages (false);
2382     if (!result) {
2383         synchronized (idleLock) {
2384             idleHandle = 0;
2385         }
2386     }
2387     return result ? 1 : 0;
2388     return 0;
2389 }
2390 
2391 /**
2392  * Initializes any internal resources needed by the
2393  * device.
2394  * <p>
2395  * This method is called after <code>create</code>.
2396  * </p>
2397  *
2398  * @see #create
2399  */
2400 protected override void init_ () {
2401     super.init_ ();
2402     initializeCallbacks ();
2403     initializeSystemColors ();
2404     initializeSystemSettings ();
2405     initializeWidgetTable ();
2406     initializeWindowManager ();
2407 }
2408 
2409 void initializeCallbacks () {
2410     closures = new GClosure* [Widget.LAST_SIGNAL];
2411     closuresCount = new int[Widget.LAST_SIGNAL];
2412     closuresProc = new GCallback [Widget.LAST_SIGNAL];
2413     signalIds = new int [Widget.LAST_SIGNAL];
2414 
2415     /* Cache signals for GtkWidget */
2416     signalIds [Widget.BUTTON_PRESS_EVENT] = OS.g_signal_lookup (OS.button_press_event.ptr, OS.GTK_TYPE_WIDGET ());
2417     signalIds [Widget.BUTTON_RELEASE_EVENT] = OS.g_signal_lookup (OS.button_release_event.ptr, OS.GTK_TYPE_WIDGET ());
2418     signalIds [Widget.CONFIGURE_EVENT] = OS.g_signal_lookup (OS.configure_event.ptr, OS.GTK_TYPE_WIDGET ());
2419     signalIds [Widget.DELETE_EVENT] = OS.g_signal_lookup (OS.delete_event.ptr, OS.GTK_TYPE_WIDGET ());
2420     signalIds [Widget.ENTER_NOTIFY_EVENT] = OS.g_signal_lookup (OS.enter_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2421     signalIds [Widget.EVENT] = OS.g_signal_lookup (OS.event.ptr, OS.GTK_TYPE_WIDGET ());
2422     signalIds [Widget.EVENT_AFTER] = OS.g_signal_lookup (OS.event_after.ptr, OS.GTK_TYPE_WIDGET ());
2423     signalIds [Widget.EXPOSE_EVENT] = OS.g_signal_lookup (OS.expose_event.ptr, OS.GTK_TYPE_WIDGET ());
2424     signalIds [Widget.FOCUS] = OS.g_signal_lookup (OS.focus.ptr, OS.GTK_TYPE_WIDGET ());
2425     signalIds [Widget.FOCUS_IN_EVENT] = OS.g_signal_lookup (OS.focus_in_event.ptr, OS.GTK_TYPE_WIDGET ());
2426     signalIds [Widget.FOCUS_OUT_EVENT] = OS.g_signal_lookup (OS.focus_out_event.ptr, OS.GTK_TYPE_WIDGET ());
2427     signalIds [Widget.GRAB_FOCUS] = OS.g_signal_lookup (OS.grab_focus.ptr, OS.GTK_TYPE_WIDGET ());
2428     signalIds [Widget.HIDE] = OS.g_signal_lookup (OS.hide.ptr, OS.GTK_TYPE_WIDGET ());
2429     signalIds [Widget.KEY_PRESS_EVENT] = OS.g_signal_lookup (OS.key_press_event.ptr, OS.GTK_TYPE_WIDGET ());
2430     signalIds [Widget.KEY_RELEASE_EVENT] = OS.g_signal_lookup (OS.key_release_event.ptr, OS.GTK_TYPE_WIDGET ());
2431     signalIds [Widget.LEAVE_NOTIFY_EVENT] = OS.g_signal_lookup (OS.leave_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2432     signalIds [Widget.MAP] = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET ());
2433     signalIds [Widget.MAP_EVENT] = OS.g_signal_lookup (OS.map_event.ptr, OS.GTK_TYPE_WIDGET ());
2434     signalIds [Widget.MNEMONIC_ACTIVATE] = OS.g_signal_lookup (OS.mnemonic_activate.ptr, OS.GTK_TYPE_WIDGET ());
2435     signalIds [Widget.MOTION_NOTIFY_EVENT] = OS.g_signal_lookup (OS.motion_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2436     signalIds [Widget.POPUP_MENU] = OS.g_signal_lookup (OS.popup_menu.ptr, OS.GTK_TYPE_WIDGET ());
2437     signalIds [Widget.REALIZE] = OS.g_signal_lookup (OS.realize.ptr, OS.GTK_TYPE_WIDGET ());
2438     signalIds [Widget.SCROLL_EVENT] = OS.g_signal_lookup (OS.scroll_event.ptr, OS.GTK_TYPE_WIDGET ());
2439     signalIds [Widget.SHOW] = OS.g_signal_lookup (OS.show.ptr, OS.GTK_TYPE_WIDGET ());
2440     signalIds [Widget.SHOW_HELP] = OS.g_signal_lookup (OS.show_help.ptr, OS.GTK_TYPE_WIDGET ());
2441     signalIds [Widget.SIZE_ALLOCATE] = OS.g_signal_lookup (OS.size_allocate.ptr, OS.GTK_TYPE_WIDGET ());
2442     signalIds [Widget.STYLE_SET] = OS.g_signal_lookup (OS.style_set.ptr, OS.GTK_TYPE_WIDGET ());
2443     signalIds [Widget.UNMAP] = OS.g_signal_lookup (OS.unmap.ptr, OS.GTK_TYPE_WIDGET ());
2444     signalIds [Widget.UNMAP_EVENT] = OS.g_signal_lookup (OS.unmap_event.ptr, OS.GTK_TYPE_WIDGET ());
2445     signalIds [Widget.UNREALIZE] = OS.g_signal_lookup (OS.realize.ptr, OS.GTK_TYPE_WIDGET ());
2446     signalIds [Widget.VISIBILITY_NOTIFY_EVENT] = OS.g_signal_lookup (OS.visibility_notify_event.ptr, OS.GTK_TYPE_WIDGET ());
2447     signalIds [Widget.WINDOW_STATE_EVENT] = OS.g_signal_lookup (OS.window_state_event.ptr, OS.GTK_TYPE_WIDGET ());
2448 
2449     GCallback do_cclosure_new( GCallback cb, int value, ptrdiff_t notify ){
2450         CallbackData* res= new CallbackData;
2451         res.display = this;
2452         res.data = cast(void*)value;
2453         windowProcCallbackDatas[ value ] = res;
2454         return cb;
2455     }
2456 
2457     GCallback windowProc2 = cast(GCallback)&windowProcFunc2;
2458     closuresProc [Widget.ACTIVATE] = do_cclosure_new (windowProc2, Widget.ACTIVATE, 0);
2459     closuresProc [Widget.ACTIVATE_INVERSE] = do_cclosure_new (windowProc2, Widget.ACTIVATE_INVERSE, 0);
2460     closuresProc [Widget.CHANGED] = do_cclosure_new (windowProc2, Widget.CHANGED, 0);
2461     closuresProc [Widget.CLICKED] = do_cclosure_new (windowProc2, Widget.CLICKED, 0);
2462     closuresProc [Widget.DAY_SELECTED] = do_cclosure_new (windowProc2, Widget.DAY_SELECTED, 0);
2463     closuresProc [Widget.HIDE] = do_cclosure_new (windowProc2, Widget.HIDE, 0);
2464     closuresProc [Widget.GRAB_FOCUS] = do_cclosure_new (windowProc2, Widget.GRAB_FOCUS, 0);
2465     closuresProc [Widget.MAP] = do_cclosure_new (windowProc2, Widget.MAP, 0);
2466     closuresProc [Widget.MONTH_CHANGED] = do_cclosure_new (windowProc2, Widget.MONTH_CHANGED, 0);
2467     closuresProc [Widget.OUTPUT] = do_cclosure_new (windowProc2, Widget.OUTPUT, 0);
2468     closuresProc [Widget.POPUP_MENU] = do_cclosure_new (windowProc2, Widget.POPUP_MENU, 0);
2469     closuresProc [Widget.PREEDIT_CHANGED] = do_cclosure_new (windowProc2, Widget.PREEDIT_CHANGED, 0);
2470     closuresProc [Widget.REALIZE] = do_cclosure_new (windowProc2, Widget.REALIZE, 0);
2471     closuresProc [Widget.SELECT] = do_cclosure_new (windowProc2, Widget.SELECT, 0);
2472     closuresProc [Widget.SHOW] = do_cclosure_new (windowProc2, Widget.SHOW, 0);
2473     closuresProc [Widget.VALUE_CHANGED] = do_cclosure_new (windowProc2, Widget.VALUE_CHANGED, 0);
2474     closuresProc [Widget.UNMAP] = do_cclosure_new (windowProc2, Widget.UNMAP, 0);
2475     closuresProc [Widget.UNREALIZE] = do_cclosure_new (windowProc2, Widget.UNREALIZE, 0);
2476 
2477     GCallback windowProc3 = cast(GCallback)&windowProcFunc3;
2478     closuresProc [Widget.BUTTON_PRESS_EVENT] = do_cclosure_new (windowProc3, Widget.BUTTON_PRESS_EVENT, 0);
2479     closuresProc [Widget.BUTTON_PRESS_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.BUTTON_PRESS_EVENT_INVERSE, 0);
2480     closuresProc [Widget.BUTTON_RELEASE_EVENT] = do_cclosure_new (windowProc3, Widget.BUTTON_RELEASE_EVENT, 0);
2481     closuresProc [Widget.BUTTON_RELEASE_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.BUTTON_RELEASE_EVENT_INVERSE, 0);
2482     closuresProc [Widget.COMMIT] = do_cclosure_new (windowProc3, Widget.COMMIT, 0);
2483     closuresProc [Widget.CONFIGURE_EVENT] = do_cclosure_new (windowProc3, Widget.CONFIGURE_EVENT, 0);
2484     closuresProc [Widget.DELETE_EVENT] = do_cclosure_new (windowProc3, Widget.DELETE_EVENT, 0);
2485     closuresProc [Widget.ENTER_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.ENTER_NOTIFY_EVENT, 0);
2486     closuresProc [Widget.EVENT] = do_cclosure_new (windowProc3, Widget.EVENT, 0);
2487     closuresProc [Widget.EVENT_AFTER] = do_cclosure_new (windowProc3, Widget.EVENT_AFTER, 0);
2488     closuresProc [Widget.EXPOSE_EVENT] = do_cclosure_new (windowProc3, Widget.EXPOSE_EVENT, 0);
2489     closuresProc [Widget.EXPOSE_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.EXPOSE_EVENT_INVERSE, 0);
2490     closuresProc [Widget.FOCUS] = do_cclosure_new (windowProc3, Widget.FOCUS, 0);
2491     closuresProc [Widget.FOCUS_IN_EVENT] = do_cclosure_new (windowProc3, Widget.FOCUS_IN_EVENT, 0);
2492     closuresProc [Widget.FOCUS_OUT_EVENT] = do_cclosure_new (windowProc3, Widget.FOCUS_OUT_EVENT, 0);
2493     closuresProc [Widget.KEY_PRESS_EVENT] = do_cclosure_new (windowProc3, Widget.KEY_PRESS_EVENT, 0);
2494     closuresProc [Widget.KEY_RELEASE_EVENT] = do_cclosure_new (windowProc3, Widget.KEY_RELEASE_EVENT, 0);
2495     closuresProc [Widget.INPUT] = do_cclosure_new (windowProc3, Widget.INPUT, 0);
2496     closuresProc [Widget.LEAVE_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.LEAVE_NOTIFY_EVENT, 0);
2497     closuresProc [Widget.MAP_EVENT] = do_cclosure_new (windowProc3, Widget.MAP_EVENT, 0);
2498     closuresProc [Widget.MNEMONIC_ACTIVATE] = do_cclosure_new (windowProc3, Widget.MNEMONIC_ACTIVATE, 0);
2499     closuresProc [Widget.MOTION_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT, 0);
2500     closuresProc [Widget.MOTION_NOTIFY_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT_INVERSE, 0);
2501     closuresProc [Widget.MOVE_FOCUS] = do_cclosure_new (windowProc3, Widget.MOVE_FOCUS, 0);
2502     closuresProc [Widget.POPULATE_POPUP] = do_cclosure_new (windowProc3, Widget.POPULATE_POPUP, 0);
2503     closuresProc [Widget.SCROLL_EVENT] = do_cclosure_new (windowProc3, Widget.SCROLL_EVENT, 0);
2504     closuresProc [Widget.SHOW_HELP] = do_cclosure_new (windowProc3, Widget.SHOW_HELP, 0);
2505     closuresProc [Widget.SIZE_ALLOCATE] = do_cclosure_new (windowProc3, Widget.SIZE_ALLOCATE, 0);
2506     closuresProc [Widget.STYLE_SET] = do_cclosure_new (windowProc3, Widget.STYLE_SET, 0);
2507     closuresProc [Widget.TOGGLED] = do_cclosure_new (windowProc3, Widget.TOGGLED, 0);
2508     closuresProc [Widget.UNMAP_EVENT] = do_cclosure_new (windowProc3, Widget.UNMAP_EVENT, 0);
2509     closuresProc [Widget.VISIBILITY_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.VISIBILITY_NOTIFY_EVENT, 0);
2510     closuresProc [Widget.WINDOW_STATE_EVENT] = do_cclosure_new (windowProc3, Widget.WINDOW_STATE_EVENT, 0);
2511 
2512     GCallback windowProc4 = cast(GCallback)&windowProcFunc4;
2513     closuresProc [Widget.DELETE_RANGE] = do_cclosure_new (windowProc4, Widget.DELETE_RANGE, 0);
2514     closuresProc [Widget.DELETE_TEXT] = do_cclosure_new (windowProc4, Widget.DELETE_TEXT, 0);
2515     closuresProc [Widget.ROW_ACTIVATED] = do_cclosure_new (windowProc4, Widget.ROW_ACTIVATED, 0);
2516     closuresProc [Widget.SCROLL_CHILD] = do_cclosure_new (windowProc4, Widget.SCROLL_CHILD, 0);
2517     closuresProc [Widget.SWITCH_PAGE] = do_cclosure_new (windowProc4, Widget.SWITCH_PAGE, 0);
2518     closuresProc [Widget.TEST_COLLAPSE_ROW] = do_cclosure_new (windowProc4, Widget.TEST_COLLAPSE_ROW, 0);
2519     closuresProc [Widget.TEST_EXPAND_ROW] = do_cclosure_new (windowProc4, Widget.TEST_EXPAND_ROW, 0);
2520 
2521     GCallback windowProc5 = cast(GCallback)&windowProcFunc5;
2522     closuresProc [Widget.EXPAND_COLLAPSE_CURSOR_ROW] = do_cclosure_new (windowProc5, Widget.EXPAND_COLLAPSE_CURSOR_ROW, 0);
2523     closuresProc [Widget.INSERT_TEXT] = do_cclosure_new (windowProc5, Widget.INSERT_TEXT, 0);
2524     closuresProc [Widget.TEXT_BUFFER_INSERT_TEXT] = do_cclosure_new (windowProc5, Widget.TEXT_BUFFER_INSERT_TEXT, 0);
2525 
2526     GCallback windowChangeValueProc = cast(GCallback)&windowProcChangeValueFunc;
2527     closuresProc [Widget.CHANGE_VALUE] = do_cclosure_new (windowChangeValueProc, Widget.CHANGE_VALUE, 0);
2528 
2529     for (int i = 0; i < Widget.LAST_SIGNAL; i++) {
2530         if (closuresProc[i] !is null) {
2531             auto res = windowProcCallbackDatas [i];
2532             closures [i] = OS.g_cclosure_new(closuresProc [i], res, null);
2533         }
2534         if (closures [i] !is null) {
2535             OS.g_closure_ref (closures [i]);
2536             OS.g_closure_sink (closures [i]);
2537         }
2538     }
2539     shellMapProcCallbackData.display = this;
2540     shellMapProcCallbackData.data = null;
2541     shellMapProcClosure = OS.g_cclosure_new (cast(GCallback)&shellMapProcFunc, &shellMapProcCallbackData, cast(GClosureNotify)0);
2542     OS.g_closure_ref (shellMapProcClosure);
2543 }
2544 
2545 void* getWindowProcUserData( int value ){
2546     return windowProcCallbackDatas[ value ];
2547 
2548 }
2549 
2550 void initializeSystemSettings () {
2551     styleSetProcCallbackData.display = this;
2552     styleSetProcCallbackData.data = null;
2553     OS.g_signal_connect (shellHandle, OS.style_set.ptr, cast(GCallback)&styleSetProcFunc, &styleSetProcCallbackData);
2554 
2555     /*
2556     * Feature in GTK.  Despite the fact that the
2557     * gtk-entry-select-on-focus property is a global
2558     * setting, it is initialized when the GtkEntry
2559     * is initialized.  This means that it cannot be
2560     * accessed before a GtkEntry is created.  The
2561     * fix is to for the initializaion by creating
2562     * a temporary GtkEntry.
2563     */
2564     auto entry = OS.gtk_entry_new ();
2565     OS.gtk_widget_destroy (entry);
2566     int buffer2;
2567     auto settings = OS.gtk_settings_get_default ();
2568     OS.g_object_get1 (settings, OS.gtk_entry_select_on_focus.ptr, &buffer2);
2569     entrySelectOnFocus = buffer2 !is 0;
2570 }
2571 
2572 void initializeWidgetTable () {
2573     indexTable = new ptrdiff_t [GROW_SIZE];
2574     widgetTable = new Widget [GROW_SIZE];
2575     for (int i=0; i<GROW_SIZE-1; i++) indexTable [i] = i + 1;
2576     indexTable [GROW_SIZE - 1] = -1;
2577 }
2578 
2579 void initializeWindowManager () {
2580     /* Get the window manager name */
2581     windowManager = ""; //$NON-NLS-1$
2582     if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 0)) {
2583         auto screen = OS.gdk_screen_get_default ();
2584         if (screen !is null) {
2585             auto ptr2 = OS.gdk_x11_screen_get_window_manager_name (screen);
2586             windowManager = fromStringz( ptr2 )._idup();
2587         }
2588     }
2589 }
2590 
2591 /**
2592  * Invokes platform specific functionality to dispose a GC handle.
2593  * <p>
2594  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
2595  * API for <code>Display</code>. It is marked public only so that it
2596  * can be shared within the packages provided by SWT. It is not
2597  * available on all platforms, and should never be called from
2598  * application code.
2599  * </p>
2600  *
2601  * @param hDC the platform specific GC handle
2602  * @param data the platform specific GC data
2603  */
2604 public override void internal_dispose_GC (GdkGC* gdkGC, GCData data) {
2605     OS.g_object_unref (gdkGC);
2606 }
2607 
2608 /**
2609  * Invokes platform specific functionality to allocate a new GC handle.
2610  * <p>
2611  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
2612  * API for <code>Display</code>. It is marked public only so that it
2613  * can be shared within the packages provided by SWT. It is not
2614  * available on all platforms, and should never be called from
2615  * application code.
2616  * </p>
2617  *
2618  * @param data the platform specific GC data
2619  * @return the platform specific GC handle
2620  *
2621  * @exception SWTException <ul>
2622  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2623  * </ul>
2624  * @exception SWTError <ul>
2625  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for gc creation</li>
2626  * </ul>
2627  */
2628 public override GdkGC* internal_new_GC (GCData data) {
2629     if (isDisposed()) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
2630     auto root = cast(GdkDrawable *) OS.GDK_ROOT_PARENT ();
2631     auto gdkGC = OS.gdk_gc_new (root);
2632     if (gdkGC is null) SWT.error (SWT.ERROR_NO_HANDLES);
2633     OS.gdk_gc_set_subwindow (gdkGC, OS.GDK_INCLUDE_INFERIORS);
2634     if (data !is null) {
2635         int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
2636         if ((data.style & mask) is 0) {
2637             data.style |= SWT.LEFT_TO_RIGHT;
2638         }
2639         data.device = this;
2640         data.drawable = root;
2641         data.background = getSystemColor (SWT.COLOR_WHITE).handle;
2642         data.foreground = getSystemColor (SWT.COLOR_BLACK).handle;
2643         data.font = getSystemFont ();
2644     }
2645     return gdkGC;
2646     return null;
2647 }
2648 
2649 bool isValidThread () {
2650     return thread is Thread.currentThread ();
2651 }
2652 
2653 /**
2654  * Maps a point from one coordinate system to another.
2655  * When the control is null, coordinates are mapped to
2656  * the display.
2657  * <p>
2658  * NOTE: On right-to-left platforms where the coordinate
2659  * systems are mirrored, special care needs to be taken
2660  * when mapping coordinates from one control to another
2661  * to ensure the result is correctly mirrored.
2662  *
2663  * Mapping a point that is the origin of a rectangle and
2664  * then adding the width and height is not equivalent to
2665  * mapping the rectangle.  When one control is mirrored
2666  * and the other is not, adding the width and height to a
2667  * point that was mapped causes the rectangle to extend
2668  * in the wrong direction.  Mapping the entire rectangle
2669  * instead of just one point causes both the origin and
2670  * the corner of the rectangle to be mapped.
2671  * </p>
2672  *
2673  * @param from the source <code>Control</code> or <code>null</code>
2674  * @param to the destination <code>Control</code> or <code>null</code>
2675  * @param point to be mapped
2676  * @return point with mapped coordinates
2677  *
2678  * @exception IllegalArgumentException <ul>
2679  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
2680  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2681  * </ul>
2682  * @exception SWTException <ul>
2683  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2684  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2685  * </ul>
2686  *
2687  * @since 2.1.2
2688  */
2689 public Point map (Control from, Control to, Point point) {
2690     checkDevice ();
2691     if (point is null) error (SWT.ERROR_NULL_ARGUMENT);
2692     return map (from, to, point.x, point.y);
2693 }
2694 
2695 /**
2696  * Maps a point from one coordinate system to another.
2697  * When the control is null, coordinates are mapped to
2698  * the display.
2699  * <p>
2700  * NOTE: On right-to-left platforms where the coordinate
2701  * systems are mirrored, special care needs to be taken
2702  * when mapping coordinates from one control to another
2703  * to ensure the result is correctly mirrored.
2704  *
2705  * Mapping a point that is the origin of a rectangle and
2706  * then adding the width and height is not equivalent to
2707  * mapping the rectangle.  When one control is mirrored
2708  * and the other is not, adding the width and height to a
2709  * point that was mapped causes the rectangle to extend
2710  * in the wrong direction.  Mapping the entire rectangle
2711  * instead of just one point causes both the origin and
2712  * the corner of the rectangle to be mapped.
2713  * </p>
2714  *
2715  * @param from the source <code>Control</code> or <code>null</code>
2716  * @param to the destination <code>Control</code> or <code>null</code>
2717  * @param x coordinates to be mapped
2718  * @param y coordinates to be mapped
2719  * @return point with mapped coordinates
2720  *
2721  * @exception IllegalArgumentException <ul>
2722  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2723  * </ul>
2724  * @exception SWTException <ul>
2725  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2726  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2727  * </ul>
2728  *
2729  * @since 2.1.2
2730  */
2731 public Point map (Control from, Control to, int x, int y) {
2732     checkDevice ();
2733     if (from !is null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2734     if (to !is null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2735     Point point = new Point (x, y);
2736     if (from is to) return point;
2737     if (from !is null) {
2738         auto window = from.eventWindow ();
2739         int origin_x, origin_y;
2740         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2741         if ((from.style & SWT.MIRRORED) !is 0) point.x = from.getClientWidth () - point.x;
2742         point.x += origin_x;
2743         point.y += origin_y;
2744     }
2745     if (to !is null) {
2746         auto window = to.eventWindow ();
2747         int origin_x, origin_y;
2748         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2749         point.x -= origin_x;
2750         point.y -= origin_y;
2751         if ((to.style & SWT.MIRRORED) !is 0) point.x = to.getClientWidth () - point.x;
2752     }
2753     return point;
2754 }
2755 
2756 /**
2757  * Maps a point from one coordinate system to another.
2758  * When the control is null, coordinates are mapped to
2759  * the display.
2760  * <p>
2761  * NOTE: On right-to-left platforms where the coordinate
2762  * systems are mirrored, special care needs to be taken
2763  * when mapping coordinates from one control to another
2764  * to ensure the result is correctly mirrored.
2765  *
2766  * Mapping a point that is the origin of a rectangle and
2767  * then adding the width and height is not equivalent to
2768  * mapping the rectangle.  When one control is mirrored
2769  * and the other is not, adding the width and height to a
2770  * point that was mapped causes the rectangle to extend
2771  * in the wrong direction.  Mapping the entire rectangle
2772  * instead of just one point causes both the origin and
2773  * the corner of the rectangle to be mapped.
2774  * </p>
2775  *
2776  * @param from the source <code>Control</code> or <code>null</code>
2777  * @param to the destination <code>Control</code> or <code>null</code>
2778  * @param rectangle to be mapped
2779  * @return rectangle with mapped coordinates
2780  *
2781  * @exception IllegalArgumentException <ul>
2782  *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
2783  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2784  * </ul>
2785  * @exception SWTException <ul>
2786  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2787  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2788  * </ul>
2789  *
2790  * @since 2.1.2
2791  */
2792 public Rectangle map (Control from, Control to, Rectangle rectangle) {
2793     checkDevice();
2794     if (rectangle is null) error (SWT.ERROR_NULL_ARGUMENT);
2795     return map (from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
2796 }
2797 
2798 static wchar mbcsToWcs (wchar ch) {
2799     int key = ch & 0xFFFF;
2800     if (key <= 0x7F) return ch;
2801     char [] buffer;
2802     if (key <= 0xFF) {
2803         buffer = new char [1];
2804         buffer [0] = cast(char) key;
2805     } else {
2806         buffer = new char [2];
2807         buffer [0] = cast(char) ((key >> 8) & 0xFF);
2808         buffer [1] = cast(char) (key & 0xFF);
2809     }
2810     wchar [] result = Converter.mbcsToWcs (null, buffer);
2811     if (result.length is 0) return 0;
2812     return result [0];
2813 }
2814 
2815 
2816 package void doMenuPositionProc( GtkMenu* window, bool hasLocation ){
2817     /*
2818     * Bug in GTK.  The timestamp passed into gtk_menu_popup is used
2819     * to perform an X pointer grab.  It cannot be zero, else the grab
2820     * will fail.  The fix is to ensure that the timestamp of the last
2821     * event processed is used.
2822     */
2823     OS.gtk_menu_popup (window, null, null,
2824         hasLocation ? &menuPositionProcFunc : null,
2825         cast(void*)this, 0, getLastEventTime() );
2826 }
2827 
2828 private static extern(C) void menuPositionProcFunc (GtkMenu* menu, int* x, int* y, int* push_in, void* user_data) {
2829     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
2830     auto display = cast(Display)user_data;
2831     display.menuPositionProc( menu, x, y, push_in, null );
2832 }
2833 
2834 void menuPositionProc (GtkMenu* menu, int* x, int* y, int* push_in, void* user_data) {
2835     Widget widget = getWidget (cast(GtkWidget*)menu);
2836     if (widget is null) return;
2837     widget.menuPositionProc (menu, x, y, push_in, user_data);
2838 }
2839 
2840 /**
2841  * Maps a point from one coordinate system to another.
2842  * When the control is null, coordinates are mapped to
2843  * the display.
2844  * <p>
2845  * NOTE: On right-to-left platforms where the coordinate
2846  * systems are mirrored, special care needs to be taken
2847  * when mapping coordinates from one control to another
2848  * to ensure the result is correctly mirrored.
2849  *
2850  * Mapping a point that is the origin of a rectangle and
2851  * then adding the width and height is not equivalent to
2852  * mapping the rectangle.  When one control is mirrored
2853  * and the other is not, adding the width and height to a
2854  * point that was mapped causes the rectangle to extend
2855  * in the wrong direction.  Mapping the entire rectangle
2856  * instead of just one point causes both the origin and
2857  * the corner of the rectangle to be mapped.
2858  * </p>
2859  *
2860  * @param from the source <code>Control</code> or <code>null</code>
2861  * @param to the destination <code>Control</code> or <code>null</code>
2862  * @param x coordinates to be mapped
2863  * @param y coordinates to be mapped
2864  * @param width coordinates to be mapped
2865  * @param height coordinates to be mapped
2866  * @return rectangle with mapped coordinates
2867  *
2868  * @exception IllegalArgumentException <ul>
2869  *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
2870  * </ul>
2871  * @exception SWTException <ul>
2872  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2873  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2874  * </ul>
2875  *
2876  * @since 2.1.2
2877  */
2878 public Rectangle map (Control from, Control to, int x, int y, int width, int height) {
2879     checkDevice();
2880     if (from !is null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2881     if (to !is null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
2882     Rectangle rect = new Rectangle (x, y, width, height);
2883     if (from is to) return rect;
2884     bool fromRTL = false, toRTL = false;
2885     if (from !is null) {
2886         auto window = from.eventWindow ();
2887         int origin_x, origin_y;
2888         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2889         fromRTL = (from.style & SWT.MIRRORED) !is 0;
2890         if (fromRTL) rect.x = from.getClientWidth() - rect.x;
2891         rect.x += origin_x;
2892         rect.y += origin_y;
2893     }
2894     if (to !is null) {
2895         auto window = to.eventWindow ();
2896         int origin_x, origin_y;
2897         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
2898         rect.x -= origin_x;
2899         rect.y -= origin_y;
2900         toRTL = (to.style & SWT.MIRRORED) !is 0;
2901         if (toRTL) rect.x = to.getClientWidth () - rect.x;
2902     }
2903     if (fromRTL !is toRTL) rect.x -= rect.width;
2904     return rect;
2905 }
2906 
2907 private static extern(C) int mouseHoverProcFunc ( void* user_data) {
2908     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
2909     CallbackData* cbdata = cast(CallbackData*)user_data;
2910     return cbdata.display.mouseHoverProc( cast(GtkWidget*)cbdata.data );
2911 }
2912 int mouseHoverProc (GtkWidget* handle) {
2913     Widget widget = getWidget (handle);
2914     if (widget is null) return 0;
2915     return widget.hoverProc (handle);
2916 }
2917 
2918 /**
2919  * Generate a low level system event.
2920  *
2921  * <code>post</code> is used to generate low level keyboard
2922  * and mouse events. The intent is to enable automated UI
2923  * testing by simulating the input from the user.  Most
2924  * SWT applications should never need to call this method.
2925  * <p>
2926  * Note that this operation can fail when the operating system
2927  * fails to generate the event for any reason.  For example,
2928  * this can happen when there is no such key or mouse button
2929  * or when the system event queue is full.
2930  * </p>
2931  * <p>
2932  * <b>Event Types:</b>
2933  * <p>KeyDown, KeyUp
2934  * <p>The following fields in the <code>Event</code> apply:
2935  * <ul>
2936  * <li>(in) type KeyDown or KeyUp</li>
2937  * <p> Either one of:
2938  * <li>(in) character a character that corresponds to a keyboard key</li>
2939  * <li>(in) keyCode the key code of the key that was typed,
2940  *          as defined by the key code constants in class <code>SWT</code></li>
2941  * </ul>
2942  * <p>MouseDown, MouseUp</p>
2943  * <p>The following fields in the <code>Event</code> apply:
2944  * <ul>
2945  * <li>(in) type MouseDown or MouseUp
2946  * <li>(in) button the button that is pressed or released
2947  * </ul>
2948  * <p>MouseMove</p>
2949  * <p>The following fields in the <code>Event</code> apply:
2950  * <ul>
2951  * <li>(in) type MouseMove
2952  * <li>(in) x the x coordinate to move the mouse pointer to in screen coordinates
2953  * <li>(in) y the y coordinate to move the mouse pointer to in screen coordinates
2954  * </ul>
2955  * </dl>
2956  *
2957  * @param event the event to be generated
2958  *
2959  * @return true if the event was generated or false otherwise
2960  *
2961  * @exception IllegalArgumentException <ul>
2962  *    <li>ERROR_NULL_ARGUMENT - if the event is null</li>
2963  * </ul>
2964  * @exception SWTException <ul>
2965  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
2966  * </ul>
2967  *
2968  * @since 3.0
2969  *
2970  */
2971 public bool post (Event event) {
2972     synchronized (Device.classinfo) {
2973         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
2974         if (event is null) error (SWT.ERROR_NULL_ARGUMENT);
2975         if (!OS.GDK_WINDOWING_X11()) return false;
2976         auto xDisplay = OS.GDK_DISPLAY ();
2977         int type = event.type;
2978         switch (type) {
2979             case SWT.KeyDown:
2980             case SWT.KeyUp: {
2981                 int keyCode = 0;
2982                 auto keysym = untranslateKey (event.keyCode);
2983                 if (keysym !is 0) keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
2984                 if (keyCode is 0) {
2985                     char key = cast(char) event.character;
2986                     switch (key) {
2987                         case SWT.BS: keysym = OS.GDK_BackSpace; break;
2988                         case SWT.CR: keysym = OS.GDK_Return; break;
2989                         case SWT.DEL: keysym = OS.GDK_Delete; break;
2990                         case SWT.ESC: keysym = OS.GDK_Escape; break;
2991                         case SWT.TAB: keysym = OS.GDK_Tab; break;
2992                         case SWT.LF: keysym = OS.GDK_Linefeed; break;
2993                         default:
2994                             keysym = key;
2995                     }
2996                     keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
2997                     if (keyCode is 0) return false;
2998                 }
2999                 OS.XTestFakeKeyEvent (xDisplay, keyCode, type is SWT.KeyDown, 0);
3000                 return true;
3001             }
3002             case SWT.MouseDown:
3003             case SWT.MouseMove:
3004             case SWT.MouseUp: {
3005                 if (type is SWT.MouseMove) {
3006                     OS.XTestFakeMotionEvent (xDisplay, -1, event.x, event.y, 0);
3007                 } else {
3008                     int button = event.button;
3009                     switch (button) {
3010                         case 1:
3011                         case 2:
3012                         case 3: break;
3013                         case 4: button = 6; break;
3014                         case 5: button = 7; break;
3015                         default: return false;
3016                     }
3017                     OS.XTestFakeButtonEvent (xDisplay, button, type is SWT.MouseDown, 0);
3018                 }
3019                 return true;
3020         default:
3021             }
3022             /*
3023             * This code is intentionally commented. After posting a
3024             * mouse wheel event the system may respond unpredictably
3025             * to subsequent mouse actions.
3026             */
3027 //          case SWT.MouseWheel: {
3028 //              if (event.count is 0) return false;
3029 //              int button = event.count < 0 ? 5 : 4;
3030 //              OS.XTestFakeButtonEvent (xDisplay, button, type is SWT.MouseWheel, 0);
3031 //          }
3032         }
3033         return false;
3034     }
3035 }
3036 
3037 void postEvent (Event event) {
3038     /*
3039     * Place the event at the end of the event queue.
3040     * This code is always called in the Display's
3041     * thread so it must be re-enterant but does not
3042     * need to be synchronized.
3043     */
3044     if (eventQueue is null) eventQueue = new Event [4];
3045     ptrdiff_t index = 0;
3046     ptrdiff_t length = eventQueue.length;
3047     while (index < length) {
3048         if (eventQueue [index] is null) break;
3049         index++;
3050     }
3051     if (index is length) {
3052         Event [] newQueue = new Event [length + 4];
3053         System.arraycopy (eventQueue, 0, newQueue, 0, length);
3054         eventQueue = newQueue;
3055     }
3056     eventQueue [index] = event;
3057 }
3058 
3059 void putGdkEvents () {
3060     if (gdkEventCount !is 0) {
3061         for (int i = 0; i < gdkEventCount; i++) {
3062             auto event = gdkEvents [i];
3063             Widget widget = gdkEventWidgets [i];
3064             if (widget is null || !widget.isDisposed ()) {
3065                 OS.gdk_event_put (event);
3066             }
3067             OS.gdk_event_free (event);
3068             gdkEvents [i] = null;
3069             gdkEventWidgets [i] = null;
3070         }
3071         gdkEventCount = 0;
3072     }
3073 }
3074 
3075 /**
3076  * Reads an event from the operating system's event queue,
3077  * dispatches it appropriately, and returns <code>true</code>
3078  * if there is potentially more work to do, or <code>false</code>
3079  * if the caller can sleep until another event is placed on
3080  * the event queue.
3081  * <p>
3082  * In addition to checking the system event queue, this method also
3083  * checks if any inter-thread messages (created by <code>syncExec()</code>
3084  * or <code>asyncExec()</code>) are waiting to be processed, and if
3085  * so handles them before returning.
3086  * </p>
3087  *
3088  * @return <code>false</code> if the caller can sleep upon return from this method
3089  *
3090  * @exception SWTException <ul>
3091  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3092  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3093  *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
3094  * </ul>
3095  *
3096  * @see #sleep
3097  * @see #wake
3098  */
3099 public bool readAndDispatch () {
3100     checkDevice ();
3101     bool events = false;
3102     events |= runSettings ();
3103     events |= runPopups ();
3104     events |= cast(bool)OS.g_main_context_iteration (null, false);
3105     if (events) {
3106         runDeferredEvents ();
3107         return true;
3108     }
3109     return runAsyncMessages (false);
3110 }
3111 
3112 static void register (Display display) {
3113     synchronized (Device.classinfo) {
3114         for (int i=0; i<Displays.length; i++) {
3115             if (Displays [i] is null) {
3116                 Displays [i] = display;
3117                 return;
3118             }
3119         }
3120         Display [] newDisplays = new Display [Displays.length + 4];
3121         System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
3122         newDisplays [Displays.length] = display;
3123         Displays = newDisplays;
3124     }
3125 }
3126 
3127 /**
3128  * Releases any internal resources back to the operating
3129  * system and clears all fields except the device handle.
3130  * <p>
3131  * Disposes all shells which are currently open on the display.
3132  * After this method has been invoked, all related related shells
3133  * will answer <code>true</code> when sent the message
3134  * <code>isDisposed()</code>.
3135  * </p><p>
3136  * When a device is destroyed, resources that were acquired
3137  * on behalf of the programmer need to be returned to the
3138  * operating system.  For example, if the device allocated a
3139  * font to be used as the system font, this font would be
3140  * freed in <code>release</code>.  Also,to assist the garbage
3141  * collector and minimize the amount of memory that is not
3142  * reclaimed when the programmer keeps a reference to a
3143  * disposed device, all fields except the handle are zero'd.
3144  * The handle is needed by <code>destroy</code>.
3145  * </p>
3146  * This method is called before <code>destroy</code>.
3147  *
3148  * @see Device#dispose
3149  * @see #destroy
3150  */
3151 protected override void release () {
3152     sendEvent (SWT.Dispose, new Event ());
3153     Shell [] shells = getShells ();
3154     for (int i=0; i<shells.length; i++) {
3155         Shell shell = shells [i];
3156         if (!shell.isDisposed ())  shell.dispose ();
3157     }
3158     if (tray !is null) tray.dispose ();
3159     tray = null;
3160     while (readAndDispatch ()) {}
3161     if (disposeList !is null) {
3162         for (int i=0; i<disposeList.length; i++) {
3163             if (disposeList [i] !is null) disposeList [i].run ();
3164         }
3165     }
3166     disposeList = null;
3167     synchronizer.releaseSynchronizer ();
3168     synchronizer = null;
3169     releaseDisplay ();
3170     super.release ();
3171 }
3172 
3173 void releaseDisplay () {
3174 
3175     /* Dispose xfilter callback */
3176     OS.gdk_window_remove_filter(null, &filterProcFunc, null);
3177 
3178     /* Dispose checkIfEvent callback */
3179 
3180     /* Dispose preedit window */
3181     if (preeditWindow !is null) OS.gtk_widget_destroy ( &preeditWindow.bin.container.widget);
3182     imControl = null;
3183 
3184     /* Dispose the menu callback */
3185 
3186     /* Dispose the tooltip map callback */
3187 
3188     /* Dispose the shell map callback */
3189 
3190     /* Dispose the run async messages callback */
3191     if (idleHandle !is 0) OS.g_source_remove (idleHandle);
3192     idleHandle = 0;
3193 
3194     /* Dispose GtkTreeView callbacks */
3195 
3196     /* Dispose the set direction callback */
3197 
3198     /* Dispose the emission proc callback */
3199 
3200     /* Dispose the set direction callback */
3201 
3202     /* Dispose the caret callback */
3203     if (caretId !is 0) OS.gtk_timeout_remove (caretId);
3204     caretId = 0;
3205 
3206     /* Release closures */
3207     for (int i = 0; i < Widget.LAST_SIGNAL; i++) {
3208         if (closures [i] !is null) OS.g_closure_unref (closures [i]);
3209     }
3210     if (shellMapProcClosure !is null) OS.g_closure_unref (shellMapProcClosure);
3211 
3212     /* Dispose the timer callback */
3213     if (timerIds !is null) {
3214         for (int i=0; i<timerIds.length; i++) {
3215             if (timerIds [i] !is 0) OS.gtk_timeout_remove (timerIds [i]);
3216         }
3217     }
3218     timerIds = null;
3219     timerList = null;
3220 
3221     /* Dispose mouse hover callback */
3222     if (mouseHoverId !is 0) OS.gtk_timeout_remove (mouseHoverId);
3223     mouseHoverId = 0;
3224     mouseHoverHandle = null;
3225 
3226     /* Dispose the default font */
3227     if (systemFont !is null) systemFont.dispose ();
3228     systemFont = null;
3229 
3230     /* Dispose the System Images */
3231     if (errorImage !is null) errorImage.dispose();
3232     if (infoImage !is null) infoImage.dispose();
3233     if (questionImage !is null) questionImage.dispose();
3234     if (warningImage !is null) warningImage.dispose();
3235     errorImage = infoImage = questionImage = warningImage = null;
3236 
3237     /* Release the System Cursors */
3238     for (int i = 0; i < cursors.length; i++) {
3239         if (cursors [i] !is null) cursors [i].dispose ();
3240     }
3241     cursors = null;
3242 
3243     /* Release Acquired Resources */
3244     if (resources !is null) {
3245         for (int i=0; i<resources.length; i++) {
3246             if (resources [i] !is null) resources [i].dispose ();
3247         }
3248         resources = null;
3249     }
3250 
3251     /* Release the System Colors */
3252     COLOR_WIDGET_DARK_SHADOW = COLOR_WIDGET_NORMAL_SHADOW = COLOR_WIDGET_LIGHT_SHADOW =
3253     COLOR_WIDGET_HIGHLIGHT_SHADOW = COLOR_WIDGET_BACKGROUND = COLOR_WIDGET_BORDER =
3254     COLOR_LIST_FOREGROUND = COLOR_LIST_BACKGROUND = COLOR_LIST_SELECTION = COLOR_LIST_SELECTION_TEXT =
3255     COLOR_WIDGET_FOREGROUND = COLOR_TITLE_FOREGROUND = COLOR_TITLE_BACKGROUND = COLOR_TITLE_BACKGROUND_GRADIENT =
3256     COLOR_TITLE_INACTIVE_FOREGROUND = COLOR_TITLE_INACTIVE_BACKGROUND = COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT =
3257     COLOR_INFO_BACKGROUND = COLOR_INFO_FOREGROUND = null;
3258 
3259     /* Dispose the event callback */
3260     OS.gdk_event_handler_set (null, null, null);
3261 
3262     /* Dispose the hidden shell */
3263     if (shellHandle !is null) OS.gtk_widget_destroy (shellHandle);
3264     shellHandle = null;
3265 
3266     /* Dispose the settings callback */
3267 
3268     /* Release the sleep resources */
3269     max_priority = 0;
3270     timeout = 0;
3271     if (fds !is null) OS.g_free (fds.ptr);
3272     fds = null;
3273 
3274     /* Release references */
3275     popups = null;
3276     thread = null;
3277     lastWidget = activeShell = null;
3278     //flushData = null;
3279     closures = null;
3280     indexTable = null;
3281     signalIds = null;
3282     treeSelection = null;
3283     widgetTable = null;
3284     modalShells = null;
3285     data = null;
3286     values = null;
3287     keys = null;
3288     windowManager = null;
3289     eventTable = filterTable = null;
3290     modalDialog = null;
3291     flushRect = null;
3292     exposeEvent = null;
3293     visibilityEvent = null;
3294     idleLock = null;
3295 }
3296 
3297 /**
3298  * Removes the listener from the collection of listeners who will
3299  * be notified when an event of the given type occurs anywhere in
3300  * a widget. The event type is one of the event constants defined
3301  * in class <code>SWT</code>.
3302  *
3303  * @param eventType the type of event to listen for
3304  * @param listener the listener which should no longer be notified when the event occurs
3305  *
3306  * @exception IllegalArgumentException <ul>
3307  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3308  * </ul>
3309  * @exception SWTException <ul>
3310  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3311  * </ul>
3312  *
3313  * @see Listener
3314  * @see SWT
3315  * @see #addFilter
3316  * @see #addListener
3317  *
3318  * @since 3.0
3319  */
3320 public void removeFilter (int eventType, Listener listener) {
3321     checkDevice ();
3322     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
3323     if (filterTable is null) return;
3324     filterTable.unhook (eventType, listener);
3325     if (filterTable.size () is 0) filterTable = null;
3326 }
3327 
3328 GdkEvent* removeGdkEvent () {
3329     if (gdkEventCount is 0) return null;
3330     auto event = gdkEvents [0];
3331     --gdkEventCount;
3332     SimpleType!(GdkEvent*).arraycopy (gdkEvents, 1, gdkEvents, 0, gdkEventCount);
3333     System.arraycopy (gdkEventWidgets, 1, gdkEventWidgets, 0, gdkEventCount);
3334     gdkEvents [gdkEventCount] = null;
3335     gdkEventWidgets [gdkEventCount] = null;
3336     if (gdkEventCount is 0) {
3337         gdkEvents = null;
3338         gdkEventWidgets = null;
3339     }
3340     return event;
3341 }
3342 
3343 void removeIdleProc () {
3344     synchronized (idleLock) {
3345         if (idleHandle !is 0) OS.g_source_remove (idleHandle);
3346         idleNeeded = false;
3347         idleHandle = 0;
3348     }
3349 }
3350 /**
3351  * Removes the listener from the collection of listeners who will
3352  * be notified when an event of the given type occurs. The event type
3353  * is one of the event constants defined in class <code>SWT</code>.
3354  *
3355  * @param eventType the type of event to listen for
3356  * @param listener the listener which should no longer be notified
3357  *
3358  * @exception IllegalArgumentException <ul>
3359  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3360  * </ul>
3361  * @exception SWTException <ul>
3362  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3363  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3364  * </ul>
3365  *
3366  * @see Listener
3367  * @see SWT
3368  * @see #addListener
3369  *
3370  * @since 2.0
3371  */
3372 public void removeListener (int eventType, Listener listener) {
3373     checkDevice ();
3374     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
3375     if (eventTable is null) return;
3376     eventTable.unhook (eventType, listener);
3377 }
3378 
3379 void removeMouseHoverTimeout (void* handle) {
3380     if (handle !is mouseHoverHandle) return;
3381     if (mouseHoverId !is 0) OS.gtk_timeout_remove (mouseHoverId);
3382     mouseHoverId = 0;
3383     mouseHoverHandle = null;
3384 }
3385 
3386 void removePopup (Menu menu) {
3387     if (popups is null) return;
3388     for (int i=0; i<popups.length; i++) {
3389         if (popups [i] is menu) {
3390             popups [i] = null;
3391             return;
3392         }
3393     }
3394 }
3395 
3396 Widget removeWidget (GtkWidget* handle) {
3397     if (handle is null) return null;
3398     lastWidget = null;
3399     Widget widget = null;
3400     auto index = cast(ptrdiff_t)OS.g_object_get_qdata (cast(GObject*)handle, SWT_OBJECT_INDEX) - 1;
3401     if (0 <= index && index < widgetTable.length) {
3402         widget = widgetTable [index];
3403         widgetTable [index] = null;
3404         indexTable [index] = freeSlot;
3405         freeSlot = index;
3406         OS.g_object_set_qdata (cast(GObject*)handle, SWT_OBJECT_INDEX, null);
3407     }
3408     return widget;
3409 }
3410 
3411 bool runAsyncMessages (bool all) {
3412     return synchronizer.runAsyncMessages (all);
3413 }
3414 
3415 bool runDeferredEvents () {
3416     /*
3417     * Run deferred events.  This code is always
3418     * called in the Display's thread so it must
3419     * be re-enterant but need not be synchronized.
3420     */
3421     while (eventQueue !is null) {
3422 
3423         /* Take an event off the queue */
3424         Event event = eventQueue [0];
3425         if (event is null) break;
3426         ptrdiff_t len = eventQueue.length;
3427         System.arraycopy (eventQueue, 1, eventQueue, 0, --len);
3428         eventQueue [len] = null;
3429 
3430         /* Run the event */
3431         Widget widget = event.widget;
3432         if (widget !is null && !widget.isDisposed ()) {
3433             Widget item = event.item;
3434             if (item is null || !item.isDisposed ()) {
3435                 widget.sendEvent (event);
3436             }
3437         }
3438 
3439         /*
3440         * At this point, the event queue could
3441         * be null due to a recursive invokation
3442         * when running the event.
3443         */
3444     }
3445 
3446     /* Clear the queue */
3447     eventQueue = null;
3448     return true;
3449 }
3450 
3451 bool runPopups () {
3452     if (popups is null) return false;
3453     bool result = false;
3454     while (popups !is null) {
3455         Menu menu = popups [0];
3456         if (menu is null) break;
3457         ptrdiff_t len = popups.length;
3458         System.arraycopy (popups, 1, popups, 0, --len);
3459         popups [len] = null;
3460         runDeferredEvents ();
3461         if (!menu.isDisposed ()) menu._setVisible (true);
3462         result = true;
3463     }
3464     popups = null;
3465     return result;
3466 }
3467 
3468 bool runSettings () {
3469     if (!runSettingsFld) return false;
3470     runSettingsFld = false;
3471     saveResources ();
3472     initializeSystemColors ();
3473     sendEvent (SWT.Settings, null);
3474     Shell [] shells = getShells ();
3475     for (int i=0; i<shells.length; i++) {
3476         Shell shell = shells [i];
3477         if (!shell.isDisposed ()) {
3478             shell.fixStyle ();
3479             shell.redraw (true);
3480             shell.layout (true, true);
3481         }
3482     }
3483     return true;
3484 }
3485 
3486 /**
3487  * On platforms which support it, sets the application name
3488  * to be the argument. On Motif, for example, this can be used
3489  * to set the name used for resource lookup.  Specifying
3490  * <code>null</code> for the name clears it.
3491  *
3492  * @param name the new app name or <code>null</code>
3493  */
3494 public static void setAppName (String name) {
3495     APP_NAME = name;
3496 }
3497 
3498 /**
3499  * Sets the location of the on-screen pointer relative to the top left corner
3500  * of the screen.  <b>Note: It is typically considered bad practice for a
3501  * program to move the on-screen pointer location.</b>
3502  *
3503  * @param x the new x coordinate for the cursor
3504  * @param y the new y coordinate for the cursor
3505  *
3506  * @exception SWTException <ul>
3507  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3508  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3509  * </ul>
3510  *
3511  * @since 2.1
3512  */
3513 public void setCursorLocation (int x, int y) {
3514     checkDevice ();
3515     if (OS.GDK_WINDOWING_X11 ()) {
3516         auto xDisplay = OS.GDK_DISPLAY ();
3517         auto xWindow = OS.XDefaultRootWindow (xDisplay);
3518         OS.XWarpPointer (xDisplay, OS.None, xWindow, 0, 0, 0, 0, x, y);
3519     }
3520 }
3521 
3522 /**
3523  * Sets the location of the on-screen pointer relative to the top left corner
3524  * of the screen.  <b>Note: It is typically considered bad practice for a
3525  * program to move the on-screen pointer location.</b>
3526  *
3527  * @param point new position
3528  *
3529  * @exception SWTException <ul>
3530  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3531  *    <li>ERROR_NULL_ARGUMENT - if the point is null
3532  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3533  * </ul>
3534  *
3535  * @since 2.0
3536  */
3537 public void setCursorLocation (Point point) {
3538     checkDevice ();
3539     if (point is null) error (SWT.ERROR_NULL_ARGUMENT);
3540     setCursorLocation (point.x, point.y);
3541 }
3542 
3543 /**
3544  * Sets the application defined property of the receiver
3545  * with the specified name to the given argument.
3546  * <p>
3547  * Applications may have associated arbitrary objects with the
3548  * receiver in this fashion. If the objects stored in the
3549  * properties need to be notified when the display is disposed
3550  * of, it is the application's responsibility provide a
3551  * <code>disposeExec()</code> handler which does so.
3552  * </p>
3553  *
3554  * @param key the name of the property
3555  * @param value the new value for the property
3556  *
3557  * @exception SWTException <ul>
3558  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3559  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3560  * </ul>
3561  *
3562  * @see #getData(String)
3563  * @see #disposeExec(Runnable)
3564  */
3565 public void setData (String key, Object value) {
3566     checkDevice ();
3567     // SWT extension: allow null for zero length string
3568     //if (key is null) error (SWT.ERROR_NULL_ARGUMENT);
3569 
3570     if (key.equals (DISPATCH_EVENT_KEY)) {
3571         ArrayWrapperInt wrappedValue;
3572         if (value is null || (null !is (wrappedValue=cast(ArrayWrapperInt)value))) {
3573             if (wrappedValue is null) {
3574                 dispatchEvents = [];
3575             } else {
3576                 dispatchEvents = wrappedValue.array;
3577             }
3578             if (value is null) putGdkEvents ();
3579             return;
3580         }
3581     }
3582     if (key.equals (SET_MODAL_DIALOG)) {
3583         setModalDialog (cast(Dialog) data);
3584         return;
3585     }
3586 
3587     if (key.equals (ADD_WIDGET_KEY)) {
3588         auto wrap = cast(ArrayWrapperObject) value;
3589         if( wrap is null ) SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " []");
3590         Object [] data = wrap.array;
3591         auto handle = (cast(LONG) data [0]).intValue;
3592         Widget widget = cast(Widget) data [1];
3593         if (widget !is null) {
3594             addWidget (cast(GtkWidget*)handle, widget);
3595         } else {
3596             removeWidget (cast(GtkWidget*)handle);
3597         }
3598     }
3599 
3600     if (key==/*eq*/ ADD_IDLE_PROC_KEY) {
3601         addIdleProc ();
3602         return;
3603     }
3604     if (key==/*eq*/ REMOVE_IDLE_PROC_KEY) {
3605         removeIdleProc ();
3606         return;
3607     }
3608 
3609     /* Remove the key/value pair */
3610     if (value is null) {
3611         if (keys is null) return;
3612         int index = 0;
3613         while (index < keys.length && keys [index]!=/*!eq*/ key) index++;
3614         if (index is keys.length) return;
3615         if (keys.length is 1) {
3616             keys = null;
3617             values = null;
3618         } else {
3619             String [] newKeys = new String [keys.length - 1];
3620             Object [] newValues = new Object [values.length - 1];
3621             System.arraycopy (keys, 0, newKeys, 0, index);
3622             System.arraycopy (keys, index + 1, newKeys, index, newKeys.length - index);
3623             System.arraycopy (values, 0, newValues, 0, index);
3624             System.arraycopy (values, index + 1, newValues, index, newValues.length - index);
3625             keys = newKeys;
3626             values = newValues;
3627         }
3628         return;
3629     }
3630 
3631     /* Add the key/value pair */
3632     if (keys is null) {
3633         keys = [key];
3634         values = [value];
3635         return;
3636     }
3637     for (int i=0; i<keys.length; i++) {
3638         if (keys [i]==/*eq*/ key) {
3639             values [i] = value;
3640             return;
3641         }
3642     }
3643     String [] newKeys = new String [keys.length + 1];
3644     Object [] newValues = new Object [values.length + 1];
3645     System.arraycopy (keys, 0, newKeys, 0, keys.length);
3646     System.arraycopy (values, 0, newValues, 0, values.length);
3647     newKeys [keys.length] = key;
3648     newValues [values.length] = value;
3649     keys = newKeys;
3650     values = newValues;
3651 }
3652 
3653 /**
3654  * Sets the application defined, display specific data
3655  * associated with the receiver, to the argument.
3656  * The <em>display specific data</em> is a single,
3657  * unnamed field that is stored with every display.
3658  * <p>
3659  * Applications may put arbitrary objects in this field. If
3660  * the object stored in the display specific data needs to
3661  * be notified when the display is disposed of, it is the
3662  * application's responsibility provide a
3663  * <code>disposeExec()</code> handler which does so.
3664  * </p>
3665  *
3666  * @param data the new display specific data
3667  *
3668  * @exception SWTException <ul>
3669  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3670  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3671  * </ul>
3672  *
3673  * @see #getData()
3674  * @see #disposeExec(Runnable)
3675  */
3676 public void setData (Object data) {
3677     checkDevice ();
3678     this.data = data;
3679 }
3680 
3681 
3682 void doSetDirectionProc( GtkWidget* widget, int direction ){
3683     setDirectionProcCallbackData.display = this;
3684     setDirectionProcCallbackData.data = cast(void*)direction;
3685     OS.gtk_container_forall (cast(GtkContainer*)widget, cast(GtkCallback)&setDirectionProcFunc, &setDirectionProcCallbackData);
3686 }
3687 
3688 package static extern(C) ptrdiff_t setDirectionProcFunc (GtkWidget* widget, void* data) {
3689     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3690     CallbackData* cbdata = cast(CallbackData*)data;
3691     return cbdata.display.setDirectionProc( widget, cast(int)cbdata.data );
3692 }
3693 ptrdiff_t setDirectionProc (GtkWidget* widget, int direction) {
3694     OS.gtk_widget_set_direction (widget,  direction);
3695     if (OS.GTK_IS_MENU_ITEM (widget)) {
3696         auto submenu = OS.gtk_menu_item_get_submenu (widget);
3697         if (submenu !is null) {
3698             OS.gtk_widget_set_direction (submenu, direction);
3699             OS.gtk_container_forall (cast(GtkContainer*)submenu, cast(GtkCallback)&setDirectionProcFunc, cast(void*)direction);
3700         }
3701     }
3702     if (OS.GTK_IS_CONTAINER (cast(GTypeInstance*)widget)) {
3703         OS.gtk_container_forall (cast(GtkContainer*)widget, cast(GtkCallback)&setDirectionProcFunc, cast(void*)direction);
3704     }
3705     return 0;
3706 }
3707 
3708 void setModalDialog (Dialog modalDailog) {
3709     this.modalDialog = modalDailog;
3710     Shell [] shells = getShells ();
3711     for (int i=0; i<shells.length; i++) shells [i].updateModal ();
3712 }
3713 
3714 void setModalShell (Shell shell) {
3715     if (modalShells is null) modalShells = new Shell [4];
3716     ptrdiff_t index = 0, length = modalShells.length;
3717     while (index < length) {
3718         if (modalShells [index] is shell) return;
3719         if (modalShells [index] is null) break;
3720         index++;
3721     }
3722     if (index is length) {
3723         Shell [] newModalShells = new Shell [length + 4];
3724         System.arraycopy (modalShells, 0, newModalShells, 0, length);
3725         modalShells = newModalShells;
3726     }
3727     modalShells [index] = shell;
3728     Shell [] shells = getShells ();
3729     for (int i=0; i<shells.length; i++) shells [i].updateModal ();
3730 }
3731 
3732 /**
3733  * Sets the synchronizer used by the display to be
3734  * the argument, which can not be null.
3735  *
3736  * @param synchronizer the new synchronizer for the display (must not be null)
3737  *
3738  * @exception IllegalArgumentException <ul>
3739  *    <li>ERROR_NULL_ARGUMENT - if the synchronizer is null</li>
3740  * </ul>
3741  * @exception SWTException <ul>
3742  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3743  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3744  *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
3745  * </ul>
3746  */
3747 public void setSynchronizer (Synchronizer synchronizer) {
3748     checkDevice ();
3749     if (synchronizer is null) error (SWT.ERROR_NULL_ARGUMENT);
3750     if (synchronizer is this.synchronizer) return;
3751     Synchronizer oldSynchronizer;
3752     synchronized (Device.classinfo) {
3753         oldSynchronizer = this.synchronizer;
3754         this.synchronizer = synchronizer;
3755     }
3756     if (oldSynchronizer !is null) {
3757         oldSynchronizer.runAsyncMessages(true);
3758     }
3759 }
3760 
3761 void showIMWindow (Control control) {
3762     imControl = control;
3763     if (preeditWindow is null) {
3764         preeditWindow = cast(GtkWindow*)OS.gtk_window_new (OS.GTK_WINDOW_POPUP);
3765         if (preeditWindow is null) error (SWT.ERROR_NO_HANDLES);
3766         preeditLabel = cast(GtkLabel*) OS.gtk_label_new (null);
3767         if (preeditLabel is null) error (SWT.ERROR_NO_HANDLES);
3768         OS.gtk_container_add (cast(GtkContainer*)preeditWindow, cast(GtkWidget*) preeditLabel);
3769         OS.gtk_widget_show (cast(GtkWidget*)preeditLabel);
3770     }
3771     char* preeditString;
3772     PangoAttrList* pangoAttrs;
3773     auto imHandle = control.imHandle ();
3774     OS.gtk_im_context_get_preedit_string (imHandle, &preeditString, &pangoAttrs, null);
3775     if (preeditString !is null && OS.strlen (preeditString) > 0) {
3776         Control widget = control.findBackgroundControl ();
3777         if (widget is null) widget = control;
3778         OS.gtk_widget_modify_bg (cast(GtkWidget*)preeditWindow, OS.GTK_STATE_NORMAL, widget.getBackgroundColor ());
3779         widget.setForegroundColor (cast(GtkWidget*)preeditLabel, control.getForegroundColor());
3780         OS.gtk_widget_modify_font (cast(GtkWidget*)preeditLabel, control.getFontDescription ());
3781         if (pangoAttrs !is null) OS.gtk_label_set_attributes (preeditLabel, pangoAttrs);
3782         OS.gtk_label_set_text (preeditLabel, preeditString);
3783         Point point = control.toDisplay (control.getIMCaretPos ());
3784         OS.gtk_window_move (preeditWindow, point.x, point.y);
3785         GtkRequisition requisition;
3786         OS.gtk_widget_size_request (cast(GtkWidget*)preeditLabel, &requisition);
3787         OS.gtk_window_resize (preeditWindow, requisition.width, requisition.height);
3788         OS.gtk_widget_show (cast(GtkWidget*)preeditWindow);
3789     } else {
3790         OS.gtk_widget_hide (cast(GtkWidget*)preeditWindow);
3791     }
3792     if (preeditString !is null) OS.g_free (preeditString);
3793     if (pangoAttrs !is null) OS.pango_attr_list_unref (pangoAttrs);
3794 }
3795 
3796 /**
3797  * Causes the user-interface thread to <em>sleep</em> (that is,
3798  * to be put in a state where it does not consume CPU cycles)
3799  * until an event is received or it is otherwise awakened.
3800  *
3801  * @return <code>true</code> if an event requiring dispatching was placed on the queue.
3802  *
3803  * @exception SWTException <ul>
3804  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3805  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3806  * </ul>
3807  *
3808  * @see #wake
3809  */
3810 public bool sleep () {
3811     checkDevice ();
3812     if (gdkEventCount is 0) {
3813         gdkEvents = null;
3814         gdkEventWidgets = null;
3815     }
3816     if (settingsChanged) {
3817         settingsChanged = false;
3818         runSettingsFld = true;
3819         return false;
3820     }
3821     if (getMessageCount () !is 0) return true;
3822     if (fds is null) {
3823         allocated_nfds = 2;
3824         GPollFD* ptr = cast(GPollFD*) OS.g_malloc( GPollFD.sizeof * allocated_nfds );
3825         fds = ptr[ 0 .. allocated_nfds ];
3826     }
3827     max_priority = timeout = 0;
3828     auto context = OS.g_main_context_default ();
3829     bool result = false;
3830     do {
3831         if (OS.g_main_context_acquire (context)) {
3832             result = cast(bool)OS.g_main_context_prepare (context, &max_priority);
3833             int nfds;
3834             while ((nfds = OS.g_main_context_query (context, max_priority, &timeout, fds.ptr, allocated_nfds)) > allocated_nfds) {
3835                 OS.g_free (fds.ptr);
3836                 allocated_nfds = nfds;
3837                 GPollFD* ptr = cast(GPollFD*) OS.g_malloc( GPollFD.sizeof * allocated_nfds );
3838                 fds = ptr[ 0 .. allocated_nfds ];
3839             }
3840             GPollFunc poll = OS.g_main_context_get_poll_func (context);
3841             if (poll !is null) {
3842                 if (nfds > 0 || timeout !is 0) {
3843                     /*
3844                     * Bug in GTK. For some reason, g_main_context_wakeup() may
3845                     * fail to wake up the UI thread from the polling function.
3846                     * The fix is to sleep for a maximum of 50 milliseconds.
3847                     */
3848                     if (timeout < 0) timeout = 50;
3849 
3850                     /* Exit the OS lock to allow other threads to enter GTK */
3851                     Lock lock = OS.lock;
3852                     int count = lock.lock ();
3853                     for (int i = 0; i < count; i++) lock.unlock ();
3854                     try {
3855                         wake_state = false;
3856                         poll( fds.ptr, nfds, timeout);
3857                     } finally {
3858                         for (int i = 0; i < count; i++) lock.lock ();
3859                         lock.unlock ();
3860                     }
3861                 }
3862             }
3863             OS.g_main_context_check (context, max_priority, fds.ptr, nfds);
3864             OS.g_main_context_release (context);
3865         }
3866     } while (!result && getMessageCount () is 0 && !wake_state);
3867     wake_state = false;
3868     return true;
3869 }
3870 
3871 /**
3872  * Causes the <code>run()</code> method of the runnable to
3873  * be invoked by the user-interface thread after the specified
3874  * number of milliseconds have elapsed. If milliseconds is less
3875  * than zero, the runnable is not executed.
3876  * <p>
3877  * Note that at the time the runnable is invoked, widgets
3878  * that have the receiver as their display may have been
3879  * disposed. Therefore, it is necessary to check for this
3880  * case inside the runnable before accessing the widget.
3881  * </p>
3882  *
3883  * @param milliseconds the delay before running the runnable
3884  * @param runnable code to run on the user-interface thread
3885  *
3886  * @exception IllegalArgumentException <ul>
3887  *    <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
3888  * </ul>
3889  * @exception SWTException <ul>
3890  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3891  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
3892  * </ul>
3893  *
3894  * @see #asyncExec
3895  */
3896 public void timerExec (int milliseconds, Runnable runnable) {
3897     checkDevice ();
3898     if (runnable is null) error (SWT.ERROR_NULL_ARGUMENT);
3899     if (timerList is null) timerList = new Runnable [4];
3900     if (timerIds is null) timerIds = new int [4];
3901     int index = 0;
3902     while (index < timerList.length) {
3903         if (timerList [index] is runnable) break;
3904         index++;
3905     }
3906     if (index !is timerList.length) {
3907         OS.gtk_timeout_remove (timerIds [index]);
3908         timerList [index] = null;
3909         timerIds [index] = 0;
3910         if (milliseconds < 0) return;
3911     } else {
3912         if (milliseconds < 0) return;
3913         index = 0;
3914         while (index < timerList.length) {
3915             if (timerList [index] is null) break;
3916             index++;
3917         }
3918         if (index is timerList.length) {
3919             Runnable [] newTimerList = new Runnable [timerList.length + 4];
3920             SimpleType!(Runnable).arraycopy (timerList, 0, newTimerList, 0, timerList.length);
3921             timerList = newTimerList;
3922             int [] newTimerIds = new int [timerIds.length + 4];
3923             System.arraycopy (timerIds, 0, newTimerIds, 0, timerIds.length);
3924             timerIds = newTimerIds;
3925         }
3926     }
3927     timerProcCallbackData.display = this;
3928     timerProcCallbackData.data = cast(void*)index;
3929     int timerId = OS.gtk_timeout_add (milliseconds, &timerProcFunc, &timerProcCallbackData);
3930     if (timerId !is 0) {
3931         timerIds [index] = timerId;
3932         timerList [index] = runnable;
3933     }
3934 }
3935 
3936 
3937 private static extern(C) int timerProcFunc ( void * data ) {
3938     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3939     CallbackData* cbdata = cast( CallbackData* ) data;
3940     return cbdata.display.timerProc( cast(int) cbdata.data );
3941 }
3942 
3943 int timerProc (int i) {
3944     if (timerList is null) return 0;
3945     int index = i;
3946     if (0 <= index && index < timerList.length) {
3947         Runnable runnable = timerList [index];
3948         timerList [index] = null;
3949         timerIds [index] = 0;
3950         if (runnable !is null) runnable.run ();
3951     }
3952     return 0;
3953 }
3954 
3955 private static extern(C) int caretProcFunc ( void * data ) {
3956     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3957     CallbackData* cbdata = cast( CallbackData* ) data;
3958     return cbdata.display.caretProc( cast(int) cbdata.data );
3959 }
3960 int caretProc (ptrdiff_t clientData) {
3961     caretId = 0;
3962     if (currentCaret is null) {
3963         return 0;
3964     }
3965     if (currentCaret.blinkCaret()) {
3966         int blinkRate = currentCaret.blinkRate;
3967         if (blinkRate is 0) return 0;
3968         caretProcCallbackData.display = this;
3969         caretProcCallbackData.data = cast(void*)0;
3970         caretId = OS.gtk_timeout_add (blinkRate, &caretProcFunc, &caretProcCallbackData);
3971     } else {
3972         currentCaret = null;
3973     }
3974     return 0;
3975 }
3976 
3977 
3978 package ptrdiff_t doSizeAllocateConnect( CallbackData* cbdata, GtkWidget* window, GtkWidget* widget ){
3979     cbdata.display = this;
3980     cbdata.data = cast(void*)widget;
3981     return OS.g_signal_connect (cast(void*)window, OS.size_allocate.ptr, cast(GCallback)&sizeAllocateProcFunc, cast(void*)&cbdata);
3982 }
3983 
3984 private static extern(C) void sizeAllocateProcFunc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
3985     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
3986     auto cbdata = cast(CallbackData*)user_data;
3987     cbdata.display.sizeAllocateProc( cast(GtkWidget*)handle, arg0, cast(int)cbdata.data );
3988 }
3989 
3990 void sizeAllocateProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
3991     Widget widget = getWidget ( cast(GtkWidget*)user_data);
3992     if (widget is null) return;
3993     widget.sizeAllocateProc (handle, arg0, user_data);
3994 }
3995 
3996 
3997 package ptrdiff_t doSizeRequestConnect( CallbackData* cbdata, GtkWidget* window, GtkWidget* widget ){
3998     cbdata.display = this;
3999     cbdata.data = cast(void*)widget;
4000     return OS.g_signal_connect (cast(void*)window, OS.size_request.ptr, cast(GCallback)&sizeRequestProcFunc, cast(void*)&cbdata );
4001 }
4002 
4003 private static extern(C) void  sizeRequestProcFunc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4004     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4005     auto cbdata = cast(CallbackData*)user_data;
4006     cbdata.display.sizeRequestProcMeth( cast(GtkWidget*)handle, arg0, cast(int)cbdata.data );
4007 }
4008 
4009 ptrdiff_t sizeRequestProcMeth (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4010     Widget widget = getWidget (cast(GtkWidget*)user_data);
4011     if (widget is null) return 0;
4012     return widget.sizeRequestProc (handle, arg0, user_data);
4013 }
4014 
4015 package void doTreeSelectionProcConnect( CallbackData* cbdata, GtkWidget* widget, GtkTreeSelection* selection ){
4016     cbdata.display = this;
4017     cbdata.data = cast(void*)widget;
4018     OS.gtk_tree_selection_selected_foreach (selection, &treeSelectionProcFunc, widget);
4019 }
4020 
4021 private static extern(C) void  treeSelectionProcFunc (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void* data) {
4022     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4023     auto cbdata = cast(CallbackData*)data;
4024     cbdata.display.treeSelectionProcMeth( model, path, iter, cbdata.data );
4025 }
4026 
4027 void treeSelectionProcMeth (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void* data) {
4028     Widget widget = getWidget (cast(GtkWidget*)data);
4029     if (widget is null) return;
4030     widget.treeSelectionProc (model, path, iter, treeSelection, treeSelectionLength++);
4031 }
4032 
4033 void saveResources () {
4034     ptrdiff_t resourceCount = 0;
4035     if (resources is null) {
4036         resources = new Resource [RESOURCE_SIZE];
4037     } else {
4038         resourceCount = resources.length;
4039         Resource [] newResources = new Resource [resourceCount + RESOURCE_SIZE];
4040         System.arraycopy (resources, 0, newResources, 0, resourceCount);
4041         resources = newResources;
4042     }
4043     if (systemFont !is null) {
4044         resources [resourceCount++] = systemFont;
4045         systemFont = null;
4046     }
4047     if (errorImage !is null) resources [resourceCount++] = errorImage;
4048     if (infoImage !is null) resources [resourceCount++] = infoImage;
4049     if (questionImage !is null) resources [resourceCount++] = questionImage;
4050     if (warningImage !is null) resources [resourceCount++] = warningImage;
4051     errorImage = infoImage = questionImage = warningImage = null;
4052     for (int i=0; i<cursors.length; i++) {
4053         if (cursors [i] !is null) resources [resourceCount++] = cursors [i];
4054         cursors [i] = null;
4055     }
4056     if (resourceCount < RESOURCE_SIZE) {
4057         Resource [] newResources = new Resource [resourceCount];
4058         System.arraycopy (resources, 0, newResources, 0, resourceCount);
4059         resources = newResources;
4060     }
4061 }
4062 
4063 void sendEvent (int eventType, Event event) {
4064     if (eventTable is null && filterTable is null) {
4065         return;
4066     }
4067     if (event is null) event = new Event ();
4068     event.display = this;
4069     event.type = eventType;
4070     if (event.time is 0) event.time = getLastEventTime ();
4071     if (!filterEvent (event)) {
4072         if (eventTable !is null) eventTable.sendEvent (event);
4073     }
4074 }
4075 
4076 void setCurrentCaret (Caret caret) {
4077     if (caretId !is 0) OS.gtk_timeout_remove(caretId);
4078     caretId = 0;
4079     currentCaret = caret;
4080     if (caret is null) return;
4081     int blinkRate = currentCaret.blinkRate;
4082     caretProcCallbackData.display = this;
4083     caretProcCallbackData.data = cast(void*)0;
4084     caretId = OS.gtk_timeout_add (blinkRate, &caretProcFunc, &caretProcCallbackData);
4085 }
4086 
4087 private static extern(C) int shellMapProcFunc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4088     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4089     auto cbdata = cast(CallbackData*)user_data;
4090     return cbdata.display.shellMapProc( cast(GtkWidget*)handle, arg0, cast(int)cbdata.data );
4091 }
4092 
4093 int shellMapProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4094     Widget widget = getWidget (cast(GtkWidget*)handle);
4095     if (widget is null) return 0;
4096     return widget.shellMapProc (handle, arg0, user_data);
4097 }
4098 
4099 private static extern(C) int styleSetProcFunc (ptrdiff_t gobject, ptrdiff_t arg1, ptrdiff_t user_data) {
4100     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4101     auto cbdata = cast(CallbackData*)user_data;
4102     return cbdata.display.styleSetProcMeth( gobject, arg1, cast(int)cbdata.data );
4103 }
4104 int styleSetProcMeth (ptrdiff_t gobject, ptrdiff_t arg1, ptrdiff_t user_data) {
4105     settingsChanged = true;
4106     return 0;
4107 }
4108 
4109 /**
4110  * Causes the <code>run()</code> method of the runnable to
4111  * be invoked by the user-interface thread at the next
4112  * reasonable opportunity. The thread which calls this method
4113  * is suspended until the runnable completes.  Specifying <code>null</code>
4114  * as the runnable simply wakes the user-interface thread.
4115  * <p>
4116  * Note that at the time the runnable is invoked, widgets
4117  * that have the receiver as their display may have been
4118  * disposed. Therefore, it is necessary to check for this
4119  * case inside the runnable before accessing the widget.
4120  * </p>
4121  *
4122  * @param runnable code to run on the user-interface thread or <code>null</code>
4123  *
4124  * @exception SWTException <ul>
4125  *    <li>ERROR_FAILED_EXEC - if an exception occurred when executing the runnable</li>
4126  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4127  * </ul>
4128  *
4129  * @see #asyncExec
4130  */
4131 public void syncExec (Runnable runnable) {
4132     Synchronizer synchronizer;
4133     synchronized (Device.classinfo) {
4134         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
4135         synchronizer = this.synchronizer;
4136         synchronized (idleLock) {
4137             if (idleNeeded && idleHandle is 0) {
4138                 //NOTE: calling unlocked function in OS
4139             idleProcCallbackData.display = this;
4140             idleProcCallbackData.data = cast(void*)0;
4141             //PORTING_TODO: was _g_idle_add, calling directly
4142             idleHandle = OS.g_idle_add (&idleProcFunc, &idleProcCallbackData);
4143             }
4144         }
4145     }
4146     synchronizer.syncExec (runnable);
4147 }
4148 
4149 static int translateKey (int key) {
4150     for (int i=0; i<KeyTable.length; i++) {
4151         if (KeyTable [i] [0] is key) return KeyTable [i] [1];
4152     }
4153     return 0;
4154 }
4155 
4156 static int untranslateKey (int key) {
4157     for (int i=0; i<KeyTable.length; i++) {
4158         if (KeyTable [i] [1] is key) return KeyTable [i] [0];
4159     }
4160     return 0;
4161 }
4162 
4163 /**
4164  * Forces all outstanding paint requests for the display
4165  * to be processed before this method returns.
4166  *
4167  * @exception SWTException <ul>
4168  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4169  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4170  * </ul>
4171  *
4172  * @see Control#update()
4173  */
4174 public void update () {
4175     checkDevice ();
4176     flushExposes (null, true);
4177     OS.gdk_window_process_all_updates ();
4178 }
4179 
4180 /**
4181  * If the receiver's user-interface thread was <code>sleep</code>ing,
4182  * causes it to be awakened and start running again. Note that this
4183  * method may be called from any thread.
4184  *
4185  * @exception SWTException <ul>
4186  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
4187  * </ul>
4188  *
4189  * @see #sleep
4190  */
4191 public void wake () {
4192     synchronized (Device.classinfo) {
4193         if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
4194         if (thread is Thread.currentThread ()) return;
4195         wakeThread ();
4196     }
4197 }
4198 
4199 void wakeThread () {
4200     OS.g_main_context_wakeup (null);
4201     wake_state = true;
4202 }
4203 
4204 static dchar wcsToMbcs (char ch) {
4205     //PORTING_TODO not sure about this
4206     int key = ch & 0xFFFF;
4207     if (key <= 0x7F) return ch;
4208     char [] buffer = Converter.wcsToMbcs (null,[ch], false);
4209     if (buffer.length is 1) return '\0';
4210     if (buffer.length is 2) {
4211         return cast(char) (((buffer [0] & 0xFF) << 8) | (buffer [1] & 0xFF));
4212     }
4213     return '\0';
4214 }
4215 
4216 private static extern(C) int windowProcFunc2 (GtkWidget* handle, ptrdiff_t user_data) {
4217     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4218     CallbackData* cbdata = cast(CallbackData*)user_data;
4219     return cbdata.display.windowProc( handle, cast(ptrdiff_t)cbdata.data );
4220 }
4221 int windowProc (GtkWidget* handle, ptrdiff_t user_data) {
4222     Widget widget = getWidget (handle);
4223     if (widget is null) return 0;
4224     return widget.windowProc (handle, user_data);
4225 }
4226 
4227 private static extern(C) int windowProcFunc3 (ptrdiff_t handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4228     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4229     CallbackData* cbdata = cast(CallbackData*)user_data;
4230     return cbdata.display.windowProc( cast(GtkWidget*)handle, arg0, cast(ptrdiff_t)cbdata.data );
4231 }
4232 int windowProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t user_data) {
4233     Widget widget = getWidget (handle);
4234     if (widget is null) return 0;
4235     return widget.windowProc (handle, arg0, user_data);
4236 }
4237 
4238 private static extern(C) int windowProcFunc4 (ptrdiff_t handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t user_data) {
4239     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4240     CallbackData* cbdata = cast(CallbackData*)user_data;
4241     return cbdata.display.windowProc( cast(GtkWidget*)handle, arg0, arg1, cast(ptrdiff_t)cbdata.data );
4242 }
4243 int windowProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t user_data) {
4244     Widget widget = getWidget (handle);
4245     if (widget is null) return 0;
4246     return widget.windowProc (handle, arg0, arg1, user_data);
4247 }
4248 
4249 private static extern(C) int windowProcFunc5 (ptrdiff_t handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t arg2, ptrdiff_t user_data) {
4250     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4251     CallbackData* cbdata = cast(CallbackData*)user_data;
4252     return cbdata.display.windowProc( cast(GtkWidget*)handle, arg0, arg1, arg2, cast(ptrdiff_t)cbdata.data );
4253 }
4254 int windowProc (GtkWidget* handle, ptrdiff_t arg0, ptrdiff_t arg1, ptrdiff_t arg2, ptrdiff_t user_data) {
4255     Widget widget = getWidget (handle);
4256     if (widget is null) return 0;
4257     return widget.windowProc (handle, arg0, arg1, arg2, user_data);
4258 }
4259 
4260 private static extern(C) int windowProcChangeValueFunc(GtkWidget* handle, int scroll, double value1, void* user_data) {
4261     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4262     CallbackData* cbdata = cast(CallbackData*)user_data;
4263     Widget widget = cbdata.display.getWidget (handle);
4264     if (widget is null) return 0;
4265     return widget.gtk_change_value(handle, scroll, value1, user_data);
4266 }
4267 
4268 package int doWindowTimerAdd( CallbackData* cbdata, int delay, GtkWidget* widget ){
4269     OS.g_object_set_data(cast(GObject*)widget, Display.classinfo.name.ptr, cast(void*)this);
4270     return OS.gtk_timeout_add (delay, &windowTimerProcFunc, widget);
4271 }
4272 private static extern(C) int windowTimerProcFunc (void* user_data) {
4273     version(LOG) getDwtLogger().error( __FILE__, __LINE__,  "Display {}:", __LINE__ ).flush;
4274     Display d = cast(Display) OS.g_object_get_data(cast(GObject*)user_data, Display.classinfo.name.ptr );
4275     return d.windowTimerProc( cast(GtkWidget*)user_data );
4276 }
4277 
4278 int windowTimerProc (GtkWidget* handle) {
4279     Widget widget = getWidget (handle);
4280     if (widget is null) return 0;
4281     return widget.timerProc (handle);
4282 }
4283 
4284 }
4285 
4286 package struct CallbackData {
4287     Display display;
4288     void* data;
4289 }
4290