Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/swt/widgets/Display.java


1   /*******************************************************************************
2    * Copyright (c) 2000, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.swt.widgets;
12  
13  
14  import org.eclipse.swt.*;
15  import org.eclipse.swt.internal.*;
16  import org.eclipse.swt.internal.gtk.*;
17  import org.eclipse.swt.graphics.*;
18  
19  /**
20   * Instances of this class are responsible for managing the
21   * connection between SWT and the underlying operating
22   * system. Their most important function is to implement
23   * the SWT event loop in terms of the platform event model.
24   * They also provide various methods for accessing information
25   * about the operating system, and have overall control over
26   * the operating system resources which SWT allocates.
27   * <p>
28   * Applications which are built with SWT will <em>almost always</em>
29   * require only a single display. In particular, some platforms
30   * which SWT supports will not allow more than one <em>active</em>
31   * display. In other words, some platforms do not support
32   * creating a new display if one already exists that has not been
33   * sent the <code>dispose()</code> message.
34   * <p>
35   * In SWT, the thread which creates a <code>Display</code>
36   * instance is distinguished as the <em>user-interface thread</em>
37   * for that display.
38   * </p>
39   * The user-interface thread for a particular display has the
40   * following special attributes:
41   * <ul>
42   * <li>
43   * The event loop for that display must be run from the thread.
44   * </li>
45   * <li>
46   * Some SWT API methods (notably, most of the public methods in
47   * <code>Widget</code> and its subclasses), may only be called
48   * from the thread. (To support multi-threaded user-interface
49   * applications, class <code>Display</code> provides inter-thread
50   * communication methods which allow threads other than the 
51   * user-interface thread to request that it perform operations
52   * on their behalf.)
53   * </li>
54   * <li>
55   * The thread is not allowed to construct other 
56   * <code>Display</code>s until that display has been disposed.
57   * (Note that, this is in addition to the restriction mentioned
58   * above concerning platform support for multiple displays. Thus,
59   * the only way to have multiple simultaneously active displays,
60   * even on platforms which support it, is to have multiple threads.)
61   * </li>
62   * </ul>
63   * Enforcing these attributes allows SWT to be implemented directly
64   * on the underlying operating system's event model. This has 
65   * numerous benefits including smaller footprint, better use of 
66   * resources, safer memory management, clearer program logic,
67   * better performance, and fewer overall operating system threads
68   * required. The down side however, is that care must be taken
69   * (only) when constructing multi-threaded applications to use the
70   * inter-thread communication mechanisms which this class provides
71   * when required.
72   * </p><p>
73   * All SWT API methods which may only be called from the user-interface
74   * thread are distinguished in their documentation by indicating that
75   * they throw the "<code>ERROR_THREAD_INVALID_ACCESS</code>"
76   * SWT exception.
77   * </p>
78   * <dl>
79   * <dt><b>Styles:</b></dt>
80   * <dd>(none)</dd>
81   * <dt><b>Events:</b></dt>
82   * <dd>Close, Dispose</dd>
83   * </dl>
84   * <p>
85   * IMPORTANT: This class is <em>not</em> intended to be subclassed.
86   * </p>
87   * @see #syncExec
88   * @see #asyncExec
89   * @see #wake
90   * @see #readAndDispatch
91   * @see #sleep
92   * @see Device#dispose
93   */
94  public class Display extends Device {
95  
96    /* Events Dispatching and Callback */
97    boolean wake;
98    int gdkEventCount;
99    long /*int*/ [] gdkEvents;
100   int [] dispatchEvents;
101   Widget [] gdkEventWidgets;
102   Event [] eventQueue;
103   Callback eventCallback, filterCallback;
104   GdkEventButton gdkEvent = new GdkEventButton ();
105   long /*int*/ eventProc, filterProc, windowProc2, windowProc3, windowProc4, windowProc5;
106   Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5;
107   EventTable eventTable, filterTable;
108   static String APP_NAME = "SWT";
109   static final String DISPATCH_EVENT_KEY = "org.eclipse.swt.internal.gtk.dispatchEvent";
110 
111   /* Widget Table */
112   int freeSlot;
113   int [] indexTable;
114   Widget [] widgetTable;
115   final static int GROW_SIZE = 1024;
116   static final int SWT_OBJECT_INDEX;
117   static {
118     byte [] buffer = Converter.wcsToMbcs (null, "SWT_OBJECT_INDEX", true);
119     SWT_OBJECT_INDEX = OS.g_quark_from_string (buffer);
120   }
121     
122   /* Input method resources */
123   Control imControl;
124   long /*int*/ preeditWindow, preeditLabel;
125 
126   /* Sync/Async Widget Communication */
127   Synchronizer synchronizer = new Synchronizer (this);
128   Thread thread;
129 
130   /* Display Shutdown */
131   Runnable [] disposeList;
132   
133   /* System Tray */
134   Tray tray;
135   
136   /* Timers */
137   int [] timerIds;
138   Runnable [] timerList;
139   Callback timerCallback;
140   long /*int*/ timerProc;
141   Callback windowTimerCallback;
142   long /*int*/ windowTimerProc;
143   
144   /* Caret */
145   Caret currentCaret;
146   Callback caretCallback;
147   int caretId;
148   long /*int*/ caretProc;
149   
150   /* Mnemonics */
151   Control mnemonicControl;
152 
153   /* Mouse hover */
154   int mouseHoverId;
155   long /*int*/ mouseHoverHandle, mouseHoverProc;
156   Callback mouseHoverCallback;
157   
158   /* Menu position callback */
159   long /*int*/ menuPositionProc;
160   Callback menuPositionCallback;
161 
162   /* Shell map callback */
163   long /*int*/ shellMapProc;
164   Callback shellMapCallback;
165   
166   /* GtkTreeView callbacks */
167   int[] treeSelection;
168   int treeSelectionLength;
169   long /*int*/ treeSelectionProc;
170   Callback treeSelectionCallback;
171   long /*int*/ textCellDataProc;
172   Callback textCellDataCallback;
173   long /*int*/ pixbufCellDataProc;
174   Callback pixbufCellDataCallback;
175   
176   /* Flush exposes */
177   long /*int*/ checkIfEventProc;
178   Callback checkIfEventCallback;
179   long /*int*/ flushWindow;
180   boolean flushAll;
181   GdkRectangle flushRect = new GdkRectangle ();
182   XExposeEvent exposeEvent = new XExposeEvent ();
183   XVisibilityEvent visibilityEvent = new XVisibilityEvent ();
184   long /*int*/ [] flushData = new long /*int*/ [1];
185 
186   /* Drag Detect */
187   int dragStartX,dragStartY;
188   boolean dragging;
189   
190   /* Fonts */
191   long /*int*/ defaultFont;
192 
193   /* System Images */
194   long /*int*/ errorPixmap, infoPixmap, questionPixmap, warningPixmap;
195   long /*int*/ errorMask, infoMask, questionMask, warningMask;
196   
197   /* System Cursors */
198   Cursor [] cursors = new Cursor [SWT.CURSOR_HAND + 1];
199 
200   /* Colors */
201   GdkColor COLOR_WIDGET_DARK_SHADOW, COLOR_WIDGET_NORMAL_SHADOW, COLOR_WIDGET_LIGHT_SHADOW;
202   GdkColor COLOR_WIDGET_HIGHLIGHT_SHADOW, COLOR_WIDGET_BACKGROUND, COLOR_WIDGET_FOREGROUND, COLOR_WIDGET_BORDER;
203   GdkColor COLOR_LIST_FOREGROUND, COLOR_LIST_BACKGROUND, COLOR_LIST_SELECTION, COLOR_LIST_SELECTION_TEXT;
204   GdkColor COLOR_TEXT_FOREGROUND, COLOR_TEXT_BACKGROUND, COLOR_INFO_BACKGROUND, COLOR_INFO_FOREGROUND;
205   GdkColor COLOR_TITLE_FOREGROUND, COLOR_TITLE_BACKGROUND, COLOR_TITLE_BACKGROUND_GRADIENT;
206   GdkColor COLOR_TITLE_INACTIVE_FOREGROUND, COLOR_TITLE_INACTIVE_BACKGROUND, COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT;
207 
208   /* Popup Menus */
209   Menu [] popups;
210   int popupTime;
211   
212   /* Key Mappings */
213   static final int [] [] KeyTable = {
214     
215     /* Keyboard and Mouse Masks */
216     {OS.GDK_Alt_L,    SWT.ALT},
217     {OS.GDK_Alt_R,    SWT.ALT},
218     {OS.GDK_Meta_L,  SWT.ALT},
219     {OS.GDK_Meta_R,  SWT.ALT},
220     {OS.GDK_Shift_L,    SWT.SHIFT},
221     {OS.GDK_Shift_R,    SWT.SHIFT},
222     {OS.GDK_Control_L,  SWT.CONTROL},
223     {OS.GDK_Control_R,  SWT.CONTROL},
224 //    {OS.GDK_????,    SWT.COMMAND},
225 //    {OS.GDK_????,    SWT.COMMAND},
226     
227     /* Non-Numeric Keypad Keys */
228     {OS.GDK_Up,            SWT.ARROW_UP},
229     {OS.GDK_KP_Up,          SWT.ARROW_UP},
230     {OS.GDK_Down,          SWT.ARROW_DOWN},
231     {OS.GDK_KP_Down,      SWT.ARROW_DOWN},
232     {OS.GDK_Left,            SWT.ARROW_LEFT},
233     {OS.GDK_KP_Left,        SWT.ARROW_LEFT},
234     {OS.GDK_Right,          SWT.ARROW_RIGHT},
235     {OS.GDK_KP_Right,        SWT.ARROW_RIGHT},
236     {OS.GDK_Page_Up,        SWT.PAGE_UP},
237     {OS.GDK_KP_Page_Up,    SWT.PAGE_UP},
238     {OS.GDK_Page_Down,      SWT.PAGE_DOWN},
239     {OS.GDK_KP_Page_Down,  SWT.PAGE_DOWN},
240     {OS.GDK_Home,          SWT.HOME},
241     {OS.GDK_KP_Home,      SWT.HOME},
242     {OS.GDK_End,            SWT.END},
243     {OS.GDK_KP_End,        SWT.END},
244     {OS.GDK_Insert,          SWT.INSERT},
245     {OS.GDK_KP_Insert,      SWT.INSERT},
246     
247     /* Virtual and Ascii Keys */
248     {OS.GDK_BackSpace,    SWT.BS},
249     {OS.GDK_Return,        SWT.CR},
250     {OS.GDK_Delete,        SWT.DEL},
251     {OS.GDK_KP_Delete,    SWT.DEL},
252     {OS.GDK_Escape,      SWT.ESC},
253     {OS.GDK_Linefeed,      SWT.LF},
254     {OS.GDK_Tab,          SWT.TAB},
255     {OS.GDK_ISO_Left_Tab,   SWT.TAB},
256   
257     /* Functions Keys */
258     {OS.GDK_F1,    SWT.F1},
259     {OS.GDK_F2,    SWT.F2},
260     {OS.GDK_F3,    SWT.F3},
261     {OS.GDK_F4,    SWT.F4},
262     {OS.GDK_F5,    SWT.F5},
263     {OS.GDK_F6,    SWT.F6},
264     {OS.GDK_F7,    SWT.F7},
265     {OS.GDK_F8,    SWT.F8},
266     {OS.GDK_F9,    SWT.F9},
267     {OS.GDK_F10,    SWT.F10},
268     {OS.GDK_F11,    SWT.F11},
269     {OS.GDK_F12,    SWT.F12},
270     {OS.GDK_F13,    SWT.F13},
271     {OS.GDK_F14,    SWT.F14},
272     {OS.GDK_F15,    SWT.F15},
273     
274     /* Numeric Keypad Keys */
275     {OS.GDK_KP_Multiply,    SWT.KEYPAD_MULTIPLY},
276     {OS.GDK_KP_Add,      SWT.KEYPAD_ADD},
277     {OS.GDK_KP_Enter,      SWT.KEYPAD_CR},
278     {OS.GDK_KP_Subtract,  SWT.KEYPAD_SUBTRACT},
279     {OS.GDK_KP_Decimal,  SWT.KEYPAD_DECIMAL},
280     {OS.GDK_KP_Divide,    SWT.KEYPAD_DIVIDE},
281     {OS.GDK_KP_0,      SWT.KEYPAD_0},
282     {OS.GDK_KP_1,      SWT.KEYPAD_1},
283     {OS.GDK_KP_2,      SWT.KEYPAD_2},
284     {OS.GDK_KP_3,      SWT.KEYPAD_3},
285     {OS.GDK_KP_4,      SWT.KEYPAD_4},
286     {OS.GDK_KP_5,      SWT.KEYPAD_5},
287     {OS.GDK_KP_6,      SWT.KEYPAD_6},
288     {OS.GDK_KP_7,      SWT.KEYPAD_7},
289     {OS.GDK_KP_8,      SWT.KEYPAD_8},
290     {OS.GDK_KP_9,      SWT.KEYPAD_9},
291     {OS.GDK_KP_Equal,  SWT.KEYPAD_EQUAL},
292 
293     /* Other keys */
294     {OS.GDK_Caps_Lock,    SWT.CAPS_LOCK},
295     {OS.GDK_Num_Lock,    SWT.NUM_LOCK},
296     {OS.GDK_Scroll_Lock,    SWT.SCROLL_LOCK},
297     {OS.GDK_Pause,        SWT.PAUSE},
298     {OS.GDK_Break,        SWT.BREAK},
299     {OS.GDK_Print,          SWT.PRINT_SCREEN},
300     {OS.GDK_Help,          SWT.HELP},
301     
302   };
303 
304   /* Multiple Displays. */
305   static Display Default;
306   static Display [] Displays = new Display [4];
307 
308   /* Package name */
309   static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets.";
310   /* This code is intentionally commented.
311    * ".class" can not be used on CLDC.
312    */
313   /*static {
314     String name = Display.class.getName ();
315     int index = name.lastIndexOf ('.');
316     PACKAGE_NAME = name.substring (0, index + 1);
317   }*/
318 
319   /*
320   * In order to support CLDC, .class cannot be used because
321   * it does not compile on some Java compilers when they are
322   * targeted for CLDC.  Use Class.forName() instead.
323   */
324   static final Class OS_LOCK;
325   static {
326     Class lock = null;
327     try {
328       lock = Class.forName ("org.eclipse.swt.internal.gtk.OS");
329     } catch (Throwable th) {
330     }
331     OS_LOCK = lock;
332   }
333   
334   /* #define in gdkevents.h */
335   static final int DOUBLE_CLICK_TIME = 250;
336 
337   /* GTK Version */
338   static final int MAJOR = 2;
339   static final int MINOR = 0;
340   static final int MICRO = 6;
341 
342   /* Display Data */
343   Object data;
344   String [] keys;
345   Object [] values;
346   
347   /* Initial Guesses for Shell Trimmings. */
348   int borderTrimWidth = 4, borderTrimHeight = 4;
349   int resizeTrimWidth = 6, resizeTrimHeight = 6;
350   int titleBorderTrimWidth = 5, titleBorderTrimHeight = 28;
351   int titleResizeTrimWidth = 6, titleResizeTrimHeight = 29;
352   int titleTrimWidth = 0, titleTrimHeight = 23;
353   
354   /*
355   * TEMPORARY CODE.  Install the runnable that
356   * gets the current display. This code will
357   * be removed in the future.
358   */
359   static {
360     DeviceFinder = new Runnable () {
361       public void run () {
362         Device device = getCurrent ();
363         if (device == null) {
364           device = getDefault ();
365         }
366         setDevice (device);
367       }
368     };
369   }
370 
371 /*
372 * TEMPORARY CODE.
373 */
374 static void setDevice (Device device) {
375   CurrentDevice = device;
376 }
377 
378 /**
379  * Constructs a new instance of this class.
380  * <p>
381  * Note: The resulting display is marked as the <em>current</em>
382  * display. If this is the first display which has been 
383  * constructed since the application started, it is also
384  * marked as the <em>default</em> display.
385  * </p>
386  *
387  * @exception SWTException <ul>
388  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
389  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
390  * </ul>
391  *
392  * @see #getCurrent
393  * @see #getDefault
394  * @see Widget#checkSubclass
395  * @see Shell
396  */
397 public Display () {
398   this (null);
399 }
400 
401 public Display (DeviceData data) {
402   super (data);
403 }
404 
405 /**
406  * Adds the listener to the collection of listeners who will
407  * be notifed when an event of the given type occurs anywhere
408  * in this display. When the event does occur, the listener is
409  * notified by sending it the <code>handleEvent()</code> message.
410  *
411  * @param eventType the type of event to listen for
412  * @param listener the listener which should be notified when the event occurs
413  *
414  * @exception IllegalArgumentException <ul>
415  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
416  * </ul>
417  * @exception SWTException <ul>
418  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
419  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
420  * </ul>
421  *
422  * @see Listener
423  * @see #removeFilter
424  * @see #removeListener
425  * 
426  * @since 3.0 
427  */
428 public void addFilter (int eventType, Listener listener) {
429   checkDevice ();
430   if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
431   if (filterTable == null) filterTable = new EventTable ();
432   filterTable.hook (eventType, listener);
433 }
434 
435 void addGdkEvent (long /*int*/ event) {
436   if (gdkEvents == null) {
437     gdkEvents = new long /*int*/ [4];
438     gdkEventWidgets = new Widget [4];
439     gdkEventCount = 0;
440   }
441   if (gdkEventCount == gdkEvents.length) {
442     long /*int*/ [] newEvents = new long /*int*/ [gdkEventCount + 4];
443     System.arraycopy (gdkEvents, 0, newEvents, 0, gdkEventCount);
444     gdkEvents = newEvents;
445     Widget [] newWidgets = new Widget [gdkEventCount + 4];
446     System.arraycopy (gdkEventWidgets, 0, newWidgets, 0, gdkEventCount);
447     gdkEventWidgets = newWidgets;
448   }
449   Widget widget = null;
450   long /*int*/ handle = OS.gtk_get_event_widget (event);
451   if (handle != 0) {
452     do {
453       widget = getWidget (handle);
454     } while (widget == null && (handle = OS.gtk_widget_get_parent (handle)) != 0);
455   }
456   gdkEvents [gdkEventCount] = event;
457   gdkEventWidgets [gdkEventCount] = widget;
458   gdkEventCount++;
459 }
460 
461 /**
462  * Adds the listener to the collection of listeners who will
463  * be notifed when an event of the given type occurs. When the
464  * event does occur in the display, the listener is notified by
465  * sending it the <code>handleEvent()</code> message.
466  *
467  * @param eventType the type of event to listen for
468  * @param listener the listener which should be notified when the event occurs
469  *
470  * @exception IllegalArgumentException <ul>
471  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
472  * </ul>
473  * @exception SWTException <ul>
474  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
475  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
476  * </ul>
477  *
478  * @see Listener
479  * @see #removeListener
480  * 
481  * @since 2.0 
482  */
483 public void addListener (int eventType, Listener listener) {
484   checkDevice ();
485   if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
486   if (eventTable == null) eventTable = new EventTable ();
487   eventTable.hook (eventType, listener);
488 }
489 
490 void addMouseHoverTimeout (long /*int*/ handle) {
491   if (mouseHoverId != 0) OS.gtk_timeout_remove (mouseHoverId);
492   mouseHoverId = OS.gtk_timeout_add (400, mouseHoverProc, handle);
493   mouseHoverHandle = handle;
494 }
495 
496 void addPopup (Menu menu) {
497   if (popups == null) popups = new Menu [4];
498   int length = popups.length;
499   for (int i=0; i<length; i++) {
500     if (popups [i] == menu) return;
501   }
502   int index = 0;
503   while (index < length) {
504     if (popups [index] == null) break;
505     index++;
506   }
507   if (index == length) {
508     Menu [] newPopups = new Menu [length + 4];
509     System.arraycopy (popups, 0, newPopups, 0, length);
510     popups = newPopups;
511   }
512   popups [index] = menu;
513 }
514 
515 void addWidget (long /*int*/ handle, Widget widget) {
516   if (handle == 0) return;
517   if (freeSlot == -1) {
518     int length = (freeSlot = indexTable.length) + GROW_SIZE;
519     int[] newIndexTable = new int[length];
520     Widget[] newWidgetTable = new Widget [length];
521     System.arraycopy (indexTable, 0, newIndexTable, 0, freeSlot);
522     System.arraycopy (widgetTable, 0, newWidgetTable, 0, freeSlot);
523     for (int i = freeSlot; i < length - 1; i++) {
524       newIndexTable[i] = i + 1;
525     }
526     newIndexTable[length - 1] = -1;
527     indexTable = newIndexTable;
528     widgetTable = newWidgetTable;
529   }
530   int index = freeSlot + 1;
531   OS.g_object_set_qdata (handle, SWT_OBJECT_INDEX, index);
532   int oldSlot = freeSlot;
533   freeSlot = indexTable[oldSlot];
534   indexTable [oldSlot] = -2;
535   widgetTable [oldSlot] = widget;
536 }
537 
538 /**
539  * Causes the <code>run()</code> method of the runnable to
540  * be invoked by the user-interface thread at the next 
541  * reasonable opportunity. The caller of this method continues 
542  * to run in parallel, and is not notified when the
543  * runnable has completed.
544  *
545  * @param runnable code to run on the user-interface thread.
546  *
547  * @exception SWTException <ul>
548  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
549  * </ul>
550  * 
551  * @see #syncExec
552  */
553 public void asyncExec (Runnable runnable) {
554   if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
555   synchronizer.asyncExec (runnable);
556 }
557 
558 /**
559  * Causes the system hardware to emit a short sound
560  * (if it supports this capability).
561  * 
562  * @exception SWTException <ul>
563  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
564  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
565  * </ul>
566  */
567 public void beep () {
568   if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
569   OS.gdk_beep();
570   OS.gdk_flush();
571 }
572 
573 protected void checkDevice () {
574   if (thread == null) error (SWT.ERROR_WIDGET_DISPOSED);
575   if (thread != Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
576   if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
577 }
578 
579 static synchronized void checkDisplay (Thread thread) {
580   for (int i=0; i<Displays.length; i++) {
581     if (Displays [i] != null && Displays [i].thread == thread) {
582       SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS);
583     }
584   }
585 }
586 
587 long /*int*/ checkIfEventProc (long /*int*/ display, long /*int*/ xEvent, long /*int*/ userData) {
588   OS.memmove (exposeEvent, xEvent, XExposeEvent.sizeof);
589   switch (exposeEvent.type) {
590     case OS.VisibilityNotify:
591     case OS.Expose:
592     case OS.GraphicsExpose:
593       break;
594     default:
595       return 0;
596   }
597   long /*int*/ window = OS.gdk_window_lookup (exposeEvent.window);
598   if (window == 0) return 0;
599   if (flushWindow != 0) {
600     if (flushAll) {
601       long /*int*/ tempWindow = window;
602       do {
603         if (tempWindow == flushWindow) break;
604       } while ((tempWindow = OS.gdk_window_get_parent (tempWindow)) != 0);
605       if (tempWindow != flushWindow) return 0;
606     } else {
607       if (window != flushWindow) return 0;
608     }
609   }
610   switch (exposeEvent.type) {
611     case OS.Expose:
612     case OS.GraphicsExpose: {
613       flushRect.x = exposeEvent.x;
614       flushRect.y = exposeEvent.y;
615       flushRect.width = exposeEvent.width;
616       flushRect.height = exposeEvent.height;
617       OS.gdk_window_invalidate_rect (window, flushRect, true);
618       exposeEvent.type = -1;
619       OS.memmove (xEvent, exposeEvent, XExposeEvent.sizeof);
620       break;
621     }
622     case OS.VisibilityNotify: {
623       OS.memmove (visibilityEvent, xEvent, XVisibilityEvent.sizeof);
624       OS.gdk_window_get_user_data (window, flushData);
625       long /*int*/ handle = flushData [0];
626       Widget widget = handle != 0 ? getWidget (handle) : null;
627       if (widget != null && widget instanceof Control) {
628         Control control = (Control) widget;
629         if (window == control.paintWindow ()) {
630           if (visibilityEvent.state == OS.VisibilityFullyObscured) {
631             control.state |= Widget.OBSCURED;
632           } else {
633             control.state &= ~Widget.OBSCURED;
634           }
635         }
636       }
637       break;
638     }
639   }
640   return 0;
641 }
642 
643 /**
644  * Checks that this class can be subclassed.
645  * <p>
646  * IMPORTANT: See the comment in <code>Widget.checkSubclass()</code>.
647  * </p>
648  *
649  * @exception SWTException <ul>
650  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
651  * </ul>
652  *
653  * @see Widget#checkSubclass
654  */
655 protected void checkSubclass () {
656   if (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
657 }
658 
659 /**
660  * Requests that the connection between SWT and the underlying
661  * operating system be closed.
662  *
663  * @exception SWTException <ul>
664  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
665  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
666  * </ul>
667  *
668  * @see Device#dispose
669  * 
670  * @since 2.0
671  */
672 public void close () {
673   checkDevice ();
674   Event event = new Event ();
675   sendEvent (SWT.Close, event);
676   if (event.doit) dispose ();
677 }
678 
679 /**
680  * Creates the device in the operating system.  If the device
681  * does not have a handle, this method may do nothing depending
682  * on the device.
683  * <p>
684  * This method is called before <code>init</code>.
685  * </p>
686  *
687  * @param data the DeviceData which describes the receiver
688  *
689  * @see #init
690  */
691 protected void create (DeviceData data) {
692   checkSubclass ();
693   checkDisplay(thread = Thread.currentThread ());
694   createDisplay (data);
695   register ();
696   if (Default == null) Default = this;
697 }
698 
699 synchronized void createDisplay (DeviceData data) {
700   /*
701   * This code is intentionally commented.
702   */
703 //  if (!OS.g_thread_supported ()) {
704 //    OS.g_thread_init (0);
705 //    OS.gdk_threads_init ();
706 //  }
707   OS.gtk_set_locale();
708   if (!OS.gtk_init_check (new long /*int*/ [] {0}, null)) {
709     SWT.error (SWT.ERROR_NO_HANDLES);
710   }
711   OS.gtk_widget_set_default_direction (OS.GTK_TEXT_DIR_LTR);
712   OS.gdk_rgb_init ();
713   long /*int*/ ptr = OS.gtk_check_version (MAJOR, MINOR, MICRO);
714   if (ptr != 0) {
715     int length = OS.strlen (ptr);
716     byte [] buffer = new byte [length];
717     OS.memmove (buffer, ptr, length);
718     System.out.println ("***WARNING: " + new String (Converter.mbcsToWcs (null, buffer)));
719     System.out.println ("***WARNING: SWT requires GTK " + MAJOR+ "." + MINOR + "." + MICRO);
720     int major = OS.gtk_major_version (), minor = OS.gtk_minor_version (), micro = OS.gtk_micro_version ();
721     System.out.println ("***WARNING: Detected: " + major + "." + minor + "." + micro);
722   }
723   byte [] buffer = Converter.wcsToMbcs (null, APP_NAME, true);
724   OS.gdk_set_program_class (buffer);
725   byte [] flatStyle = Converter.wcsToMbcs (null, "style \"swt-flat\" { GtkToolbar::shadow-type = none } widget \"*swt-toolbar-flat*\" style : highest \"swt-flat\"", true);
726   OS.gtk_rc_parse_string (flatStyle);
727 
728   /* Initialize the event callback */
729   eventCallback = new Callback (this, "eventProc", 2);
730   eventProc = eventCallback.getAddress ();
731   if (eventProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
732   OS.gdk_event_handler_set (eventProc, 0, 0);
733 }
734 
735 long /*int*/[] createImage (String name) {
736   long /*int*/ style = OS.gtk_widget_get_default_style ();
737   byte[] buffer = Converter.wcsToMbcs (null, name, true);
738   long /*int*/ pixbuf = OS.gtk_icon_set_render_icon (
739     OS.gtk_icon_factory_lookup_default (buffer), style,
740     OS.GTK_TEXT_DIR_NONE, OS.GTK_STATE_NORMAL, -1, 0, 0);
741   if (pixbuf == 0) return null;
742   long /*int*/[] pixmap_return = new long /*int*/[1];
743   long /*int*/[] mask_return = new long /*int*/[1];
744   OS.gdk_pixbuf_render_pixmap_and_mask (pixbuf, pixmap_return, mask_return, 128);
745   OS.g_object_unref (pixbuf);
746   return new long /*int*/[] {pixmap_return [0], mask_return [0]};
747 }
748 
749 synchronized void deregister () {
750   for (int i=0; i<Displays.length; i++) {
751     if (this == Displays [i]) Displays [i] = null;
752   }
753 }
754 
755 /**
756  * Destroys the device in the operating system and releases
757  * the device's handle.  If the device does not have a handle,
758  * this method may do nothing depending on the device.
759  * <p>
760  * This method is called after <code>release</code>.
761  * </p>
762  * @see #dispose
763  * @see #release
764  */
765 protected void destroy () {
766   if (this == Default) Default = null;
767   deregister ();
768   destroyDisplay ();
769 }
770 
771 void destroyDisplay () {
772 }
773 
774 /**
775  * Returns the display which the given thread is the
776  * user-interface thread for, or null if the given thread
777  * is not a user-interface thread for any display.
778  *
779  * @param thread the user-interface thread
780  * @return the display for the given thread
781  */
782 public static synchronized Display findDisplay (Thread thread) {
783   for (int i=0; i<Displays.length; i++) {
784     Display display = Displays [i];
785     if (display != null && display.thread == thread) {
786       return display;
787     }
788   }
789   return null;
790 }
791 
792 /**
793  * Causes the <code>run()</code> method of the runnable to
794  * be invoked by the user-interface thread just before the
795  * receiver is disposed.
796  *
797  * @param runnable code to run at dispose time.
798  * 
799  * @exception SWTException <ul>
800  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
801  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
802  * </ul>
803  */
804 public void disposeExec (Runnable runnable) {
805   checkDevice ();
806   if (disposeList == null) disposeList = new Runnable [4];
807   for (int i=0; i<disposeList.length; i++) {
808     if (disposeList [i] == null) {
809       disposeList [i] = runnable;
810       return;
811     }
812   }
813   Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
814   System.arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
815   newDisposeList [disposeList.length] = runnable;
816   disposeList = newDisposeList;
817 }
818 
819 /**
820  * Does whatever display specific cleanup is required, and then
821  * uses the code in <code>SWTError.error</code> to handle the error.
822  *
823  * @param code the descriptive error code
824  *
825  * @see SWTError#error
826  */
827 void error (int code) {
828   SWT.error (code);
829 }
830 
831 long /*int*/ eventProc (long /*int*/ event, long /*int*/ data) {
832   OS.memmove (gdkEvent, event, GdkEventButton.sizeof);
833   boolean dispatch = true;
834   if (dispatchEvents != null) {
835     dispatch = false;
836     for (int i = 0; i < dispatchEvents.length; i++) {
837       if (gdkEvent.type == dispatchEvents [i]) {
838         dispatch = true;
839         break;
840       }
841     }
842   }
843   if (!dispatch) {
844     addGdkEvent (OS.gdk_event_copy (event));
845     return 0;
846   }
847   Control control = null;
848   long /*int*/ window = 0;
849   switch (gdkEvent.type) {
850     case OS.GDK_ENTER_NOTIFY:
851     case OS.GDK_LEAVE_NOTIFY:
852     case OS.GDK_BUTTON_PRESS:
853     case OS.GDK_2BUTTON_PRESS: 
854     case OS.GDK_3BUTTON_PRESS:
855     case OS.GDK_BUTTON_RELEASE: 
856     case OS.GDK_MOTION_NOTIFY:  {
857       window = gdkEvent.window;
858       long /*int*/ [] user_data = new long /*int*/ [1];
859       do {
860         OS.gdk_window_get_user_data (window, user_data);
861         long /*int*/ handle = user_data [0];
862         if (handle != 0) {
863           Widget widget = getWidget (handle);
864           if (widget != null && widget instanceof Control) {
865             control = (Control) widget;
866             break;
867           }
868         }
869       } while ((window = OS.gdk_window_get_parent (window)) != 0);
870     }
871   }
872   Shell shell = null;
873   if (control != null ) {
874     shell = control.getShell ();
875     if ((shell.style & SWT.ON_TOP) != 0) {
876       OS.gtk_grab_add (shell.shellHandle);
877     }
878   }
879   OS.gtk_main_do_event (event);
880   if (dispatchEvents == null) putGdkEvents ();
881   if (control != null ) {
882     if (shell != null && !shell.isDisposed () && (shell.style & SWT.ON_TOP) != 0) {
883       OS.gtk_grab_remove (shell.shellHandle);
884     }
885   }
886   return 0;
887 }
888 
889 /**
890  * Given the operating system handle for a widget, returns
891  * the instance of the <code>Widget</code> subclass which
892  * represents it in the currently running application, if
893  * such exists, or null if no matching widget can be found.
894  *
895  * @param handle the handle for the widget
896  * @return the SWT widget that the handle represents
897  *
898  * @exception SWTException <ul>
899  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
900  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
901  * </ul>
902  */
903 public Widget findWidget (long /*int*/ handle) {
904   checkDevice ();
905   return getWidget (handle);
906 }
907 
908 void flushExposes (long /*int*/ window, boolean all) {
909   OS.gdk_flush ();
910   OS.gdk_flush ();
911   if (OS.GDK_WINDOWING_X11 ()) {
912     this.flushWindow = window;
913     this.flushAll = all;
914     long /*int*/ xDisplay = OS.GDK_DISPLAY ();
915     long /*int*/ xEvent = OS.g_malloc (XEvent.sizeof);
916     OS.XCheckIfEvent (xDisplay, xEvent, checkIfEventProc, 0);
917     OS.g_free (xEvent);
918     this.flushWindow = 0;
919   }
920 }
921 
922 /**
923  * Returns the currently active <code>Shell</code>, or null
924  * if no shell belonging to the currently running application
925  * is active.
926  *
927  * @return the active shell or null
928  *
929  * @exception SWTException <ul>
930  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
931  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
932  * </ul>
933  */
934 public Shell getActiveShell () {
935   checkDevice ();
936   Shell [] shells = getShells ();
937   for (int i=0; i<shells.length; i++) {
938      if (shells [i].hasFocus) return shells [i];
939   }
940   return null;
941 }
942 
943 /**
944  * Returns a rectangle describing the receiver's size and location.
945  *
946  * @return the bounding rectangle
947  *
948  * @exception SWTException <ul>
949  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
950  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
951  * </ul>
952  */
953 public Rectangle getBounds () {
954   checkDevice ();
955   return new Rectangle (0, 0, OS.gdk_screen_width (), OS.gdk_screen_height ());
956 }
957 
958 /**
959  * Returns the display which the currently running thread is
960  * the user-interface thread for, or null if the currently
961  * running thread is not a user-interface thread for any display.
962  *
963  * @return the current display
964  */
965 public static synchronized Display getCurrent () {
966   Thread current = Thread.currentThread ();
967   for (int i=0; i<Displays.length; i++) {
968     Display display = Displays [i];
969     if (display != null && display.thread == current) return display;
970   }
971   return null;
972 }
973 
974 /**
975  * Returns the control which the on-screen pointer is currently
976  * over top of, or null if it is not currently over one of the
977  * controls built by the currently running application.
978  *
979  * @return the control under the cursor
980  *
981  * @exception SWTException <ul>
982  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
983  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
984  * </ul>
985  */
986 public Control getCursorControl () {
987   checkDevice();
988   int[] x = new int[1], y = new int[1];
989   long /*int*/ window = OS.gdk_window_at_pointer (x,y);
990   if (window == 0) return null;
991   long /*int*/ [] user_data = new long /*int*/ [1];
992   OS.gdk_window_get_user_data (window, user_data);
993   long /*int*/ handle = user_data [0];
994   if (handle == 0) return null;
995   do {
996     Widget widget = getWidget (handle);
997     if (widget != null && widget instanceof Control) {
998       Control control = (Control) widget;
999       if (control.isEnabled ()) return control;
1000    }
1001  } while ((handle = OS.gtk_widget_get_parent (handle)) != 0);
1002  return null;
1003}
1004
1005boolean filterEvent (Event event) {
1006  if (filterTable != null) filterTable.sendEvent (event);
1007  return false;
1008}
1009
1010boolean filters (int eventType) {
1011  if (filterTable == null) return false;
1012  return filterTable.hooks (eventType);
1013}
1014
1015long /*int*/ filterProc (long /*int*/ xEvent, long /*int*/ gdkEvent, long /*int*/ data) {
1016  Widget widget = getWidget (data);
1017  if (widget == null) return 0;
1018  return widget.filterProc (xEvent, gdkEvent, data);
1019}
1020
1021/**
1022 * Returns the location of the on-screen pointer relative
1023 * to the top left corner of the screen.
1024 *
1025 * @return the cursor location
1026 *
1027 * @exception SWTException <ul>
1028 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1029 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1030 * </ul>
1031 */
1032public Point getCursorLocation () {
1033  checkDevice ();
1034  int [] x = new int [1], y = new int [1];
1035  OS.gdk_window_get_pointer (0, x, y, null);
1036  return new Point (x [0], y [0]);
1037}
1038
1039/**
1040 * Returns an array containing the recommended cursor sizes.
1041 *
1042 * @return the array of cursor sizes
1043 *
1044 * @exception SWTException <ul>
1045 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1046 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1047 * </ul>
1048 * 
1049 * @since 3.0
1050 */
1051public Point [] getCursorSizes () {
1052  checkDevice ();
1053  return new Point [] {new Point (16, 16), new Point (32, 32)}; 
1054}
1055
1056/**
1057 * Returns the application defined property of the receiver
1058 * with the specified name, or null if it has not been set.
1059 * <p>
1060 * Applications may have associated arbitrary objects with the
1061 * receiver in this fashion. If the objects stored in the
1062 * properties need to be notified when the display is disposed
1063 * of, it is the application's responsibility provide a
1064 * <code>disposeExec()</code> handler which does so.
1065 * </p>
1066 *
1067 * @param key the name of the property
1068 * @return the value of the property or null if it has not been set
1069 *
1070 * @exception IllegalArgumentException <ul>
1071 *    <li>ERROR_NULL_ARGUMENT - if the key is null</li>
1072 * </ul>
1073 * @exception SWTException <ul>
1074 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1075 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1076 * </ul>
1077 *
1078 * @see #setData
1079 * @see #disposeExec
1080 */
1081public Object getData (String key) {
1082  checkDevice ();
1083  if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
1084  if (key.equals (DISPATCH_EVENT_KEY)) {
1085    return dispatchEvents;
1086  }
1087  if (keys == null) return null;
1088  for (int i=0; i<keys.length; i++) {
1089    if (keys [i].equals (key)) return values [i];
1090  }
1091  return null;
1092}
1093
1094/**
1095 * Returns the application defined, display specific data
1096 * associated with the receiver, or null if it has not been
1097 * set. The <em>display specific data</em> is a single,
1098 * unnamed field that is stored with every display. 
1099 * <p>
1100 * Applications may put arbitrary objects in this field. If
1101 * the object stored in the display specific data needs to
1102 * be notified when the display is disposed of, it is the
1103 * application's responsibility provide a
1104 * <code>disposeExec()</code> handler which does so.
1105 * </p>
1106 *
1107 * @return the display specific data
1108 *
1109 * @exception SWTException <ul>
1110 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1111 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1112 * </ul>
1113 *
1114 * @see #setData
1115 * @see #disposeExec
1116 */
1117public Object getData () {
1118  checkDevice ();
1119  return data;
1120}
1121
1122/**
1123 * Returns a point whose x coordinate is the horizontal
1124 * dots per inch of the display, and whose y coordinate
1125 * is the vertical dots per inch of the display.
1126 *
1127 * @return the horizontal and vertical DPI
1128 *
1129 * @exception SWTException <ul>
1130 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1131 * </ul>
1132 */
1133public Point getDPI () {
1134  checkDevice ();
1135  int widthMM = OS.gdk_screen_width_mm ();
1136  int width = OS.gdk_screen_width ();
1137  int dpi = Compatibility.round (254 * width, widthMM * 10);
1138  return new Point (dpi, dpi);
1139}
1140
1141/**
1142 * Returns the default display. One is created (making the
1143 * thread that invokes this method its user-interface thread)
1144 * if it did not already exist.
1145 *
1146 * @return the default display
1147 */
1148public static synchronized Display getDefault () {
1149  if (Default == null) Default = new Display ();
1150  return Default;
1151}
1152
1153static boolean isValidClass (Class clazz) {
1154  String name = clazz.getName ();
1155  int index = name.lastIndexOf ('.');
1156  return name.substring (0, index + 1).equals (PACKAGE_PREFIX);
1157}
1158
1159/**
1160 * Returns the button dismissal alignment, one of <code>LEFT</code> or <code>RIGHT</code>.
1161 * The button dismissal alignment is the ordering that should be used when positioning the
1162 * default dismissal button for a dialog.  For example, in a dialog that contains an OK and
1163 * CANCEL button, on platforms where the button dismissal alignment is <code>LEFT</code>, the
1164 * button ordering should be OK/CANCEL.  When button dismissal alignment is <code>RIGHT</code>,
1165 * the button ordering should be CANCEL/OK.
1166 *
1167 * @return the button dismissal order
1168 *
1169 * @exception SWTException <ul>
1170 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1171 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1172 * </ul>
1173 * 
1174 * @since 2.1
1175 */
1176public int getDismissalAlignment () {
1177  checkDevice ();
1178  return SWT.RIGHT;
1179}
1180
1181/**
1182 * Returns the longest duration, in milliseconds, between
1183 * two mouse button clicks that will be considered a
1184 * <em>double click</em> by the underlying operating system.
1185 *
1186 * @return the double click time
1187 *
1188 * @exception SWTException <ul>
1189 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1190 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1191 * </ul>
1192 */
1193public int getDoubleClickTime () {
1194  checkDevice ();
1195  return DOUBLE_CLICK_TIME;
1196}
1197
1198/**
1199 * Returns the control which currently has keyboard focus,
1200 * or null if keyboard events are not currently going to
1201 * any of the controls built by the currently running
1202 * application.
1203 *
1204 * @return the control under the cursor
1205 *
1206 * @exception SWTException <ul>
1207 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1208 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1209 * </ul>
1210 */
1211public Control getFocusControl () {
1212  checkDevice ();
1213  Shell shell = getActiveShell ();
1214  if (shell == null) return null;
1215  long /*int*/ shellHandle = shell.shellHandle;
1216  long /*int*/ handle = OS.gtk_window_get_focus (shellHandle);
1217  if (handle == 0) return null;
1218  do {
1219    Widget widget = getWidget (handle);
1220    if (widget != null && widget instanceof Control) {
1221      Control control = (Control) widget;
1222      return control.isEnabled () ? control : null;
1223    }
1224  } while ((handle = OS.gtk_widget_get_parent (handle)) != 0);
1225  return null;
1226}
1227
1228/**
1229 * Returns true when the high contrast mode is enabled.
1230 * Otherwise, false is returned.
1231 * <p>
1232 * Note: This operation is a hint and is not supported on
1233 * platforms that do not have this concept.
1234 * </p>
1235 *
1236 * @return the high contrast mode
1237 *
1238 * @exception SWTException <ul>
1239 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1240 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1241 * </ul>
1242 * 
1243 * @since 3.0
1244 */
1245public boolean getHighContrast () {
1246  checkDevice ();
1247  return false;
1248}
1249
1250public int getDepth () {
1251  checkDevice ();
1252  GdkVisual visual = new GdkVisual ();
1253  OS.memmove (visual, OS.gdk_visual_get_system());
1254  return visual.depth;
1255}
1256
1257/**
1258 * Returns the maximum allowed depth of icons on this display.
1259 * On some platforms, this may be different than the actual
1260 * depth of the display.
1261 *
1262 * @return the maximum icon depth
1263 *
1264 * @exception SWTException <ul>
1265 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1266 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1267 * </ul>
1268 */
1269public int getIconDepth () {
1270  checkDevice ();
1271  return getDepth ();
1272}
1273
1274/**
1275 * Returns an array containing the recommended icon sizes.
1276 *
1277 * @return the array of icon sizes
1278 *
1279 * @exception SWTException <ul>
1280 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1281 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1282 * </ul>
1283 * 
1284 * @see Decorations#setImages(Image[])
1285 * 
1286 * @since 3.0
1287 */
1288public Point [] getIconSizes () {
1289  checkDevice ();
1290  return new Point [] {new Point (16, 16), new Point (32, 32)}; 
1291}
1292
1293int getLastEventTime () {
1294  return OS.gtk_get_current_event_time ();
1295}
1296
1297int getMessageCount () {
1298  return synchronizer.getMessageCount ();
1299}
1300
1301/**
1302 * Returns an array of monitors attached to the device.
1303 * 
1304 * @return the array of monitors
1305 * 
1306 * @since 3.0
1307 */
1308public Monitor [] getMonitors () {
1309  checkDevice ();
1310  Monitor [] monitors = null;
1311  long /*int*/ screen = OS.gdk_screen_get_default ();
1312  if (screen != 0) {
1313    int monitorCount = OS.gdk_screen_get_n_monitors (screen);
1314    if (monitorCount > 0) {
1315      monitors = new Monitor [monitorCount];
1316      GdkRectangle dest = new GdkRectangle ();
1317      for (int i = 0; i < monitorCount; i++) {
1318        OS.gdk_screen_get_monitor_geometry (screen, i, dest);
1319        Monitor monitor = new Monitor ();
1320        monitor.handle = i;
1321        monitor.x = dest.x;
1322        monitor.y = dest.y;
1323        monitor.width = dest.width;
1324        monitor.height = dest.height;
1325        monitor.clientX = monitor.x;
1326        monitor.clientY = monitor.y;
1327        monitor.clientWidth = monitor.width;
1328        monitor.clientHeight = monitor.height;
1329        monitors [i] = monitor;
1330      }
1331    }
1332  }
1333  if (monitors == null) {
1334    /* No multimonitor support detected, default to one monitor */
1335    Monitor monitor = new Monitor ();
1336    Rectangle bounds = getBounds ();
1337    monitor.x = bounds.x;
1338    monitor.y = bounds.y;
1339    monitor.width = bounds.width;
1340    monitor.height = bounds.height;
1341    monitor.clientX = monitor.x;
1342    monitor.clientY = monitor.y;
1343    monitor.clientWidth = monitor.width;
1344    monitor.clientHeight = monitor.height;
1345    monitors = new Monitor [] { monitor };      
1346  }
1347  return monitors;
1348}
1349
1350/**
1351 * Returns the primary monitor for that device.
1352 * 
1353 * @return the primary monitor
1354 * 
1355 * @since 3.0
1356 */
1357public Monitor getPrimaryMonitor () {
1358  checkDevice ();
1359  Monitor [] monitors = getMonitors ();
1360  return monitors [0];
1361}
1362
1363/**
1364 * Returns an array containing all shells which have not been
1365 * disposed and have the receiver as their display.
1366 *
1367 * @return the receiver's shells
1368 *
1369 * @exception SWTException <ul>
1370 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1371 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1372 * </ul>
1373 */
1374public Shell [] getShells () {
1375  checkDevice ();
1376  int length = 0;
1377  for (int i=0; i<widgetTable.length; i++) {
1378    Widget widget = widgetTable [i];
1379    if (widget != null && widget instanceof Shell) length++;
1380  }
1381  int index = 0;
1382  Shell [] result = new Shell [length];
1383  for (int i=0; i<widgetTable.length; i++) {
1384    Widget widget = widgetTable [i];
1385    if (widget != null && widget instanceof Shell) {
1386      int j = 0;
1387      while (j < index) {
1388        if (result [j] == widget) break;
1389        j++;
1390      }
1391      if (j == index) result [index++] = (Shell) widget;
1392    }
1393  }
1394  if (index == length) return result;
1395  Shell [] newResult = new Shell [index];
1396  System.arraycopy (result, 0, newResult, 0, index);
1397  return newResult;
1398}
1399
1400/**
1401 * Returns the thread that has invoked <code>syncExec</code>
1402 * or null if no such runnable is currently being invoked by
1403 * the user-interface thread.
1404 * <p>
1405 * Note: If a runnable invoked by asyncExec is currently
1406 * running, this method will return null.
1407 * </p>
1408 *
1409 * @return the receiver's sync-interface thread
1410 * 
1411 * @exception SWTException <ul>
1412 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1413 * </ul>
1414 */
1415public Thread getSyncThread () {
1416  if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
1417  return synchronizer.syncThread;
1418}
1419
1420/**
1421 * Returns the matching standard color for the given
1422 * constant, which should be one of the color constants
1423 * specified in class <code>SWT</code>. Any value other
1424 * than one of the SWT color constants which is passed
1425 * in will result in the color black. This color should
1426 * not be free'd because it was allocated by the system,
1427 * not the application.
1428 *
1429 * @param id the color constant
1430 * @return the matching color
1431 *
1432 * @exception SWTException <ul>
1433 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1434 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
1435 * </ul>
1436 *
1437 * @see SWT
1438 */
1439public Color getSystemColor (int id) {
1440  checkDevice ();
1441  GdkColor gdkColor = null;
1442  switch (id) {
1443    case SWT.COLOR_INFO_FOREGROUND:           gdkColor = COLOR_INFO_FOREGROUND; break;
1444    case SWT.COLOR_INFO_BACKGROUND:           gdkColor = COLOR_INFO_BACKGROUND; break;
1445    case SWT.COLOR_TITLE_FOREGROUND:          gdkColor = COLOR_TITLE_FOREGROUND; break;
1446    case SWT.COLOR_TITLE_BACKGROUND:          gdkColor = COLOR_TITLE_BACKGROUND; break;
1447    case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:      gdkColor = COLOR_TITLE_BACKGROUND_GRADIENT; break;
1448    case SWT.COLOR_TITLE_INACTIVE_FOREGROUND:      gdkColor = COLOR_TITLE_INACTIVE_FOREGROUND; break;
1449    case SWT.COLOR_TITLE_INACTIVE_BACKGROUND:      gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND; break;
1450    case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:  gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT; break;
1451    case SWT.COLOR_WIDGET_DARK_SHADOW:          gdkColor = COLOR_WIDGET_DARK_SHADOW; break;
1452    case SWT.COLOR_WIDGET_NORMAL_SHADOW:        gdkColor = COLOR_WIDGET_NORMAL_SHADOW; break;
1453    case SWT.COLOR_WIDGET_LIGHT_SHADOW:         gdkColor = COLOR_WIDGET_LIGHT_SHADOW; break;
1454    case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW:        gdkColor = COLOR_WIDGET_HIGHLIGHT_SHADOW; break;
1455    case SWT.COLOR_WIDGET_BACKGROUND:           gdkColor = COLOR_WIDGET_BACKGROUND; break;
1456    case SWT.COLOR_WIDGET_FOREGROUND:           gdkColor = COLOR_WIDGET_FOREGROUND; break;
1457    case SWT.COLOR_WIDGET_BORDER:             gdkColor = COLOR_WIDGET_BORDER; break;
1458    case SWT.COLOR_LIST_FOREGROUND:           gdkColor = COLOR_LIST_FOREGROUND; break;
1459    case SWT.COLOR_LIST_BACKGROUND:           gdkColor = COLOR_LIST_BACKGROUND; break;
1460    case SWT.COLOR_LIST_SELECTION:             gdkColor = COLOR_LIST_SELECTION; break;
1461    case SWT.COLOR_LIST_SELECTION_TEXT:         gdkColor = COLOR_LIST_SELECTION_TEXT; break;
1462    default:
1463      return super.getSystemColor (id);  
1464  }
1465  if (gdkColor == null) return super.getSystemColor (SWT.COLOR_BLACK);
1466  return Color.gtk_new (this, gdkColor);
1467}
1468
1469/**
1470 * Returns the matching standard platform cursor for the given
1471 * constant, which should be one of the cursor constants
1472 * specified in class <code>SWT</code>. This cursor should
1473 * not be free'd because it was allocated by the system,
1474 * not the application.  A value of <code>null</code> will
1475 * be returned if the supplied constant is not an swt cursor
1476 * constant. 
1477 *
1478 * @param id the swt cursor constant
1479 * @return the corresponding cursor or <code>null</code>
1480 *
1481 * @exception SWTException <ul>