blob: b94d01f2257a6a3d626f6aecb2ed185d68675756 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package sun.awt.X11;
26
27import java.awt.*;
28import java.awt.event.*;
29import java.awt.peer.*;
30import java.beans.PropertyChangeListener;
31import sun.awt.*;
32import java.util.*;
33import java.awt.dnd.DragSource;
34import java.awt.dnd.DragGestureListener;
35import java.awt.dnd.DragGestureEvent;
36import java.awt.dnd.DragGestureRecognizer;
37import java.awt.dnd.MouseDragGestureRecognizer;
38import java.awt.dnd.InvalidDnDOperationException;
39import java.awt.dnd.peer.DragSourceContextPeer;
40import java.awt.image.*;
41import java.security.*;
42import java.awt.im.InputMethodHighlight;
43import java.awt.im.spi.InputMethodDescriptor;
44import java.awt.datatransfer.Clipboard;
45import javax.swing.LookAndFeel;
46import javax.swing.UIDefaults;
47import java.util.logging.*;
48import sun.font.FontManager;
49import sun.misc.PerformanceLogger;
50import sun.print.PrintJob2D;
51import java.lang.reflect.*;
52
53public class XToolkit extends UNIXToolkit implements Runnable, XConstants {
54 private static Logger log = Logger.getLogger("sun.awt.X11.XToolkit");
55 private static Logger eventLog = Logger.getLogger("sun.awt.X11.event.XToolkit");
56 private static final Logger timeoutTaskLog = Logger.getLogger("sun.awt.X11.timeoutTask.XToolkit");
57 private static Logger keyEventLog = Logger.getLogger("sun.awt.X11.kye.XToolkit");
58 private static final Logger backingStoreLog = Logger.getLogger("sun.awt.X11.backingStore.XToolkit");
59
60 static final boolean PRIMARY_LOOP = false;
61 static final boolean SECONDARY_LOOP = true;
62
63 private static String awtAppClassName = null;
64
65 // the system clipboard - CLIPBOARD selection
66 XClipboard clipboard;
67 // the system selection - PRIMARY selection
68 XClipboard selection;
69
70 // Dynamic Layout Resize client code setting
71 protected static boolean dynamicLayoutSetting = false;
72
73 /**
74 * True when the x settings have been loaded.
75 */
76 private boolean loadedXSettings;
77
78 /**
79 * XSETTINGS for the default screen.
80 * <p>
81 */
82 private XSettings xs;
83
84 static int arrowCursor;
85 static TreeMap winMap = new TreeMap();
86 static HashMap specialPeerMap = new HashMap();
87 static HashMap winToDispatcher = new HashMap();
88 private static long _display;
89 static UIDefaults uidefaults;
90 static X11GraphicsEnvironment localEnv;
91 static X11GraphicsDevice device;
92 static final X11GraphicsConfig config;
93 static int awt_multiclick_time;
94 static boolean securityWarningEnabled;
95
96 private static int screenWidth = -1, screenHeight = -1; // Dimensions of default screen
97 static long awt_defaultFg; // Pixel
98 private static XMouseInfoPeer xPeer;
99 private static Method m_removeSourceEvents;
100
101 static {
102 initSecurityWarning();
103 if (GraphicsEnvironment.isHeadless()) {
104 config = null;
105 } else {
106 localEnv = (X11GraphicsEnvironment) GraphicsEnvironment
107 .getLocalGraphicsEnvironment();
108 device = (X11GraphicsDevice) localEnv.getDefaultScreenDevice();
109 config = (X11GraphicsConfig) (device.getDefaultConfiguration());
110 if (device != null) {
111 _display = device.getDisplay();
112 }
113 setupModifierMap();
114 initIDs();
115 setBackingStoreType();
116 }
117 m_removeSourceEvents = SunToolkit.getMethod(EventQueue.class, "removeSourceEvents", new Class[] {Object.class, Boolean.TYPE}) ;
118 }
119
120 // Error handler stuff
121 static XErrorEvent saved_error;
122 static long saved_error_handler;
123 static XErrorHandler curErrorHandler;
124 // Should be called under LOCK, before releasing LOCK RESTORE_XERROR_HANDLER should be called
125 static void WITH_XERROR_HANDLER(XErrorHandler handler) {
126 saved_error = null;
127 curErrorHandler = handler;
128 XSync();
129 saved_error_handler = XlibWrapper.SetToolkitErrorHandler();
130 }
131 static void XERROR_SAVE(XErrorEvent event) {
132 saved_error = event;
133 }
134 // Should be called under LOCK
135 static void RESTORE_XERROR_HANDLER() {
136 XSync();
137 XlibWrapper.XSetErrorHandler(saved_error_handler);
138 curErrorHandler = null;
139 }
140 // Should be called under LOCK
141 static int SAVED_ERROR_HANDLER(long display, XErrorEvent error) {
142 return XlibWrapper.CallErrorHandler(saved_error_handler, display, error.pData);
143 }
144 interface XErrorHandler {
145 int handleError(long display, XErrorEvent err);
146 }
147 static int GlobalErrorHandler(long display, long event_ptr) {
148 XErrorEvent event = new XErrorEvent(event_ptr);
149 try {
150 if (curErrorHandler != null) {
151 return curErrorHandler.handleError(display, event);
152 } else {
153 return SAVED_ERROR_HANDLER(display, event);
154 }
155 } finally {
156 }
157 }
158
159/*
160 * Instead of validating window id, we simply call XGetWindowProperty,
161 * but temporary install this function as the error handler to ignore
162 * BadWindow error.
163 */
164 static XErrorHandler IgnoreBadWindowHandler = new XErrorHandler() {
165 public int handleError(long display, XErrorEvent err) {
166 XERROR_SAVE(err);
167 if (err.get_error_code() == BadWindow) {
168 return 0;
169 } else {
170 return SAVED_ERROR_HANDLER(display, err);
171 }
172 }
173 };
174
175
176 private native static void initIDs();
177 native static void waitForEvents(long nextTaskTime);
178 static Thread toolkitThread;
179 static boolean isToolkitThread() {
180 return Thread.currentThread() == toolkitThread;
181 }
182
183 static void initSecurityWarning() {
184 // Enable warning only for internal builds
185 String runtime = getSystemProperty("java.runtime.version");
186 securityWarningEnabled = (runtime != null && runtime.contains("internal"));
187 }
188
189 static boolean isSecurityWarningEnabled() {
190 return securityWarningEnabled;
191 }
192
193 static native void awt_output_flush();
194
195 static final void awtFUnlock() {
196 awtUnlock();
197 awt_output_flush();
198 }
199
200
201 public native void nativeLoadSystemColors(int[] systemColors);
202
203 static UIDefaults getUIDefaults() {
204 if (uidefaults == null) {
205 initUIDefaults();
206 }
207 return uidefaults;
208 }
209
210 public void loadSystemColors(int[] systemColors) {
211 nativeLoadSystemColors(systemColors);
212 MotifColorUtilities.loadSystemColors(systemColors);
213 }
214
215
216
217 static void initUIDefaults() {
218 try {
219 // Load Defaults from MotifLookAndFeel
220
221 // This dummy load is necessary to get SystemColor initialized. !!!!!!
222 Color c = SystemColor.text;
223
224 LookAndFeel lnf = new XAWTLookAndFeel();
225 uidefaults = lnf.getDefaults();
226 }
227 catch (Exception e)
228 {
229 e.printStackTrace();
230 }
231 }
232
233 static Object displayLock = new Object();
234
235 public static long getDisplay() {
236 return _display;
237 }
238
239 public static long getDefaultRootWindow() {
240 awtLock();
241 try {
242 long res = XlibWrapper.RootWindow(XToolkit.getDisplay(),
243 XlibWrapper.DefaultScreen(XToolkit.getDisplay()));
244
245 if (res == 0) {
246 throw new IllegalStateException("Root window must not be null");
247 }
248 return res;
249 } finally {
250 awtUnlock();
251 }
252 }
253
254 void init() {
255 awtLock();
256 try {
257 XlibWrapper.XSupportsLocale();
258 if (XlibWrapper.XSetLocaleModifiers("") == null) {
259 log.finer("X locale modifiers are not supported, using default");
260 }
261
262 AwtScreenData defaultScreen = new AwtScreenData(XToolkit.getDefaultScreenData());
263 awt_defaultFg = defaultScreen.get_blackpixel();
264
265 arrowCursor = XlibWrapper.XCreateFontCursor(XToolkit.getDisplay(),
266 XCursorFontConstants.XC_arrow);
267 } finally {
268 awtUnlock();
269 }
270
271 Runtime.getRuntime().addShutdownHook(new Thread() {
272 public void run() {
273 XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance();
274 if (peer != null) {
275 peer.dispose();
276 }
277 if (xs != null) {
278 ((XAWTXSettings)xs).dispose();
279 }
280 if (log.isLoggable(Level.FINE)) {
281 dumpPeers();
282 }
283 }
284 });
285 }
286
287 static String getCorrectXIDString(String val) {
288 if (val != null) {
289 return val.replace('.', '-');
290 } else {
291 return val;
292 }
293 }
294
295 static native String getEnv(String key);
296
297
298 static String getAWTAppClassName() {
299 return awtAppClassName;
300 }
301
302 static final String DATA_TRANSFERER_CLASS_NAME = "sun.awt.X11.XDataTransferer";
303
304 public XToolkit() {
305 super();
306 if (PerformanceLogger.loggingEnabled()) {
307 PerformanceLogger.setTime("XToolkit construction");
308 }
309
310 if (!GraphicsEnvironment.isHeadless()) {
311 String mainClassName = null;
312
313 StackTraceElement trace[] = (new Throwable()).getStackTrace();
314 int bottom = trace.length - 1;
315 if (bottom >= 0) {
316 mainClassName = trace[bottom].getClassName();
317 }
318 if (mainClassName == null || mainClassName.equals("")) {
319 mainClassName = "AWT";
320 }
321 awtAppClassName = getCorrectXIDString(mainClassName);
322
323 init();
324 XWM.init();
325 SunToolkit.setDataTransfererClassName(DATA_TRANSFERER_CLASS_NAME);
326 toolkitThread = new Thread(this, "AWT-XAWT");
327 toolkitThread.setPriority(Thread.NORM_PRIORITY + 1);
328 toolkitThread.setDaemon(true);
329 ThreadGroup mainTG = (ThreadGroup)AccessController.doPrivileged(
330 new PrivilegedAction() {
331 public Object run() {
332 ThreadGroup currentTG =
333 Thread.currentThread().getThreadGroup();
334 ThreadGroup parentTG = currentTG.getParent();
335 while (parentTG != null) {
336 currentTG = parentTG;
337 parentTG = currentTG.getParent();
338 }
339 return currentTG;
340 }
341 });
342 toolkitThread.start();
343 }
344 }
345
346 public ButtonPeer createButton(Button target) {
347 ButtonPeer peer = new XButtonPeer(target);
348 targetCreatedPeer(target, peer);
349 return peer;
350 }
351
352 public FramePeer createFrame(Frame target) {
353 FramePeer peer = new XFramePeer(target);
354 targetCreatedPeer(target, peer);
355 return peer;
356 }
357
358 static void addToWinMap(long window, XBaseWindow xwin)
359 {
360 synchronized(winMap) {
361 winMap.put(Long.valueOf(window),xwin);
362 }
363 }
364
365 static void removeFromWinMap(long window, XBaseWindow xwin) {
366 synchronized(winMap) {
367 winMap.remove(Long.valueOf(window));
368 }
369 }
370 static XBaseWindow windowToXWindow(long window) {
371 synchronized(winMap) {
372 return (XBaseWindow) winMap.get(Long.valueOf(window));
373 }
374 }
375
376 static void addEventDispatcher(long window, XEventDispatcher dispatcher) {
377 synchronized(winToDispatcher) {
378 Long key = Long.valueOf(window);
379 Collection dispatchers = (Collection)winToDispatcher.get(key);
380 if (dispatchers == null) {
381 dispatchers = new Vector();
382 winToDispatcher.put(key, dispatchers);
383 }
384 dispatchers.add(dispatcher);
385 }
386 }
387 static void removeEventDispatcher(long window, XEventDispatcher dispatcher) {
388 synchronized(winToDispatcher) {
389 Long key = Long.valueOf(window);
390 Collection dispatchers = (Collection)winToDispatcher.get(key);
391 if (dispatchers != null) {
392 dispatchers.remove(dispatcher);
393 }
394 }
395 }
396
397 private Point lastCursorPos;
398
399 /**
400 * Returns whether there is last remembered cursor position. The
401 * position is remembered from X mouse events on our peers. The
402 * position is stored in <code>p</code>.
403 * @return true, if there is remembered last cursor position,
404 * false otherwise
405 */
406 boolean getLastCursorPos(Point p) {
407 awtLock();
408 try {
409 if (lastCursorPos == null) {
410 return false;
411 }
412 p.setLocation(lastCursorPos);
413 return true;
414 } finally {
415 awtUnlock();
416 }
417 }
418
419 private void processGlobalMotionEvent(XEvent e) {
420 // Only our windows guaranteely generate MotionNotify, so we
421 // should track enter/leave, to catch the moment when to
422 // switch to XQueryPointer
423 if (e.get_type() == MotionNotify) {
424 XMotionEvent ev = e.get_xmotion();
425 awtLock();
426 try {
427 if (lastCursorPos == null) {
428 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
429 } else {
430 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
431 }
432 } finally {
433 awtUnlock();
434 }
435 } else if (e.get_type() == LeaveNotify) {
436 // Leave from our window
437 awtLock();
438 try {
439 lastCursorPos = null;
440 } finally {
441 awtUnlock();
442 }
443 } else if (e.get_type() == EnterNotify) {
444 // Entrance into our window
445 XCrossingEvent ev = e.get_xcrossing();
446 awtLock();
447 try {
448 if (lastCursorPos == null) {
449 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
450 } else {
451 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
452 }
453 } finally {
454 awtUnlock();
455 }
456 }
457 }
458
459 public interface XEventListener {
460 public void eventProcessed(XEvent e);
461 }
462
463 private Collection<XEventListener> listeners = new LinkedList<XEventListener>();
464
465 public void addXEventListener(XEventListener listener) {
466 synchronized (listeners) {
467 listeners.add(listener);
468 }
469 }
470
471 private void notifyListeners(XEvent xev) {
472 synchronized (listeners) {
473 if (listeners.size() == 0) return;
474
475 XEvent copy = xev.clone();
476 try {
477 for (XEventListener listener : listeners) {
478 listener.eventProcessed(copy);
479 }
480 } finally {
481 copy.dispose();
482 }
483 }
484 }
485
486 private void dispatchEvent(XEvent ev) {
487 final XAnyEvent xany = ev.get_xany();
488
489 if (windowToXWindow(xany.get_window()) != null &&
490 (ev.get_type() == MotionNotify || ev.get_type() == EnterNotify || ev.get_type() == LeaveNotify))
491 {
492 processGlobalMotionEvent(ev);
493 }
494
495 XBaseWindow.dispatchToWindow(ev);
496
497 Collection dispatchers = null;
498 synchronized(winToDispatcher) {
499 Long key = Long.valueOf(xany.get_window());
500 dispatchers = (Collection)winToDispatcher.get(key);
501 if (dispatchers != null) { // Clone it to avoid synchronization during dispatching
502 dispatchers = new Vector(dispatchers);
503 }
504 }
505 if (dispatchers != null) {
506 Iterator iter = dispatchers.iterator();
507 while (iter.hasNext()) {
508 XEventDispatcher disp = (XEventDispatcher)iter.next();
509 disp.dispatchEvent(ev);
510 }
511 }
512 notifyListeners(ev);
513 }
514
515 static void processException(Throwable thr) {
516 if (log.isLoggable(Level.WARNING)) {
517 log.log(Level.WARNING, "Exception on Toolkit thread", thr);
518 }
519 }
520
521 static native void awt_toolkit_init();
522
523 public void run() {
524 awt_toolkit_init();
525 run(PRIMARY_LOOP);
526 }
527
528 public void run(boolean loop)
529 {
530 XEvent ev = new XEvent();
531 while(true) {
532 awtLock();
533 try {
534 if (loop == SECONDARY_LOOP) {
535 // In the secondary loop we may have already aquired awt_lock
536 // several times, so waitForEvents() might be unable to release
537 // the awt_lock and this causes lock up.
538 // For now, we just avoid waitForEvents in the secondary loop.
539 if (!XlibWrapper.XNextSecondaryLoopEvent(getDisplay(),ev.pData)) {
540 break;
541 }
542 } else {
543 callTimeoutTasks();
544 // If no events are queued, waitForEvents() causes calls to
545 // awtUnlock(), awtJNI_ThreadYield, poll, awtLock(),
546 // so it spends most of its time in poll, without holding the lock.
547 while ((XlibWrapper.XEventsQueued(getDisplay(), XlibWrapper.QueuedAfterReading) == 0) &&
548 (XlibWrapper.XEventsQueued(getDisplay(), XlibWrapper.QueuedAfterFlush) == 0)) {
549 callTimeoutTasks();
550 waitForEvents(getNextTaskTime());
551 }
552 XlibWrapper.XNextEvent(getDisplay(),ev.pData);
553 }
554
555 if (ev.get_type() != NoExpose) {
556 eventNumber++;
557 }
558
559 if (XDropTargetEventProcessor.processEvent(ev) ||
560 XDragSourceContextPeer.processEvent(ev)) {
561 continue;
562 }
563
564 if (eventLog.isLoggable(Level.FINER)) {
565 eventLog.log(Level.FINER, "{0}", ev);
566 }
567
568 // Check if input method consumes the event
569 long w = 0;
570 if (windowToXWindow(ev.get_xany().get_window()) != null) {
571 Component owner =
572 XKeyboardFocusManagerPeer.getCurrentNativeFocusOwner();
573 if (owner != null) {
574 XWindow ownerWindow = (XWindow) ComponentAccessor.getPeer(owner);
575 if (ownerWindow != null) {
576 w = ownerWindow.getContentWindow();
577 }
578 }
579 }
580 if( keyEventLog.isLoggable(Level.FINE) && (ev.get_type() == KeyPress || ev.get_type() == KeyRelease) ) {
581 keyEventLog.fine("before XFilterEvent:"+ev);
582 }
583 if (XlibWrapper.XFilterEvent(ev.getPData(), w)) {
584 continue;
585 }
586 if( keyEventLog.isLoggable(Level.FINE) && (ev.get_type() == KeyPress || ev.get_type() == KeyRelease) ) {
587 keyEventLog.fine("after XFilterEvent:"+ev); // IS THIS CORRECT?
588 }
589
590 dispatchEvent(ev);
591 } catch (ThreadDeath td) {
592 XBaseWindow.ungrabInput();
593 return;
594 } catch (Throwable thr) {
595 XBaseWindow.ungrabInput();
596 processException(thr);
597 } finally {
598 awtUnlock();
599 }
600 }
601 }
602
603 static int getDefaultScreenWidth() {
604 if (screenWidth == -1) {
605 long display = getDisplay();
606 awtLock();
607 try {
608 screenWidth = (int) XlibWrapper.DisplayWidth(display, XlibWrapper.DefaultScreen(display));
609 } finally {
610 awtUnlock();
611 }
612 }
613 return screenWidth;
614 }
615
616 static int getDefaultScreenHeight() {
617 if (screenHeight == -1) {
618 long display = getDisplay();
619 awtLock();
620 try {
621 screenHeight = (int) XlibWrapper.DisplayHeight(display, XlibWrapper.DefaultScreen(display));
622 } finally {
623 awtUnlock();
624 }
625 }
626 return screenHeight;
627 }
628
629 protected int getScreenWidth() {
630 return getDefaultScreenWidth();
631 }
632
633 protected int getScreenHeight() {
634 return getDefaultScreenHeight();
635 }
636
637 private static Rectangle getWorkArea(long root)
638 {
639 XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA");
640
641 long native_ptr = Native.allocateLongArray(4);
642 try
643 {
644 boolean workareaPresent = XA_NET_WORKAREA.getAtomData(root,
645 XAtom.XA_CARDINAL, native_ptr, 4);
646 if (workareaPresent)
647 {
648 int rootX = (int)Native.getLong(native_ptr, 0);
649 int rootY = (int)Native.getLong(native_ptr, 1);
650 int rootWidth = (int)Native.getLong(native_ptr, 2);
651 int rootHeight = (int)Native.getLong(native_ptr, 3);
652
653 return new Rectangle(rootX, rootY, rootWidth, rootHeight);
654 }
655 }
656 finally
657 {
658 XlibWrapper.unsafe.freeMemory(native_ptr);
659 }
660
661 return null;
662 }
663
664 /*
665 * If we're running in non-Xinerama environment and the current
666 * window manager supports _NET protocol then the screen insets
667 * are calculated using _NET_WM_WORKAREA property of the root
668 * window.
669 * Otherwise, i. e. if Xinerama is on or _NET_WM_WORKAREA is
670 * not set, we try to calculate the insets ourselves using
671 * getScreenInsetsManually method.
672 */
673 public Insets getScreenInsets(GraphicsConfiguration gc)
674 {
675 XNETProtocol netProto = XWM.getWM().getNETProtocol();
676 if ((netProto == null) || !netProto.active())
677 {
678 return super.getScreenInsets(gc);
679 }
680
681 XToolkit.awtLock();
682 try
683 {
684 X11GraphicsConfig x11gc = (X11GraphicsConfig)gc;
685 X11GraphicsDevice x11gd = (X11GraphicsDevice)x11gc.getDevice();
686 long root = XlibUtil.getRootWindow(x11gd.getScreen());
687 Rectangle rootBounds = XlibUtil.getWindowGeometry(root);
688
689 X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment)
690 GraphicsEnvironment.getLocalGraphicsEnvironment();
691 if (!x11ge.runningXinerama())
692 {
693 Rectangle workArea = XToolkit.getWorkArea(root);
694 if (workArea != null)
695 {
696 return new Insets(workArea.y,
697 workArea.x,
698 rootBounds.height - workArea.height - workArea.y,
699 rootBounds.width - workArea.width - workArea.x);
700 }
701 }
702
703 return getScreenInsetsManually(root, rootBounds, gc.getBounds());
704 }
705 finally
706 {
707 XToolkit.awtUnlock();
708 }
709 }
710
711 /*
712 * Manual calculation of screen insets: get all the windows with
713 * _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL hints and add these
714 * hints' values to screen insets.
715 *
716 * This method should be called under XToolkit.awtLock()
717 */
718 private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds)
719 {
720 /*
721 * During the manual calculation of screen insets we iterate
722 * all the X windows hierarchy starting from root window. This
723 * constant is the max level inspected in this hierarchy.
724 * 3 is a heuristic value: I suppose any the toolbar-like
725 * window is a child of either root or desktop window.
726 */
727 final int MAX_NESTED_LEVEL = 3;
728
729 XAtom XA_NET_WM_STRUT = XAtom.get("_NET_WM_STRUT");
730 XAtom XA_NET_WM_STRUT_PARTIAL = XAtom.get("_NET_WM_STRUT_PARTIAL");
731
732 Insets insets = new Insets(0, 0, 0, 0);
733
734 java.util.List search = new LinkedList();
735 search.add(root);
736 search.add(0);
737 while (!search.isEmpty())
738 {
739 long window = (Long)search.remove(0);
740 int windowLevel = (Integer)search.remove(0);
741
742 /*
743 * Note that most of the modern window managers unmap
744 * application window if it is iconified. Thus, any
745 * _NET_WM_STRUT[_PARTIAL] hints for iconified windows
746 * are not included to the screen insets.
747 */
748 if (XlibUtil.getWindowMapState(window) == XlibWrapper.IsUnmapped)
749 {
750 continue;
751 }
752
753 long native_ptr = Native.allocateLongArray(4);
754 try
755 {
756 // first, check if _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL are present
757 // if both are set on the window, _NET_WM_STRUT_PARTIAL is used (see _NET spec)
758 boolean strutPresent = XA_NET_WM_STRUT_PARTIAL.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
759 if (!strutPresent)
760 {
761 strutPresent = XA_NET_WM_STRUT.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
762 }
763 if (strutPresent)
764 {
765 // second, verify that window is located on the proper screen
766 Rectangle windowBounds = XlibUtil.getWindowGeometry(window);
767 if (windowLevel > 1)
768 {
769 windowBounds = XlibUtil.translateCoordinates(window, root, windowBounds);
770 }
771 // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect
772 // if the struts area intersects with screenBounds, however some window
773 // managers don't set this hint correctly, so we just get intersection with windowBounds
774 if (windowBounds.intersects(screenBounds))
775 {
776 insets.left = Math.max((int)Native.getLong(native_ptr, 0), insets.left);
777 insets.right = Math.max((int)Native.getLong(native_ptr, 1), insets.right);
778 insets.top = Math.max((int)Native.getLong(native_ptr, 2), insets.top);
779 insets.bottom = Math.max((int)Native.getLong(native_ptr, 3), insets.bottom);
780 }
781 }
782 }
783 finally
784 {
785 XlibWrapper.unsafe.freeMemory(native_ptr);
786 }
787
788 if (windowLevel < MAX_NESTED_LEVEL)
789 {
790 Set<Long> children = XlibUtil.getChildWindows(window);
791 for (long child : children)
792 {
793 search.add(child);
794 search.add(windowLevel + 1);
795 }
796 }
797 }
798
799 return insets;
800 }
801
802 /*
803 * The current implementation of disabling background erasing for
804 * canvases is that we don't set any native background color
805 * (with XSetWindowBackground) for the canvas window. However,
806 * this color is set in the peer constructor - see
807 * XWindow.postInit() for details. That's why this method from
808 * SunToolkit is not overridden in XToolkit: it's too late to
809 * disable background erasing :(
810 */
811 /*
812 @Override
813 public void disableBackgroundErase(Canvas canvas) {
814 XCanvasPeer peer = (XCanvasPeer)canvas.getPeer();
815 if (peer == null) {
816 throw new IllegalStateException("Canvas must have a valid peer");
817 }
818 peer.disableBackgroundErase();
819 }
820 */
821
822 // Need this for XMenuItemPeer.
823 protected static final Object targetToPeer(Object target) {
824 Object p=null;
825 if (target != null && !GraphicsEnvironment.isHeadless()) {
826 p = specialPeerMap.get(target);
827 }
828 if (p != null) return p;
829 else
830 return SunToolkit.targetToPeer(target);
831 }
832
833 // Need this for XMenuItemPeer.
834 protected static final void targetDisposedPeer(Object target, Object peer) {
835 SunToolkit.targetDisposedPeer(target, peer);
836 }
837
838 public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
839 return new XRobotPeer(screen.getDefaultConfiguration());
840 }
841
842
843 /*
844 * On X, support for dynamic layout on resizing is governed by the
845 * window manager. If the window manager supports it, it happens
846 * automatically. The setter method for this property is
847 * irrelevant on X.
848 */
849 public void setDynamicLayout(boolean b) {
850 dynamicLayoutSetting = b;
851 }
852
853 protected boolean isDynamicLayoutSet() {
854 return dynamicLayoutSetting;
855 }
856
857 /* Called from isDynamicLayoutActive() and from
858 * lazilyLoadDynamicLayoutSupportedProperty()
859 */
860 protected boolean isDynamicLayoutSupported() {
861 return XWM.getWM().supportsDynamicLayout();
862 }
863
864 public boolean isDynamicLayoutActive() {
865 return isDynamicLayoutSupported();
866 }
867
868
869 public FontPeer getFontPeer(String name, int style){
870 return new XFontPeer(name, style);
871 }
872
873 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
874 return XDragSourceContextPeer.createDragSourceContextPeer(dge);
875 }
876
877 public <T extends DragGestureRecognizer> T
878 createDragGestureRecognizer(Class<T> recognizerClass,
879 DragSource ds,
880 Component c,
881 int srcActions,
882 DragGestureListener dgl)
883 {
884 if (MouseDragGestureRecognizer.class.equals(recognizerClass))
885 return (T)new XMouseDragGestureRecognizer(ds, c, srcActions, dgl);
886 else
887 return null;
888 }
889
890 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
891 XCheckboxMenuItemPeer peer = new XCheckboxMenuItemPeer(target);
892 //vb157120: looks like we don't need to map menu items
893 //in new menus implementation
894 //targetCreatedPeer(target, peer);
895 return peer;
896 }
897
898 public MenuItemPeer createMenuItem(MenuItem target) {
899 XMenuItemPeer peer = new XMenuItemPeer(target);
900 //vb157120: looks like we don't need to map menu items
901 //in new menus implementation
902 //targetCreatedPeer(target, peer);
903 return peer;
904 }
905
906 public TextFieldPeer createTextField(TextField target) {
907 TextFieldPeer peer = new XTextFieldPeer(target);
908 targetCreatedPeer(target, peer);
909 return peer;
910 }
911
912 public LabelPeer createLabel(Label target) {
913 LabelPeer peer = new XLabelPeer(target);
914 targetCreatedPeer(target, peer);
915 return peer;
916 }
917
918 public ListPeer createList(java.awt.List target) {
919 ListPeer peer = new XListPeer(target);
920 targetCreatedPeer(target, peer);
921 return peer;
922 }
923
924 public CheckboxPeer createCheckbox(Checkbox target) {
925 CheckboxPeer peer = new XCheckboxPeer(target);
926 targetCreatedPeer(target, peer);
927 return peer;
928 }
929
930 public ScrollbarPeer createScrollbar(Scrollbar target) {
931 XScrollbarPeer peer = new XScrollbarPeer(target);
932 targetCreatedPeer(target, peer);
933 return peer;
934 }
935
936 public ScrollPanePeer createScrollPane(ScrollPane target) {
937 XScrollPanePeer peer = new XScrollPanePeer(target);
938 targetCreatedPeer(target, peer);
939 return peer;
940 }
941
942 public TextAreaPeer createTextArea(TextArea target) {
943 TextAreaPeer peer = new XTextAreaPeer(target);
944 targetCreatedPeer(target, peer);
945 return peer;
946 }
947
948 public ChoicePeer createChoice(Choice target) {
949 XChoicePeer peer = new XChoicePeer(target);
950 targetCreatedPeer(target, peer);
951 return peer;
952 }
953
954 public CanvasPeer createCanvas(Canvas target) {
955 XCanvasPeer peer = (isXEmbedServerRequested() ? new XEmbedCanvasPeer(target) : new XCanvasPeer(target));
956 targetCreatedPeer(target, peer);
957 return peer;
958 }
959
960 public PanelPeer createPanel(Panel target) {
961 PanelPeer peer = new XPanelPeer(target);
962 targetCreatedPeer(target, peer);
963 return peer;
964 }
965
966 public WindowPeer createWindow(Window target) {
967 WindowPeer peer = new XWindowPeer(target);
968 targetCreatedPeer(target, peer);
969 return peer;
970 }
971
972 public DialogPeer createDialog(Dialog target) {
973 DialogPeer peer = new XDialogPeer(target);
974 targetCreatedPeer(target, peer);
975 return peer;
976 }
977
978 public FileDialogPeer createFileDialog(FileDialog target) {
979 FileDialogPeer peer = new XFileDialogPeer(target);
980 targetCreatedPeer(target, peer);
981 return peer;
982 }
983
984 public MenuBarPeer createMenuBar(MenuBar target) {
985 XMenuBarPeer peer = new XMenuBarPeer(target);
986 targetCreatedPeer(target, peer);
987 return peer;
988 }
989
990 public MenuPeer createMenu(Menu target) {
991 XMenuPeer peer = new XMenuPeer(target);
992 //vb157120: looks like we don't need to map menu items
993 //in new menus implementation
994 //targetCreatedPeer(target, peer);
995 return peer;
996 }
997
998 public PopupMenuPeer createPopupMenu(PopupMenu target) {
999 XPopupMenuPeer peer = new XPopupMenuPeer(target);
1000 targetCreatedPeer(target, peer);
1001 return peer;
1002 }
1003
1004 public synchronized MouseInfoPeer getMouseInfoPeer() {
1005 if (xPeer == null) {
1006 xPeer = new XMouseInfoPeer();
1007 }
1008 return xPeer;
1009 }
1010
1011 public XEmbeddedFramePeer createEmbeddedFrame(XEmbeddedFrame target)
1012 {
1013 XEmbeddedFramePeer peer = new XEmbeddedFramePeer(target);
1014 targetCreatedPeer(target, peer);
1015 return peer;
1016 }
1017
1018 XEmbedChildProxyPeer createEmbedProxy(XEmbedChildProxy target) {
1019 XEmbedChildProxyPeer peer = new XEmbedChildProxyPeer(target);
1020 targetCreatedPeer(target, peer);
1021 return peer;
1022 }
1023
1024 public KeyboardFocusManagerPeer createKeyboardFocusManagerPeer(KeyboardFocusManager manager) throws HeadlessException {
1025 XKeyboardFocusManagerPeer peer = new XKeyboardFocusManagerPeer(manager);
1026 return peer;
1027 }
1028
1029 /**
1030 * Returns a new custom cursor.
1031 */
1032 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name)
1033 throws IndexOutOfBoundsException {
1034 return new XCustomCursor(cursor, hotSpot, name);
1035 }
1036
1037 public TrayIconPeer createTrayIcon(TrayIcon target)
1038 throws HeadlessException, AWTException
1039 {
1040 TrayIconPeer peer = new XTrayIconPeer(target);
1041 targetCreatedPeer(target, peer);
1042 return peer;
1043 }
1044
1045 public SystemTrayPeer createSystemTray(SystemTray target) throws HeadlessException {
1046 SystemTrayPeer peer = new XSystemTrayPeer(target);
1047 return peer;
1048 }
1049
1050 public boolean isTraySupported() {
1051 XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance();
1052 if (peer != null) {
1053 return peer.isAvailable();
1054 }
1055 return false;
1056 }
1057
1058 /**
1059 * Returns the supported cursor size
1060 */
1061 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) {
1062 return XCustomCursor.getBestCursorSize(
1063 java.lang.Math.max(1,preferredWidth), java.lang.Math.max(1,preferredHeight));
1064 }
1065
1066
1067 public int getMaximumCursorColors() {
1068 return 2; // Black and white.
1069 }
1070
1071 public Map mapInputMethodHighlight(InputMethodHighlight highlight) {
1072 return XInputMethod.mapInputMethodHighlight(highlight);
1073 }
1074
1075 public Clipboard getSystemClipboard() {
1076 SecurityManager security = System.getSecurityManager();
1077 if (security != null) {
1078 security.checkSystemClipboardAccess();
1079 }
1080 synchronized (this) {
1081 if (clipboard == null) {
1082 clipboard = new XClipboard("System", "CLIPBOARD");
1083 }
1084 }
1085 return clipboard;
1086 }
1087
1088 public Clipboard getSystemSelection() {
1089 SecurityManager security = System.getSecurityManager();
1090 if (security != null) {
1091 security.checkSystemClipboardAccess();
1092 }
1093 synchronized (this) {
1094 if (selection == null) {
1095 selection = new XClipboard("Selection", "PRIMARY");
1096 }
1097 }
1098 return selection;
1099 }
1100
1101 public void beep() {
1102 awtLock();
1103 try {
1104 XlibWrapper.XBell(getDisplay(), 0);
1105 } finally {
1106 awtUnlock();
1107 }
1108 }
1109
1110 static String getSystemProperty(final String name) {
1111 return (String)AccessController.doPrivileged(new PrivilegedAction() {
1112 public Object run() {
1113 return System.getProperty(name);
1114 }
1115 });
1116 }
1117
1118 public PrintJob getPrintJob(final Frame frame, final String doctitle,
1119 final Properties props) {
1120
1121 if (GraphicsEnvironment.isHeadless()) {
1122 throw new IllegalArgumentException();
1123 }
1124
1125 PrintJob2D printJob = new PrintJob2D(frame, doctitle, props);
1126
1127 if (printJob.printDialog() == false) {
1128 printJob = null;
1129 }
1130 return printJob;
1131 }
1132
1133 public PrintJob getPrintJob(final Frame frame, final String doctitle,
1134 final JobAttributes jobAttributes,
1135 final PageAttributes pageAttributes) {
1136
1137
1138 if (GraphicsEnvironment.isHeadless()) {
1139 throw new IllegalArgumentException();
1140 }
1141
1142 PrintJob2D printJob = new PrintJob2D(frame, doctitle,
1143 jobAttributes, pageAttributes);
1144
1145 if (printJob.printDialog() == false) {
1146 printJob = null;
1147 }
1148
1149 return printJob;
1150 }
1151
1152 static void XSync() {
1153 awtLock();
1154 try {
1155 XlibWrapper.XSync(getDisplay(),0);
1156 } finally {
1157 awtUnlock();
1158 }
1159 }
1160
1161 public int getScreenResolution() {
1162 long display = getDisplay();
1163 awtLock();
1164 try {
1165 return (int) ((XlibWrapper.DisplayWidth(display,
1166 XlibWrapper.DefaultScreen(display)) * 25.4) /
1167 XlibWrapper.DisplayWidthMM(display,
1168 XlibWrapper.DefaultScreen(display)));
1169 } finally {
1170 awtUnlock();
1171 }
1172 }
1173
1174 static native long getDefaultXColormap();
1175 static native long getDefaultScreenData();
1176
1177 static ColorModel screenmodel;
1178
1179 static ColorModel getStaticColorModel() {
1180 if (screenmodel == null) {
1181 screenmodel = config.getColorModel ();
1182 }
1183 return screenmodel;
1184 }
1185
1186 public ColorModel getColorModel() {
1187 return getStaticColorModel();
1188 }
1189
1190 /**
1191 * Returns a new input method adapter descriptor for native input methods.
1192 */
1193 public InputMethodDescriptor getInputMethodAdapterDescriptor() throws AWTException {
1194 return new XInputMethodDescriptor();
1195 }
1196
1197 static int getMultiClickTime() {
1198 if (awt_multiclick_time == 0) {
1199 initializeMultiClickTime();
1200 }
1201 return awt_multiclick_time;
1202 }
1203 static void initializeMultiClickTime() {
1204 awtLock();
1205 try {
1206 try {
1207 String multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(), "*", "multiClickTime");
1208 if (multiclick_time_query != null) {
1209 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query);
1210 // awt_multiclick_time = XtGetMultiClickTime(awt_display);
1211 } else {
1212 multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(),
1213 "OpenWindows", "MultiClickTimeout");
1214 if (multiclick_time_query != null) {
1215 /* Note: OpenWindows.MultiClickTimeout is in tenths of
1216 a second, so we need to multiply by 100 to convert to
1217 milliseconds */
1218 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query) * 100;
1219 } else {
1220 awt_multiclick_time = 200;
1221 // awt_multiclick_time = XtGetMultiClickTime(awt_display);
1222 }
1223 }
1224 } catch (NumberFormatException nf) {
1225 awt_multiclick_time = 200;
1226 } catch (NullPointerException npe) {
1227 awt_multiclick_time = 200;
1228 }
1229 } finally {
1230 awtUnlock();
1231 }
1232 if (awt_multiclick_time == 0) {
1233 awt_multiclick_time = 200;
1234 }
1235 }
1236
1237 public boolean isFrameStateSupported(int state)
1238 throws HeadlessException
1239 {
1240 if (state == Frame.NORMAL || state == Frame.ICONIFIED) {
1241 return true;
1242 } else {
1243 return XWM.getWM().supportsExtendedState(state);
1244 }
1245 }
1246
1247 static void dumpPeers() {
1248 if (log.isLoggable(Level.FINE)) {
1249 log.fine("Mapped windows:");
1250 Iterator iter = winMap.entrySet().iterator();
1251 while (iter.hasNext()) {
1252 Map.Entry entry = (Map.Entry)iter.next();
1253 log.fine(entry.getKey() + "->" + entry.getValue());
1254 if (entry.getValue() instanceof XComponentPeer) {
1255 Component target = (Component)((XComponentPeer)entry.getValue()).getTarget();
1256 log.fine("\ttarget: " + target);
1257 }
1258 }
1259
1260 SunToolkit.dumpPeers(log);
1261
1262 log.fine("Mapped special peers:");
1263 iter = specialPeerMap.entrySet().iterator();
1264 while (iter.hasNext()) {
1265 Map.Entry entry = (Map.Entry)iter.next();
1266 log.fine(entry.getKey() + "->" + entry.getValue());
1267 }
1268
1269 log.fine("Mapped dispatchers:");
1270 iter = winToDispatcher.entrySet().iterator();
1271 while (iter.hasNext()) {
1272 Map.Entry entry = (Map.Entry)iter.next();
1273 log.fine(entry.getKey() + "->" + entry.getValue());
1274 }
1275 }
1276 }
1277
1278 /* Protected with awt_lock. */
1279 private static boolean initialized;
1280 private static boolean timeStampUpdated;
1281 private static long timeStamp;
1282
1283 private static final XEventDispatcher timeFetcher =
1284 new XEventDispatcher() {
1285 public void dispatchEvent(XEvent ev) {
1286 switch (ev.get_type()) {
1287 case PropertyNotify:
1288 XPropertyEvent xpe = ev.get_xproperty();
1289
1290 awtLock();
1291 try {
1292 timeStamp = xpe.get_time();
1293 timeStampUpdated = true;
1294 awtLockNotifyAll();
1295 } finally {
1296 awtUnlock();
1297 }
1298
1299 break;
1300 }
1301 }
1302 };
1303
1304 private static XAtom _XA_JAVA_TIME_PROPERTY_ATOM;
1305
1306 static long getCurrentServerTime() {
1307 awtLock();
1308 try {
1309 try {
1310 if (!initialized) {
1311 XToolkit.addEventDispatcher(XBaseWindow.getXAWTRootWindow().getWindow(),
1312 timeFetcher);
1313 _XA_JAVA_TIME_PROPERTY_ATOM = XAtom.get("_SUNW_JAVA_AWT_TIME");
1314 initialized = true;
1315 }
1316 timeStampUpdated = false;
1317 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
1318 XBaseWindow.getXAWTRootWindow().getWindow(),
1319 _XA_JAVA_TIME_PROPERTY_ATOM.getAtom(), XAtom.XA_ATOM, 32,
1320 PropModeAppend,
1321 0, 0);
1322 XlibWrapper.XFlush(XToolkit.getDisplay());
1323
1324 if (isToolkitThread()) {
1325 XEvent event = new XEvent();
1326 try {
1327 XlibWrapper.XWindowEvent(XToolkit.getDisplay(),
1328 XBaseWindow.getXAWTRootWindow().getWindow(),
1329 XConstants.PropertyChangeMask,
1330 event.pData);
1331 timeFetcher.dispatchEvent(event);
1332 }
1333 finally {
1334 event.dispose();
1335 }
1336 }
1337 else {
1338 while (!timeStampUpdated) {
1339 awtLockWait();
1340 }
1341 }
1342 } catch (InterruptedException ie) {
1343 // Note: the returned timeStamp can be incorrect in this case.
1344 if (log.isLoggable(Level.FINE)) log.fine("Catched exception, timeStamp may not be correct (ie = " + ie + ")");
1345 }
1346 } finally {
1347 awtUnlock();
1348 }
1349 return timeStamp;
1350 }
1351 protected void initializeDesktopProperties() {
1352 desktopProperties.put("DnD.Autoscroll.initialDelay", Integer.valueOf(50));
1353 desktopProperties.put("DnD.Autoscroll.interval", Integer.valueOf(50));
1354 desktopProperties.put("DnD.Autoscroll.cursorHysteresis", Integer.valueOf(5));
1355 // Don't want to call getMultiClickTime() if we are headless
1356 if (!GraphicsEnvironment.isHeadless()) {
1357 desktopProperties.put("awt.multiClickInterval",
1358 Integer.valueOf(getMultiClickTime()));
1359 desktopProperties.put("awt.mouse.numButtons",
1360 Integer.valueOf(getNumMouseButtons()));
1361 }
1362 }
1363
1364 private int getNumMouseButtons() {
1365 awtLock();
1366 try {
1367 return XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), 0, 0);
1368 } finally {
1369 awtUnlock();
1370 }
1371 }
1372
1373 private final static String prefix = "DnD.Cursor.";
1374 private final static String postfix = ".32x32";
1375 private static final String dndPrefix = "DnD.";
1376
1377 protected Object lazilyLoadDesktopProperty(String name) {
1378 if (name.startsWith(prefix)) {
1379 String cursorName = name.substring(prefix.length(), name.length()) + postfix;
1380
1381 try {
1382 return Cursor.getSystemCustomCursor(cursorName);
1383 } catch (AWTException awte) {
1384 throw new RuntimeException("cannot load system cursor: " + cursorName, awte);
1385 }
1386 }
1387
1388 if (name.equals("awt.dynamicLayoutSupported")) {
1389 return Boolean.valueOf(isDynamicLayoutSupported());
1390 }
1391
1392 if (initXSettingsIfNeeded(name)) {
1393 return desktopProperties.get(name);
1394 }
1395
1396 return super.lazilyLoadDesktopProperty(name);
1397 }
1398
1399 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
1400 initXSettingsIfNeeded(name);
1401 super.addPropertyChangeListener(name, pcl);
1402 }
1403
1404 /**
1405 * Initializes XAWTXSettings if a property for a given property name is provided by
1406 * XSettings and they are not initialized yet.
1407 *
1408 * @return true if the method has initialized XAWTXSettings.
1409 */
1410 private boolean initXSettingsIfNeeded(final String propName) {
1411 if (!loadedXSettings &&
1412 (propName.startsWith("gnome.") ||
1413 propName.equals(SunToolkit.DESKTOPFONTHINTS) ||
1414 propName.startsWith(dndPrefix)))
1415 {
1416 loadedXSettings = true;
1417 if (!GraphicsEnvironment.isHeadless()) {
1418 loadXSettings();
1419 /* If no desktop font hint could be retrieved, check for
1420 * KDE running KWin and retrieve settings from fontconfig.
1421 * If that isn't found let SunToolkit will see if there's a
1422 * system property set by a user.
1423 */
1424 if (desktopProperties.get(SunToolkit.DESKTOPFONTHINTS) == null) {
1425 if (XWM.isKDE2()) {
1426 Object hint = FontManager.getFontConfigAAHint();
1427 if (hint != null) {
1428 /* set the fontconfig/KDE property so that
1429 * getDesktopHints() below will see it
1430 * and set the public property.
1431 */
1432 desktopProperties.put(UNIXToolkit.FONTCONFIGAAHINT,
1433 hint);
1434 }
1435 }
1436 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS,
1437 SunToolkit.getDesktopFontHints());
1438 }
1439
1440 return true;
1441 }
1442 }
1443 return false;
1444 }
1445
1446 private void loadXSettings() {
1447 xs = new XAWTXSettings();
1448 }
1449
1450 /**
1451 * Callback from the native side indicating some, or all, of the
1452 * desktop properties have changed and need to be reloaded.
1453 * <code>data</code> is the byte array directly from the x server and
1454 * may be in little endian format.
1455 * <p>
1456 * NB: This could be called from any thread if triggered by
1457 * <code>loadXSettings</code>. It is called from the System EDT
1458 * if triggered by an XSETTINGS change.
1459 */
1460 void parseXSettings(int screen_XXX_ignored,Map updatedSettings) {
1461
1462 if (updatedSettings == null || updatedSettings.isEmpty()) {
1463 return;
1464 }
1465
1466 Iterator i = updatedSettings.entrySet().iterator();
1467 while (i.hasNext()) {
1468 Map.Entry e = (Map.Entry)i.next();
1469 String name = (String)e.getKey();
1470
1471 name = "gnome." + name;
1472 setDesktopProperty(name, e.getValue());
1473 log.fine("name = " + name + " value = " + e.getValue());
1474
1475 // XXX: we probably want to do something smarter. In
1476 // particular, "Net" properties are of interest to the
1477 // "core" AWT itself. E.g.
1478 //
1479 // Net/DndDragThreshold -> ???
1480 // Net/DoubleClickTime -> awt.multiClickInterval
1481 }
1482
1483 setDesktopProperty(SunToolkit.DESKTOPFONTHINTS,
1484 SunToolkit.getDesktopFontHints());
1485
1486 Integer dragThreshold = null;
1487 synchronized (this) {
1488 dragThreshold = (Integer)desktopProperties.get("gnome.Net/DndDragThreshold");
1489 }
1490 if (dragThreshold != null) {
1491 setDesktopProperty("DnD.gestureMotionThreshold", dragThreshold);
1492 }
1493
1494 }
1495
1496
1497
1498 static int altMask;
1499 static int metaMask;
1500 static int numLockMask;
1501 static int modeSwitchMask;
1502 static int modLockIsShiftLock;
1503
1504 /* Like XKeysymToKeycode, but ensures that keysym is the primary
1505 * symbol on the keycode returned. Returns zero otherwise.
1506 */
1507 static int keysymToPrimaryKeycode(long sym) {
1508 awtLock();
1509 try {
1510 int code = XlibWrapper.XKeysymToKeycode(getDisplay(), sym);
1511 if (code == 0) {
1512 return 0;
1513 }
1514 long primary = XlibWrapper.XKeycodeToKeysym(getDisplay(), code, 0);
1515 if (sym != primary) {
1516 return 0;
1517 }
1518 return code;
1519 } finally {
1520 awtUnlock();
1521 }
1522 }
1523
1524 /* Assign meaning - alt, meta, etc. - to X modifiers mod1 ... mod5.
1525 * Only consider primary symbols on keycodes attached to modifiers.
1526 */
1527 static void setupModifierMap() {
1528 final int metaL = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_L);
1529 final int metaR = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_R);
1530 final int altL = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_L);
1531 final int altR = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_R);
1532 final int numLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Num_Lock);
1533 final int modeSwitch = keysymToPrimaryKeycode(XKeySymConstants.XK_Mode_switch);
1534 final int shiftLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Shift_Lock);
1535 final int capsLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Caps_Lock);
1536
1537 final int modmask[] = { ShiftMask, LockMask, ControlMask, Mod1Mask,
1538 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask };
1539
1540 log.fine("In setupModifierMap");
1541 awtLock();
1542 try {
1543 XModifierKeymap modmap = new XModifierKeymap(
1544 XlibWrapper.XGetModifierMapping(getDisplay()));
1545
1546 int nkeys = modmap.get_max_keypermod();
1547
1548 long map_ptr = modmap.get_modifiermap();
1549
1550 for (int modn = XConstants.Mod1MapIndex;
1551 modn <= XConstants.Mod5MapIndex;
1552 ++modn)
1553 {
1554 for (int i = 0; i < nkeys; ++i) {
1555 /* for each keycode attached to this modifier */
1556 int keycode = Native.getUByte(map_ptr, modn * nkeys + i);
1557
1558 if (keycode == 0) {
1559 break;
1560 }
1561 if (metaMask == 0 &&
1562 (keycode == metaL || keycode == metaR))
1563 {
1564 metaMask = modmask[modn];
1565 break;
1566 }
1567 if (altMask == 0 && (keycode == altL || keycode == altR)) {
1568 altMask = modmask[modn];
1569 break;
1570 }
1571 if (numLockMask == 0 && keycode == numLock) {
1572 numLockMask = modmask[modn];
1573 break;
1574 }
1575 if (modeSwitchMask == 0 && keycode == modeSwitch) {
1576 modeSwitchMask = modmask[modn];
1577 break;
1578 }
1579 continue;
1580 }
1581 }
1582 modLockIsShiftLock = 0;
1583 for (int j = 0; j < nkeys; ++j) {
1584 int keycode = Native.getUByte(map_ptr, XConstants.LockMapIndex * nkeys + j);
1585 if (keycode == 0) {
1586 break;
1587 }
1588 if (keycode == shiftLock) {
1589 modLockIsShiftLock = 1;
1590 break;
1591 }
1592 if (keycode == capsLock) {
1593 break;
1594 }
1595 }
1596 XlibWrapper.XFreeModifiermap(modmap.pData);
1597 } finally {
1598 awtUnlock();
1599 }
1600 if (log.isLoggable(Level.FINE)) {
1601 log.fine("metaMask = " + metaMask);
1602 log.fine("altMask = " + altMask);
1603 log.fine("numLockMask = " + numLockMask);
1604 log.fine("modeSwitchMask = " + modeSwitchMask);
1605 log.fine("modLockIsShiftLock = " + modLockIsShiftLock);
1606 }
1607 }
1608
1609
1610 private static SortedMap timeoutTasks;
1611
1612 /**
1613 * Removed the task from the list of waiting-to-be called tasks.
1614 * If the task has been scheduled several times removes only first one.
1615 */
1616 static void remove(Runnable task) {
1617 if (task == null) {
1618 throw new NullPointerException("task is null");
1619 }
1620 awtLock();
1621 try {
1622 if (timeoutTaskLog.isLoggable(Level.FINER)) {
1623 timeoutTaskLog.finer("Removing task " + task);
1624 }
1625 if (timeoutTasks == null) {
1626 if (timeoutTaskLog.isLoggable(Level.FINER)) {
1627 timeoutTaskLog.finer("Task is not scheduled");
1628 }
1629 return;
1630 }
1631 Collection values = timeoutTasks.values();
1632 Iterator iter = values.iterator();
1633 while (iter.hasNext()) {
1634 java.util.List list = (java.util.List)iter.next();
1635 boolean removed = false;
1636 if (list.contains(task)) {
1637 list.remove(task);
1638 if (list.isEmpty()) {
1639 iter.remove();
1640 }
1641 break;
1642 }
1643 }
1644 } finally {
1645 awtUnlock();
1646 }
1647 }
1648
1649 static native void wakeup_poll();
1650
1651 /**
1652 * Registers a Runnable which <code>run()</code> method will be called
1653 * once on the toolkit thread when a specified interval of time elapses.
1654 *
1655 * @param task a Runnable which <code>run</code> method will be called
1656 * on the toolkit thread when <code>interval</code> milliseconds
1657 * elapse
1658 * @param interval an interal in milliseconds
1659 *
1660 * @throws NullPointerException if <code>task</code> is <code>null</code>
1661 * @throws IllegalArgumentException if <code>interval</code> is not positive
1662 */
1663 static void schedule(Runnable task, long interval) {
1664 if (task == null) {
1665 throw new NullPointerException("task is null");
1666 }
1667 if (interval <= 0) {
1668 throw new IllegalArgumentException("interval " + interval + " is not positive");
1669 }
1670
1671 awtLock();
1672 try {
1673 if (timeoutTaskLog.isLoggable(Level.FINER)) {
1674 timeoutTaskLog.log(Level.FINER, "XToolkit.schedule(): current time={0}" +
1675 "; interval={1}" +
1676 "; task being added={2}" + "; tasks before addition={3}", new Object[] {
1677 Long.valueOf(System.currentTimeMillis()), Long.valueOf(interval), task, timeoutTasks});
1678 }
1679
1680 if (timeoutTasks == null) {
1681 timeoutTasks = new TreeMap();
1682 }
1683
1684 Long time = Long.valueOf(System.currentTimeMillis() + interval);
1685 java.util.List tasks = (java.util.List)timeoutTasks.get(time);
1686 if (tasks == null) {
1687 tasks = new ArrayList(1);
1688 timeoutTasks.put(time, tasks);
1689 }
1690 tasks.add(task);
1691
1692
1693 if (timeoutTasks.get(timeoutTasks.firstKey()) == tasks && tasks.size() == 1) {
1694 // Added task became first task - poll won't know
1695 // about it so we need to wake it up
1696 wakeup_poll();
1697 }
1698 } finally {
1699 awtUnlock();
1700 }
1701 }
1702
1703 private long getNextTaskTime() {
1704 awtLock();
1705 try {
1706 if (timeoutTasks == null || timeoutTasks.isEmpty()) {
1707 return -1L;
1708 }
1709 return (Long)timeoutTasks.firstKey();
1710 } finally {
1711 awtUnlock();
1712 }
1713 }
1714
1715 /**
1716 * Executes mature timeout tasks registered with schedule().
1717 * Called from run() under awtLock.
1718 */
1719 private static void callTimeoutTasks() {
1720 if (timeoutTaskLog.isLoggable(Level.FINER)) {
1721 timeoutTaskLog.log(Level.FINER, "XToolkit.callTimeoutTasks(): current time={0}" +
1722 "; tasks={1}", new Object[] {Long.valueOf(System.currentTimeMillis()), timeoutTasks});
1723 }
1724
1725 if (timeoutTasks == null || timeoutTasks.isEmpty()) {
1726 return;
1727 }
1728
1729 Long currentTime = Long.valueOf(System.currentTimeMillis());
1730 Long time = (Long)timeoutTasks.firstKey();
1731
1732 while (time.compareTo(currentTime) <= 0) {
1733 java.util.List tasks = (java.util.List)timeoutTasks.remove(time);
1734
1735 for (Iterator iter = tasks.iterator(); iter.hasNext();) {
1736 Runnable task = (Runnable)iter.next();
1737
1738 if (timeoutTaskLog.isLoggable(Level.FINER)) {
1739 timeoutTaskLog.log(Level.FINER, "XToolkit.callTimeoutTasks(): current time={0}" +
1740 "; about to run task={1}", new Object[] {Long.valueOf(currentTime), task});
1741 }
1742
1743 try {
1744 task.run();
1745 } catch (ThreadDeath td) {
1746 throw td;
1747 } catch (Throwable thr) {
1748 processException(thr);
1749 }
1750 }
1751
1752 if (timeoutTasks.isEmpty()) {
1753 break;
1754 }
1755 time = (Long)timeoutTasks.firstKey();
1756 }
1757 }
1758
1759 static long getAwtDefaultFg() {
1760 return awt_defaultFg;
1761 }
1762
1763 static boolean isLeftMouseButton(MouseEvent me) {
1764 switch (me.getID()) {
1765 case MouseEvent.MOUSE_PRESSED:
1766 case MouseEvent.MOUSE_RELEASED:
1767 return (me.getButton() == MouseEvent.BUTTON1);
1768 case MouseEvent.MOUSE_ENTERED:
1769 case MouseEvent.MOUSE_EXITED:
1770 case MouseEvent.MOUSE_CLICKED:
1771 case MouseEvent.MOUSE_DRAGGED:
1772 return ((me.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0);
1773 }
1774 return false;
1775 }
1776
1777 static boolean isRightMouseButton(MouseEvent me) {
1778 int numButtons = ((Integer)getDefaultToolkit().getDesktopProperty("awt.mouse.numButtons")).intValue();
1779 switch (me.getID()) {
1780 case MouseEvent.MOUSE_PRESSED:
1781 case MouseEvent.MOUSE_RELEASED:
1782 return ((numButtons == 2 && me.getButton() == MouseEvent.BUTTON2) ||
1783 (numButtons > 2 && me.getButton() == MouseEvent.BUTTON3));
1784 case MouseEvent.MOUSE_ENTERED:
1785 case MouseEvent.MOUSE_EXITED:
1786 case MouseEvent.MOUSE_CLICKED:
1787 case MouseEvent.MOUSE_DRAGGED:
1788 return ((numButtons == 2 && (me.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) ||
1789 (numButtons > 2 && (me.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0));
1790 }
1791 return false;
1792 }
1793
1794 static long reset_time_utc;
1795 static final long WRAP_TIME_MILLIS = Integer.MAX_VALUE;
1796
1797 /*
1798 * This function converts between the X server time (number of milliseconds
1799 * since the last server reset) and the UTC time for the 'when' field of an
1800 * InputEvent (or another event type with a timestamp).
1801 */
1802 static long nowMillisUTC_offset(long server_offset) {
1803 // ported from awt_util.c
1804 /*
1805 * Because Time is of type 'unsigned long', it is possible that Time will
1806 * never wrap when using 64-bit Xlib. However, if a 64-bit client
1807 * connects to a 32-bit server, I suspect the values will still wrap. So
1808 * we should not attempt to remove the wrap checking even if _LP64 is
1809 * true.
1810 */
1811
1812 long current_time_utc = System.currentTimeMillis();
1813 if (log.isLoggable(Level.FINER)) {
1814 log.finer("reset_time=" + reset_time_utc + ", current_time=" + current_time_utc
1815 + ", server_offset=" + server_offset + ", wrap_time=" + WRAP_TIME_MILLIS);
1816 }
1817
1818 if ((current_time_utc - reset_time_utc) > WRAP_TIME_MILLIS) {
1819 reset_time_utc = System.currentTimeMillis() - getCurrentServerTime();
1820 }
1821
1822 if (log.isLoggable(Level.FINER)) {
1823 log.finer("result = " + (reset_time_utc + server_offset));
1824 }
1825 return reset_time_utc + server_offset;
1826 }
1827
1828 /**
1829 * @see sun.awt.SunToolkit#needsXEmbedImpl
1830 */
1831 protected boolean needsXEmbedImpl() {
1832 // XToolkit implements supports for XEmbed-client protocol and
1833 // requires the supports from the embedding host for it to work.
1834 return true;
1835 }
1836
1837 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
1838 return (modalityType == null) ||
1839 (modalityType == Dialog.ModalityType.MODELESS) ||
1840 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
1841 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
1842 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
1843 }
1844
1845 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
1846 return (exclusionType == null) ||
1847 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
1848 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
1849 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
1850 }
1851
1852 static EventQueue getEventQueue(Object target) {
1853 AppContext appContext = targetToAppContext(target);
1854 if (appContext != null) {
1855 return (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
1856 }
1857 return null;
1858 }
1859
1860 static void removeSourceEvents(EventQueue queue, Object source, boolean removeAllEvents) {
1861 try {
1862 m_removeSourceEvents.invoke(queue, source, removeAllEvents);
1863 }
1864 catch (IllegalAccessException e)
1865 {
1866 e.printStackTrace();
1867 }
1868 catch (InvocationTargetException e) {
1869 e.printStackTrace();
1870 }
1871 }
1872
1873 public boolean isAlwaysOnTopSupported() {
1874 Iterator iter = XWM.getWM().getProtocols(XLayerProtocol.class).iterator();
1875 while (iter.hasNext()) {
1876 XLayerProtocol proto = (XLayerProtocol)iter.next();
1877 if (proto.supportsLayer(XLayerProtocol.LAYER_ALWAYS_ON_TOP)) {
1878 return true;
1879 }
1880 }
1881 return false;
1882 }
1883
1884 public boolean useBufferPerWindow() {
1885 return XToolkit.getBackingStoreType() == XConstants.NotUseful;
1886 }
1887
1888 /**
1889 * Returns one of XConstants: NotUseful, WhenMapped or Always.
1890 * If backing store is not available on at least one screen, or
1891 * java2d uses DGA(which conflicts with backing store) on at least one screen,
1892 * or the string system property "sun.awt.backingStore" is neither "Always"
1893 * nor "WhenMapped", then the method returns XConstants.NotUseful.
1894 * Otherwise, if the system property "sun.awt.backingStore" is "WhenMapped",
1895 * then the method returns XConstants.WhenMapped.
1896 * Otherwise (i.e., if the system property "sun.awt.backingStore" is "Always"),
1897 * the method returns XConstants.Always.
1898 */
1899 static int getBackingStoreType() {
1900 return backingStoreType;
1901 }
1902
1903 private static void setBackingStoreType() {
1904 String prop = (String)AccessController.doPrivileged(
1905 new sun.security.action.GetPropertyAction("sun.awt.backingStore"));
1906
1907 if (prop == null) {
1908 backingStoreType = XConstants.NotUseful;
1909 if (backingStoreLog.isLoggable(Level.CONFIG)) {
1910 backingStoreLog.config("The system property sun.awt.backingStore is not set" +
1911 ", by default backingStore=NotUseful");
1912 }
1913 return;
1914 }
1915
1916 if (backingStoreLog.isLoggable(Level.CONFIG)) {
1917 backingStoreLog.config("The system property sun.awt.backingStore is " + prop);
1918 }
1919 prop = prop.toLowerCase();
1920 if (prop.equals("always")) {
1921 backingStoreType = XConstants.Always;
1922 } else if (prop.equals("whenmapped")) {
1923 backingStoreType = XConstants.WhenMapped;
1924 } else {
1925 backingStoreType = XConstants.NotUseful;
1926 }
1927
1928 if (backingStoreLog.isLoggable(Level.CONFIG)) {
1929 backingStoreLog.config("backingStore(as provided by the system property)=" +
1930 ( backingStoreType == XConstants.NotUseful ? "NotUseful"
1931 : backingStoreType == XConstants.WhenMapped ?
1932 "WhenMapped" : "Always") );
1933 }
1934
1935 if (sun.java2d.x11.X11SurfaceData.isDgaAvailable()) {
1936 backingStoreType = XConstants.NotUseful;
1937
1938 if (backingStoreLog.isLoggable(Level.CONFIG)) {
1939 backingStoreLog.config("DGA is available, backingStore=NotUseful");
1940 }
1941
1942 return;
1943 }
1944
1945 awtLock();
1946 try {
1947 int screenCount = XlibWrapper.ScreenCount(getDisplay());
1948 for (int i = 0; i < screenCount; i++) {
1949 if (XlibWrapper.DoesBackingStore(XlibWrapper.ScreenOfDisplay(getDisplay(), i))
1950 == XConstants.NotUseful) {
1951 backingStoreType = XConstants.NotUseful;
1952
1953 if (backingStoreLog.isLoggable(Level.CONFIG)) {
1954 backingStoreLog.config("Backing store is not available on the screen " +
1955 i + ", backingStore=NotUseful");
1956 }
1957
1958 return;
1959 }
1960 }
1961 } finally {
1962 awtUnlock();
1963 }
1964 }
1965
1966 /**
1967 * One of XConstants: NotUseful, WhenMapped or Always.
1968 */
1969 private static int backingStoreType;
1970
1971 static boolean awt_ServerInquired = false;
1972 static boolean awt_IsXsunServer = false;
1973 static boolean awt_XKBInquired = false;
1974 static boolean awt_UseXKB = false;
1975 /**
1976 Try to understand if it is Xsun server.
1977 By now (2005) Sun is vendor of Xsun and Xorg servers; we only return true if Xsun is running.
1978 */
1979 static boolean isXsunServer() {
1980 awtLock();
1981 try {
1982 if( awt_ServerInquired ) {
1983 return awt_IsXsunServer;
1984 }
1985 if( ! XlibWrapper.ServerVendor(getDisplay()).startsWith("Sun Microsystems") ) {
1986 awt_ServerInquired = true;
1987 awt_IsXsunServer = false;
1988 return false;
1989 }
1990 // Now, it's Sun. It still may be Xorg though, eg on Solaris 10, x86.
1991 // Today (2005), VendorRelease of Xorg is a Big Number unlike Xsun.
1992 if( XlibWrapper.VendorRelease(getDisplay()) > 10000 ) {
1993 awt_ServerInquired = true;
1994 awt_IsXsunServer = false;
1995 return false;
1996 }
1997 awt_ServerInquired = true;
1998 awt_IsXsunServer = true;
1999 return true;
2000 } finally {
2001 awtUnlock();
2002 }
2003 }
2004 /**
2005 Query XKEYBOARD extension.
2006 */
2007 static boolean isXKBenabled() {
2008 awtLock();
2009 try {
2010 if( awt_XKBInquired ) {
2011 return awt_UseXKB;
2012 }
2013 awt_XKBInquired = true;
2014 String name = "XKEYBOARD";
2015 awt_UseXKB = XlibWrapper.XQueryExtension( getDisplay(), name, XlibWrapper.larg1, XlibWrapper.larg2, XlibWrapper.larg3);
2016 return awt_UseXKB;
2017 } finally {
2018 awtUnlock();
2019 }
2020 }
2021
2022 private static long eventNumber;
2023 public static long getEventNumber() {
2024 awtLock();
2025 try {
2026 return eventNumber;
2027 } finally {
2028 awtUnlock();
2029 }
2030 }
2031
2032 private static XEventDispatcher oops_waiter;
2033 private static boolean oops_updated;
2034 private static boolean oops_failed;
2035 private XAtom oops;
2036 private static final long WORKAROUND_SLEEP = 100;
2037
2038 /**
2039 * @inheritDoc
2040 */
2041 protected boolean syncNativeQueue(final long timeout) {
2042 XBaseWindow win = XBaseWindow.getXAWTRootWindow();
2043
2044 if (oops_waiter == null) {
2045 oops_waiter = new XEventDispatcher() {
2046 public void dispatchEvent(XEvent e) {
2047 if (e.get_type() == SelectionNotify) {
2048 XSelectionEvent pe = e.get_xselection();
2049 if (pe.get_property() == oops.getAtom()) {
2050 oops_updated = true;
2051 awtLockNotifyAll();
2052 } else if (pe.get_selection() == XAtom.get("WM_S0").getAtom() &&
2053 pe.get_target() == XAtom.get("VERSION").getAtom() &&
2054 pe.get_property() == 0 &&
2055 XlibWrapper.XGetSelectionOwner(getDisplay(), XAtom.get("WM_S0").getAtom()) == 0)
2056 {
2057 // WM forgot to acquire selection or there is no WM
2058 oops_failed = true;
2059 awtLockNotifyAll();
2060 }
2061
2062 }
2063 }
2064 };
2065 }
2066
2067 if (oops == null) {
2068 oops = XAtom.get("OOPS");
2069 }
2070
2071 awtLock();
2072 try {
2073 addEventDispatcher(win.getWindow(), oops_waiter);
2074
2075 oops_updated = false;
2076 oops_failed = false;
2077 // Wait for selection notify for oops on win
2078 long event_number = getEventNumber();
2079 XAtom atom = XAtom.get("WM_S0");
2080 eventLog.log(Level.FINER, "WM_S0 selection owner {0}", new Object[] {XlibWrapper.XGetSelectionOwner(getDisplay(), atom.getAtom())});
2081 XlibWrapper.XConvertSelection(getDisplay(), atom.getAtom(),
2082 XAtom.get("VERSION").getAtom(), oops.getAtom(),
2083 win.getWindow(), XlibWrapper.CurrentTime);
2084 XSync();
2085
2086
2087 eventLog.finer("Requested OOPS");
2088
2089 long start = System.currentTimeMillis();
2090 while (!oops_updated && !oops_failed) {
2091 try {
2092 awtLockWait(timeout);
2093 } catch (InterruptedException e) {
2094 throw new RuntimeException(e);
2095 }
2096 // This "while" is a protection from spurious
2097 // wake-ups. However, we shouldn't wait for too long
2098 if ((System.currentTimeMillis() - start > timeout) && timeout >= 0) {
2099 throw new OperationTimedOut(Long.toString(System.currentTimeMillis() - start));
2100 }
2101 }
2102 if (oops_failed && getEventNumber() - event_number == 1) {
2103 // If selection update failed we can simply wait some time
2104 // hoping some events will arrive
2105 awtUnlock();
2106 eventLog.log(Level.FINEST, "Emergency sleep");
2107 try {
2108 Thread.sleep(WORKAROUND_SLEEP);
2109 } catch (InterruptedException ie) {
2110 throw new RuntimeException(ie);
2111 } finally {
2112 awtLock();
2113 }
2114 }
2115 return getEventNumber() - event_number > 2;
2116 } finally {
2117 removeEventDispatcher(win.getWindow(), oops_waiter);
2118 eventLog.log(Level.FINER, "Exiting syncNativeQueue");
2119 awtUnlock();
2120 }
2121 }
2122 public void grab(Window w) {
2123 if (w.getPeer() != null) {
2124 ((XWindowPeer)w.getPeer()).setGrab(true);
2125 }
2126 }
2127
2128 public void ungrab(Window w) {
2129 if (w.getPeer() != null) {
2130 ((XWindowPeer)w.getPeer()).setGrab(false);
2131 }
2132 }
2133 /**
2134 * Returns if the java.awt.Desktop class is supported on the current
2135 * desktop.
2136 * <p>
2137 * The methods of java.awt.Desktop class are supported on the Gnome desktop.
2138 * Check if the running desktop is Gnome by checking the window manager.
2139 */
2140 public boolean isDesktopSupported(){
2141 return XDesktopPeer.isDesktopSupported();
2142 }
2143
2144 public DesktopPeer createDesktopPeer(Desktop target){
2145 return new XDesktopPeer();
2146 }
2147
2148 public static native void setNoisyXErrorHandler();
2149}