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>