1 /*
2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package sun.awt.X11;
26
27 import java.awt.*;
28 import java.awt.event.InputEvent;
29 import java.awt.event.MouseEvent;
30 import java.awt.event.KeyEvent;
31 import java.awt.datatransfer.Clipboard;
32 import java.awt.dnd.DragSource;
33 import java.awt.dnd.DragGestureListener;
34 import java.awt.dnd.DragGestureEvent;
35 import java.awt.dnd.DragGestureRecognizer;
36 import java.awt.dnd.MouseDragGestureRecognizer;
37 import java.awt.dnd.InvalidDnDOperationException;
38 import java.awt.dnd.peer.DragSourceContextPeer;
39 import java.awt.im.InputMethodHighlight;
40 import java.awt.im.spi.InputMethodDescriptor;
41 import java.awt.image.ColorModel;
42 import java.awt.peer.*;
43 import java.beans.PropertyChangeListener;
44 import java.security.AccessController;
45 import java.security.PrivilegedAction;
46 import java.util.*;
47 import javax.swing.LookAndFeel;
48 import javax.swing.UIDefaults;
49 import sun.awt.*;
50 import sun.awt.datatransfer.DataTransferer;
51 import sun.font.FontConfigManager;
52 import sun.java2d.SunGraphicsEnvironment;
53 import sun.misc.*;
54 import sun.misc.ThreadGroupUtils;
55 import sun.print.PrintJob2D;
56 import sun.security.action.GetPropertyAction;
57 import sun.security.action.GetBooleanAction;
58 import sun.util.logging.PlatformLogger;
59
60 public final class XToolkit extends UNIXToolkit implements Runnable {
61 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XToolkit");
62 private static final PlatformLogger eventLog = PlatformLogger.getLogger("sun.awt.X11.event.XToolkit");
63 private static final PlatformLogger timeoutTaskLog = PlatformLogger.getLogger("sun.awt.X11.timeoutTask.XToolkit");
64 private static final PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XToolkit");
65 private static final PlatformLogger backingStoreLog = PlatformLogger.getLogger("sun.awt.X11.backingStore.XToolkit");
66
67 //There is 400 ms is set by default on Windows and 500 by default on KDE and GNOME.
68 //We use the same hardcoded constant.
69 private final static int AWT_MULTICLICK_DEFAULT_TIME = 500;
70
71 static final boolean PRIMARY_LOOP = false;
72 static final boolean SECONDARY_LOOP = true;
73
74 private static String awtAppClassName = null;
75
76 // the system clipboard - CLIPBOARD selection
77 XClipboard clipboard;
78 // the system selection - PRIMARY selection
79 XClipboard selection;
80
81 // Dynamic Layout Resize client code setting
82 protected static boolean dynamicLayoutSetting = false;
83
84 //Is it allowed to generate events assigned to extra mouse buttons.
85 //Set to true by default.
86 private static boolean areExtraMouseButtonsEnabled = true;
87
88 /**
89 * True when the x settings have been loaded.
90 */
91 private boolean loadedXSettings;
92
93 /**
94 * XSETTINGS for the default screen.
95 * <p>
96 */
97 private XSettings xs;
98
99 private FontConfigManager fcManager = new FontConfigManager();
100
101 static int arrowCursor;
102 static TreeMap winMap = new TreeMap();
103 static HashMap specialPeerMap = new HashMap();
104 static HashMap winToDispatcher = new HashMap();
105 private static long _display;
106 static UIDefaults uidefaults;
107 static X11GraphicsEnvironment localEnv;
108 static X11GraphicsDevice device;
109 static final X11GraphicsConfig config;
110 static int awt_multiclick_time;
111 static boolean securityWarningEnabled;
112
113 private static volatile int screenWidth = -1, screenHeight = -1; // Dimensions of default screen
114 static long awt_defaultFg; // Pixel
115 private static XMouseInfoPeer xPeer;
116
117 static {
118 initSecurityWarning();
119 if (GraphicsEnvironment.isHeadless()) {
120 config = null;
121 } else {
122 localEnv = (X11GraphicsEnvironment) GraphicsEnvironment
123 .getLocalGraphicsEnvironment();
124 device = (X11GraphicsDevice) localEnv.getDefaultScreenDevice();
125 config = (X11GraphicsConfig) (device.getDefaultConfiguration());
126 if (device != null) {
127 _display = device.getDisplay();
128 }
129 setupModifierMap();
130 initIDs();
131 setBackingStoreType();
132 }
133 }
134
135 /*
136 * Return (potentially) platform specific display timeout for the
137 * tray icon
138 */
139 static native long getTrayIconDisplayTimeout();
140
141 private native static void initIDs();
142 native static void waitForEvents(long nextTaskTime);
143 static Thread toolkitThread;
144 static boolean isToolkitThread() {
145 return Thread.currentThread() == toolkitThread;
146 }
147
148 static void initSecurityWarning() {
149 // Enable warning only for internal builds
150 String runtime = AccessController.doPrivileged(
151 new GetPropertyAction("java.runtime.version"));
152 securityWarningEnabled = (runtime != null && runtime.contains("internal"));
153 }
154
155 static boolean isSecurityWarningEnabled() {
156 return securityWarningEnabled;
157 }
158
159 static native void awt_output_flush();
160
161 static final void awtFUnlock() {
162 awtUnlock();
163 awt_output_flush();
164 }
165
166
167 public native void nativeLoadSystemColors(int[] systemColors);
168
169 static UIDefaults getUIDefaults() {
170 if (uidefaults == null) {
171 initUIDefaults();
172 }
173 return uidefaults;
174 }
175
176 public void loadSystemColors(int[] systemColors) {
177 nativeLoadSystemColors(systemColors);
178 MotifColorUtilities.loadSystemColors(systemColors);
179 }
180
181
182
183 static void initUIDefaults() {
184 try {
185 // Load Defaults from MotifLookAndFeel
186
187 // This dummy load is necessary to get SystemColor initialized. !!!!!!
188 Color c = SystemColor.text;
189
190 LookAndFeel lnf = new XAWTLookAndFeel();
191 uidefaults = lnf.getDefaults();
192 }
193 catch (Exception e)
194 {
195 e.printStackTrace();
196 }
197 }
198
199 static Object displayLock = new Object();
200
201 public static long getDisplay() {
202 return _display;
203 }
204
205 public static long getDefaultRootWindow() {
206 awtLock();
207 try {
208 long res = XlibWrapper.RootWindow(XToolkit.getDisplay(),
209 XlibWrapper.DefaultScreen(XToolkit.getDisplay()));
210
211 if (res == 0) {
212 throw new IllegalStateException("Root window must not be null");
213 }
214 return res;
215 } finally {
216 awtUnlock();
217 }
218 }
219
220 void init() {
221 awtLock();
222 try {
223 XlibWrapper.XSupportsLocale();
224 if (XlibWrapper.XSetLocaleModifiers("") == null) {
225 log.finer("X locale modifiers are not supported, using default");
226 }
227 tryXKB();
228
229 AwtScreenData defaultScreen = new AwtScreenData(XToolkit.getDefaultScreenData());
230 awt_defaultFg = defaultScreen.get_blackpixel();
231
232 arrowCursor = XlibWrapper.XCreateFontCursor(XToolkit.getDisplay(),
233 XCursorFontConstants.XC_arrow);
234 areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
235 //set system property if not yet assigned
236 System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
237
238 // Detect display mode changes
239 XlibWrapper.XSelectInput(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), XConstants.StructureNotifyMask);
240 XToolkit.addEventDispatcher(XToolkit.getDefaultRootWindow(), new XEventDispatcher() {
241 @Override
242 public void dispatchEvent(XEvent ev) {
243 if (ev.get_type() == XConstants.ConfigureNotify) {
244 awtUnlock();
245 try {
246 ((X11GraphicsEnvironment)GraphicsEnvironment.
247 getLocalGraphicsEnvironment()).
248 displayChanged();
249 } finally {
250 awtLock();
251 }
252 }
253 }
254 });
255 } finally {
256 awtUnlock();
257 }
258 PrivilegedAction<Void> a = () -> {
259 Thread shutdownThread = new Thread(ThreadGroupUtils.getRootThreadGroup(), "XToolkt-Shutdown-Thread") {
260 public void run() {
261 XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance();
262 if (peer != null) {
263 peer.dispose();
264 }
265 if (xs != null) {
266 ((XAWTXSettings)xs).dispose();
267 }
268 freeXKB();
269 if (log.isLoggable(PlatformLogger.Level.FINE)) {
270 dumpPeers();
271 }
272 }
273 };
274 shutdownThread.setContextClassLoader(null);
275 Runtime.getRuntime().addShutdownHook(shutdownThread);
276 return null;
277 };
278 AccessController.doPrivileged(a);
279 }
280
281 static String getCorrectXIDString(String val) {
282 if (val != null) {
283 return val.replace('.', '-');
284 } else {
285 return val;
286 }
287 }
288
289 static native String getEnv(String key);
290
291
292 static String getAWTAppClassName() {
293 return awtAppClassName;
294 }
295
296 public XToolkit() {
297 super();
298 if (PerformanceLogger.loggingEnabled()) {
299 PerformanceLogger.setTime("XToolkit construction");
300 }
301
302 if (!GraphicsEnvironment.isHeadless()) {
303 String mainClassName = null;
304
305 StackTraceElement trace[] = (new Throwable()).getStackTrace();
306 int bottom = trace.length - 1;
307 if (bottom >= 0) {
308 mainClassName = trace[bottom].getClassName();
309 }
310 if (mainClassName == null || mainClassName.equals("")) {
311 mainClassName = "AWT";
312 }
313 awtAppClassName = getCorrectXIDString(mainClassName);
314
315 init();
316 XWM.init();
317
318 toolkitThread = AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
319 Thread thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), XToolkit.this, "AWT-XAWT");
320 thread.setContextClassLoader(null);
321 thread.setPriority(Thread.NORM_PRIORITY + 1);
322 thread.setDaemon(true);
323 return thread;
324 });
325 toolkitThread.start();
326 }
327 }
328
329 public ButtonPeer createButton(Button target) {
330 ButtonPeer peer = new XButtonPeer(target);
331 targetCreatedPeer(target, peer);
332 return peer;
333 }
334
335 public FramePeer createLightweightFrame(LightweightFrame target) {
336 FramePeer peer = new XLightweightFramePeer(target);
337 targetCreatedPeer(target, peer);
338 return peer;
339 }
340
341 public FramePeer createFrame(Frame target) {
342 FramePeer peer = new XFramePeer(target);
343 targetCreatedPeer(target, peer);
344 return peer;
345 }
346
347 static void addToWinMap(long window, XBaseWindow xwin)
348 {
349 synchronized(winMap) {
350 winMap.put(Long.valueOf(window),xwin);
351 }
352 }
353
354 static void removeFromWinMap(long window, XBaseWindow xwin) {
355 synchronized(winMap) {
356 winMap.remove(Long.valueOf(window));
357 }
358 }
359 static XBaseWindow windowToXWindow(long window) {
360 synchronized(winMap) {
361 return (XBaseWindow) winMap.get(Long.valueOf(window));
362 }
363 }
364
365 static void addEventDispatcher(long window, XEventDispatcher dispatcher) {
366 synchronized(winToDispatcher) {
367 Long key = Long.valueOf(window);
368 Collection dispatchers = (Collection)winToDispatcher.get(key);
369 if (dispatchers == null) {
370 dispatchers = new Vector();
371 winToDispatcher.put(key, dispatchers);
372 }
373 dispatchers.add(dispatcher);
374 }
375 }
376 static void removeEventDispatcher(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.remove(dispatcher);
382 }
383 }
384 }
385
386 private Point lastCursorPos;
387
388 /**
389 * Returns whether there is last remembered cursor position. The
390 * position is remembered from X mouse events on our peers. The
391 * position is stored in <code>p</code>.
392 * @return true, if there is remembered last cursor position,
393 * false otherwise
394 */
395 boolean getLastCursorPos(Point p) {
396 awtLock();
397 try {
398 if (lastCursorPos == null) {
399 return false;
400 }
401 p.setLocation(lastCursorPos);
402 return true;
403 } finally {
404 awtUnlock();
405 }
406 }
407
408 private void processGlobalMotionEvent(XEvent e) {
409 // Only our windows guaranteely generate MotionNotify, so we
410 // should track enter/leave, to catch the moment when to
411 // switch to XQueryPointer
412 if (e.get_type() == XConstants.MotionNotify) {
413 XMotionEvent ev = e.get_xmotion();
414 awtLock();
415 try {
416 if (lastCursorPos == null) {
417 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
418 } else {
419 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
420 }
421 } finally {
422 awtUnlock();
423 }
424 } else if (e.get_type() == XConstants.LeaveNotify) {
425 // Leave from our window
426 awtLock();
427 try {
428 lastCursorPos = null;
429 } finally {
430 awtUnlock();
431 }
432 } else if (e.get_type() == XConstants.EnterNotify) {
433 // Entrance into our window
434 XCrossingEvent ev = e.get_xcrossing();
435 awtLock();
436 try {
437 if (lastCursorPos == null) {
438 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
439 } else {
440 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
441 }
442 } finally {
443 awtUnlock();
444 }
445 }
446 }
447
448 public interface XEventListener {
449 public void eventProcessed(XEvent e);
450 }
451
452 private Collection<XEventListener> listeners = new LinkedList<XEventListener>();
453
454 public void addXEventListener(XEventListener listener) {
455 synchronized (listeners) {
456 listeners.add(listener);
457 }
458 }
459
460 private void notifyListeners(XEvent xev) {
461 synchronized (listeners) {
462 if (listeners.size() == 0) return;
463
464 XEvent copy = xev.clone();
465 try {
466 for (XEventListener listener : listeners) {
467 listener.eventProcessed(copy);
468 }
469 } finally {
470 copy.dispose();
471 }
472 }
473 }
474
475 private void dispatchEvent(XEvent ev) {
476 final XAnyEvent xany = ev.get_xany();
477
478 if (windowToXWindow(xany.get_window()) != null &&
479 (ev.get_type() == XConstants.MotionNotify || ev.get_type() == XConstants.EnterNotify || ev.get_type() == XConstants.LeaveNotify))
480 {
481 processGlobalMotionEvent(ev);
482 }
483
484 if( ev.get_type() == XConstants.MappingNotify ) {
485 // The 'window' field in this event is unused.
486 // This application itself does nothing to initiate such an event
487 // (no calls of XChangeKeyboardMapping etc.).
488 // SunRay server sends this event to the application once on every
489 // keyboard (not just layout) change which means, quite seldom.
490 XlibWrapper.XRefreshKeyboardMapping(ev.pData);
491 resetKeyboardSniffer();
492 setupModifierMap();
493 }
494 XBaseWindow.dispatchToWindow(ev);
495
496 Collection dispatchers = null;
497 synchronized(winToDispatcher) {
498 Long key = Long.valueOf(xany.get_window());
499 dispatchers = (Collection)winToDispatcher.get(key);
500 if (dispatchers != null) { // Clone it to avoid synchronization during dispatching
501 dispatchers = new Vector(dispatchers);
502 }
503 }
504 if (dispatchers != null) {
505 Iterator iter = dispatchers.iterator();
506 while (iter.hasNext()) {
507 XEventDispatcher disp = (XEventDispatcher)iter.next();
508 disp.dispatchEvent(ev);
509 }
510 }
511 notifyListeners(ev);
512 }
513
514 static void processException(Throwable thr) {
515 if (log.isLoggable(PlatformLogger.Level.WARNING)) {
516 log.warning("Exception on Toolkit thread", thr);
517 }
518 }
519
520 static native void awt_toolkit_init();
521
522 public void run() {
523 awt_toolkit_init();
524 run(PRIMARY_LOOP);
525 }
526
527 public void run(boolean loop)
528 {
529 XEvent ev = new XEvent();
530 while(true) {
531 // Fix for 6829923: we should gracefully handle toolkit thread interruption
532 if (Thread.currentThread().isInterrupted()) {
533 // We expect interruption from the AppContext.dispose() method only.
534 // If the thread is interrupted from another place, let's skip it
535 // for compatibility reasons. Probably some time later we'll remove
536 // the check for AppContext.isDisposed() and will unconditionally
537 // break the loop here.
538 if (AppContext.getAppContext().isDisposed()) {
539 break;
540 }
541 }
542 awtLock();
543 try {
544 if (loop == SECONDARY_LOOP) {
545 // In the secondary loop we may have already acquired awt_lock
546 // several times, so waitForEvents() might be unable to release
547 // the awt_lock and this causes lock up.
548 // For now, we just avoid waitForEvents in the secondary loop.
549 if (!XlibWrapper.XNextSecondaryLoopEvent(getDisplay(),ev.pData)) {
550 break;
551 }
552 } else {
553 callTimeoutTasks();
554 // If no events are queued, waitForEvents() causes calls to
555 // awtUnlock(), awtJNI_ThreadYield, poll, awtLock(),
556 // so it spends most of its time in poll, without holding the lock.
557 while ((XlibWrapper.XEventsQueued(getDisplay(), XConstants.QueuedAfterReading) == 0) &&
558 (XlibWrapper.XEventsQueued(getDisplay(), XConstants.QueuedAfterFlush) == 0)) {
559 callTimeoutTasks();
560 waitForEvents(getNextTaskTime());
561 }
562 XlibWrapper.XNextEvent(getDisplay(),ev.pData);
563 }
564
565 if (ev.get_type() != XConstants.NoExpose) {
566 eventNumber++;
567 }
568 if (awt_UseXKB_Calls && ev.get_type() == awt_XKBBaseEventCode) {
569 processXkbChanges(ev);
570 }
571
572 if (XDropTargetEventProcessor.processEvent(ev) ||
573 XDragSourceContextPeer.processEvent(ev)) {
574 continue;
575 }
576
577 if (eventLog.isLoggable(PlatformLogger.Level.FINER)) {
578 eventLog.finer("{0}", ev);
579 }
580
581 // Check if input method consumes the event
582 long w = 0;
583 if (windowToXWindow(ev.get_xany().get_window()) != null) {
584 Component owner =
585 XKeyboardFocusManagerPeer.getInstance().getCurrentFocusOwner();
586 if (owner != null) {
587 XWindow ownerWindow = (XWindow) AWTAccessor.getComponentAccessor().getPeer(owner);
588 if (ownerWindow != null) {
589 w = ownerWindow.getContentWindow();
590 }
591 }
592 }
593 if( keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (ev.get_type() == XConstants.KeyPress || ev.get_type() == XConstants.KeyRelease) ) {
594 keyEventLog.fine("before XFilterEvent:"+ev);
595 }
596 if (XlibWrapper.XFilterEvent(ev.getPData(), w)) {
597 continue;
598 }
599 if( keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (ev.get_type() == XConstants.KeyPress || ev.get_type() == XConstants.KeyRelease) ) {
600 keyEventLog.fine("after XFilterEvent:"+ev); // IS THIS CORRECT?
601 }
602
603 dispatchEvent(ev);
604 } catch (ThreadDeath td) {
605 XBaseWindow.ungrabInput();
606 return;
607 } catch (Throwable thr) {
608 XBaseWindow.ungrabInput();
609 processException(thr);
610 } finally {
611 awtUnlock();
612 }
613 }
614 }
615
616 static {
617 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
618 if (ge instanceof SunGraphicsEnvironment) {
619 ((SunGraphicsEnvironment)ge).addDisplayChangedListener(
620 new DisplayChangedListener() {
621 @Override
622 public void displayChanged() {
623 // 7045370: Reset the cached values
624 XToolkit.screenWidth = -1;
625 XToolkit.screenHeight = -1;
626 }
627
628 @Override
629 public void paletteChanged() {}
630 });
631 }
632 }
633
634 private static void initScreenSize() {
635 if (screenWidth == -1 || screenHeight == -1) {
636 awtLock();
637 try {
638 XWindowAttributes pattr = new XWindowAttributes();
639 try {
640 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), pattr.pData);
641 screenWidth = pattr.get_width();
642 screenHeight = pattr.get_height();
643 } finally {
644 pattr.dispose();
645 }
646 } finally {
647 awtUnlock();
648 }
649 }
650 }
651
652 static int getDefaultScreenWidth() {
653 initScreenSize();
654 return screenWidth;
655 }
656
657 static int getDefaultScreenHeight() {
658 initScreenSize();
659 return screenHeight;
660 }
661
662 protected int getScreenWidth() {
663 return getDefaultScreenWidth();
664 }
665
666 protected int getScreenHeight() {
667 return getDefaultScreenHeight();
668 }
669
670 private static Rectangle getWorkArea(long root)
671 {
672 XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA");
673
674 long native_ptr = Native.allocateLongArray(4);
675 try
676 {
677 boolean workareaPresent = XA_NET_WORKAREA.getAtomData(root,
678 XAtom.XA_CARDINAL, native_ptr, 4);
679 if (workareaPresent)
680 {
681 int rootX = (int)Native.getLong(native_ptr, 0);
682 int rootY = (int)Native.getLong(native_ptr, 1);
683 int rootWidth = (int)Native.getLong(native_ptr, 2);
684 int rootHeight = (int)Native.getLong(native_ptr, 3);
685
686 return new Rectangle(rootX, rootY, rootWidth, rootHeight);
687 }
688 }
689 finally
690 {
691 XlibWrapper.unsafe.freeMemory(native_ptr);
692 }
693
694 return null;
695 }
696
697 /*
698 * If we're running in non-Xinerama environment and the current
699 * window manager supports _NET protocol then the screen insets
700 * are calculated using _NET_WM_WORKAREA property of the root
701 * window.
702 * Otherwise, i. e. if Xinerama is on or _NET_WM_WORKAREA is
703 * not set, we try to calculate the insets ourselves using
704 * getScreenInsetsManually method.
705 */
706 public Insets getScreenInsets(GraphicsConfiguration gc)
707 {
708 XNETProtocol netProto = XWM.getWM().getNETProtocol();
709 if ((netProto == null) || !netProto.active())
710 {
711 return super.getScreenInsets(gc);
712 }
713
714 XToolkit.awtLock();
715 try
716 {
717 X11GraphicsConfig x11gc = (X11GraphicsConfig)gc;
718 X11GraphicsDevice x11gd = (X11GraphicsDevice)x11gc.getDevice();
719 long root = XlibUtil.getRootWindow(x11gd.getScreen());
720 Rectangle rootBounds = XlibUtil.getWindowGeometry(root);
721
722 X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment)
723 GraphicsEnvironment.getLocalGraphicsEnvironment();
724 if (!x11ge.runningXinerama())
725 {
726 Rectangle workArea = XToolkit.getWorkArea(root);
727 if (workArea != null)
728 {
729 return new Insets(workArea.y,
730 workArea.x,
731 rootBounds.height - workArea.height - workArea.y,
732 rootBounds.width - workArea.width - workArea.x);
733 }
734 }
735
736 return getScreenInsetsManually(root, rootBounds, gc.getBounds());
737 }
738 finally
739 {
740 XToolkit.awtUnlock();
741 }
742 }
743
744 /*
745 * Manual calculation of screen insets: get all the windows with
746 * _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL hints and add these
747 * hints' values to screen insets.
748 *
749 * This method should be called under XToolkit.awtLock()
750 */
751 private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds)
752 {
753 /*
754 * During the manual calculation of screen insets we iterate
755 * all the X windows hierarchy starting from root window. This
756 * constant is the max level inspected in this hierarchy.
757 * 3 is a heuristic value: I suppose any the toolbar-like
758 * window is a child of either root or desktop window.
759 */
760 final int MAX_NESTED_LEVEL = 3;
761
762 XAtom XA_NET_WM_STRUT = XAtom.get("_NET_WM_STRUT");
763 XAtom XA_NET_WM_STRUT_PARTIAL = XAtom.get("_NET_WM_STRUT_PARTIAL");
764
765 Insets insets = new Insets(0, 0, 0, 0);
766
767 java.util.List search = new LinkedList();
768 search.add(root);
769 search.add(0);
770 while (!search.isEmpty())
771 {
772 long window = (Long)search.remove(0);
773 int windowLevel = (Integer)search.remove(0);
774
775 /*
776 * Note that most of the modern window managers unmap
777 * application window if it is iconified. Thus, any
778 * _NET_WM_STRUT[_PARTIAL] hints for iconified windows
779 * are not included to the screen insets.
780 */
781 if (XlibUtil.getWindowMapState(window) == XConstants.IsUnmapped)
782 {
783 continue;
784 }
785
786 long native_ptr = Native.allocateLongArray(4);
787 try
788 {
789 // first, check if _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL are present
790 // if both are set on the window, _NET_WM_STRUT_PARTIAL is used (see _NET spec)
791 boolean strutPresent = XA_NET_WM_STRUT_PARTIAL.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
792 if (!strutPresent)
793 {
794 strutPresent = XA_NET_WM_STRUT.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
795 }
796 if (strutPresent)
797 {
798 // second, verify that window is located on the proper screen
799 Rectangle windowBounds = XlibUtil.getWindowGeometry(window);
800 if (windowLevel > 1)
801 {
802 windowBounds = XlibUtil.translateCoordinates(window, root, windowBounds);
803 }
804 // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect
805 // if the struts area intersects with screenBounds, however some window
806 // managers don't set this hint correctly, so we just get intersection with windowBounds
807 if (windowBounds != null && windowBounds.intersects(screenBounds))
808 {
809 int left = (int)Native.getLong(native_ptr, 0);
810 int right = (int)Native.getLong(native_ptr, 1);
811 int top = (int)Native.getLong(native_ptr, 2);
812 int bottom = (int)Native.getLong(native_ptr, 3);
813
814 /*
815 * struts could be relative to root window bounds, so
816 * make them relative to the screen bounds in this case
817 */
818 left = rootBounds.x + left > screenBounds.x ?
819 rootBounds.x + left - screenBounds.x : 0;
820 right = rootBounds.x + rootBounds.width - right <
821 screenBounds.x + screenBounds.width ?
822 screenBounds.x + screenBounds.width -
823 (rootBounds.x + rootBounds.width - right) : 0;
824 top = rootBounds.y + top > screenBounds.y ?
825 rootBounds.y + top - screenBounds.y : 0;
826 bottom = rootBounds.y + rootBounds.height - bottom <
827 screenBounds.y + screenBounds.height ?
828 screenBounds.y + screenBounds.height -
829 (rootBounds.y + rootBounds.height - bottom) : 0;
830
831 insets.left = Math.max(left, insets.left);
832 insets.right = Math.max(right, insets.right);
833 insets.top = Math.max(top, insets.top);
834 insets.bottom = Math.max(bottom, insets.bottom);
835 }
836 }
837 }
838 finally
839 {
840 XlibWrapper.unsafe.freeMemory(native_ptr);
841 }
842
843 if (windowLevel < MAX_NESTED_LEVEL)
844 {
845 Set<Long> children = XlibUtil.getChildWindows(window);
846 for (long child : children)
847 {
848 search.add(child);
849 search.add(windowLevel + 1);
850 }
851 }
852 }
853
854 return insets;
855 }
856
857 /*
858 * The current implementation of disabling background erasing for
859 * canvases is that we don't set any native background color
860 * (with XSetWindowBackground) for the canvas window. However,
861 * this color is set in the peer constructor - see
862 * XWindow.postInit() for details. That's why this method from
863 * SunToolkit is not overridden in XToolkit: it's too late to
864 * disable background erasing :(
865 */
866 /*
867 @Override
868 public void disableBackgroundErase(Canvas canvas) {
869 XCanvasPeer peer = (XCanvasPeer)canvas.getPeer();
870 if (peer == null) {
871 throw new IllegalStateException("Canvas must have a valid peer");
872 }
873 peer.disableBackgroundErase();
874 }
875 */
876
877 // Need this for XMenuItemPeer.
878 protected static final Object targetToPeer(Object target) {
879 Object p=null;
880 if (target != null && !GraphicsEnvironment.isHeadless()) {
881 p = specialPeerMap.get(target);
882 }
883 if (p != null) return p;
884 else
885 return SunToolkit.targetToPeer(target);
886 }
887
888 // Need this for XMenuItemPeer.
889 protected static final void targetDisposedPeer(Object target, Object peer) {
890 SunToolkit.targetDisposedPeer(target, peer);
891 }
892
893 public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
894 return new XRobotPeer(screen.getDefaultConfiguration());
895 }
896
897
898 /*
899 * On X, support for dynamic layout on resizing is governed by the
900 * window manager. If the window manager supports it, it happens
901 * automatically. The setter method for this property is
902 * irrelevant on X.
903 */
904 public void setDynamicLayout(boolean b) {
905 dynamicLayoutSetting = b;
906 }
907
908 protected boolean isDynamicLayoutSet() {
909 return dynamicLayoutSetting;
910 }
911
912 /* Called from isDynamicLayoutActive() and from
913 * lazilyLoadDynamicLayoutSupportedProperty()
914 */
915 protected boolean isDynamicLayoutSupported() {
916 return XWM.getWM().supportsDynamicLayout();
917 }
918
919 public boolean isDynamicLayoutActive() {
920 return isDynamicLayoutSupported();
921 }
922
923
924 public FontPeer getFontPeer(String name, int style){
925 return new XFontPeer(name, style);
926 }
927
928 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
929 return XDragSourceContextPeer.createDragSourceContextPeer(dge);
930 }
931
932 public <T extends DragGestureRecognizer> T
933 createDragGestureRecognizer(Class<T> recognizerClass,
934 DragSource ds,
935 Component c,
936 int srcActions,
937 DragGestureListener dgl)
938 {
939 if (MouseDragGestureRecognizer.class.equals(recognizerClass))
940 return (T)new XMouseDragGestureRecognizer(ds, c, srcActions, dgl);
941 else
942 return null;
943 }
944
945 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
946 XCheckboxMenuItemPeer peer = new XCheckboxMenuItemPeer(target);
947 //vb157120: looks like we don't need to map menu items
948 //in new menus implementation
949 //targetCreatedPeer(target, peer);
950 return peer;
951 }
952
953 public MenuItemPeer createMenuItem(MenuItem target) {
954 XMenuItemPeer peer = new XMenuItemPeer(target);
955 //vb157120: looks like we don't need to map menu items
956 //in new menus implementation
957 //targetCreatedPeer(target, peer);
958 return peer;
959 }
960
961 public TextFieldPeer createTextField(TextField target) {
962 TextFieldPeer peer = new XTextFieldPeer(target);
963 targetCreatedPeer(target, peer);
964 return peer;
965 }
966
967 public LabelPeer createLabel(Label target) {
968 LabelPeer peer = new XLabelPeer(target);
969 targetCreatedPeer(target, peer);
970 return peer;
971 }
972
973 public ListPeer createList(java.awt.List target) {
974 ListPeer peer = new XListPeer(target);
975 targetCreatedPeer(target, peer);
976 return peer;
977 }
978
979 public CheckboxPeer createCheckbox(Checkbox target) {
980 CheckboxPeer peer = new XCheckboxPeer(target);
981 targetCreatedPeer(target, peer);
982 return peer;
983 }
984
985 public ScrollbarPeer createScrollbar(Scrollbar target) {
986 XScrollbarPeer peer = new XScrollbarPeer(target);
987 targetCreatedPeer(target, peer);
988 return peer;
989 }
990
991 public ScrollPanePeer createScrollPane(ScrollPane target) {
992 XScrollPanePeer peer = new XScrollPanePeer(target);
993 targetCreatedPeer(target, peer);
994 return peer;
995 }
996
997 public TextAreaPeer createTextArea(TextArea target) {
998 TextAreaPeer peer = new XTextAreaPeer(target);
999 targetCreatedPeer(target, peer);
1000 return peer;
1001 }
1002
1003 public ChoicePeer createChoice(Choice target) {
1004 XChoicePeer peer = new XChoicePeer(target);
1005 targetCreatedPeer(target, peer);
1006 return peer;
1007 }
1008
1009 public CanvasPeer createCanvas(Canvas target) {
1010 XCanvasPeer peer = (isXEmbedServerRequested() ? new XEmbedCanvasPeer(target) : new XCanvasPeer(target));
1011 targetCreatedPeer(target, peer);
1012 return peer;
1013 }
1014
1015 public PanelPeer createPanel(Panel target) {
1016 PanelPeer peer = new XPanelPeer(target);
1017 targetCreatedPeer(target, peer);
1018 return peer;
1019 }
1020
1021 public WindowPeer createWindow(Window target) {
1022 WindowPeer peer = new XWindowPeer(target);
1023 targetCreatedPeer(target, peer);
1024 return peer;
1025 }
1026
1027 public DialogPeer createDialog(Dialog target) {
1028 DialogPeer peer = new XDialogPeer(target);
1029 targetCreatedPeer(target, peer);
1030 return peer;
1031 }
1032
1033 private static Boolean sunAwtDisableGtkFileDialogs = null;
1034
1035 /**
1036 * Returns the value of "sun.awt.disableGtkFileDialogs" property. Default
1037 * value is {@code false}.
1038 */
1039 public synchronized static boolean getSunAwtDisableGtkFileDialogs() {
1040 if (sunAwtDisableGtkFileDialogs == null) {
1041 sunAwtDisableGtkFileDialogs = AccessController.doPrivileged(
1042 new GetBooleanAction("sun.awt.disableGtkFileDialogs"));
1043 }
1044 return sunAwtDisableGtkFileDialogs.booleanValue();
1045 }
1046
1047 public FileDialogPeer createFileDialog(FileDialog target) {
1048 FileDialogPeer peer = null;
1049 // The current GtkFileChooser is available from GTK+ 2.4
1050 if (!getSunAwtDisableGtkFileDialogs() && checkGtkVersion(2, 4, 0)) {
1051 peer = new GtkFileDialogPeer(target);
1052 } else {
1053 peer = new XFileDialogPeer(target);
1054 }
1055 targetCreatedPeer(target, peer);
1056 return peer;
1057 }
1058
1059 public MenuBarPeer createMenuBar(MenuBar target) {
1060 XMenuBarPeer peer = new XMenuBarPeer(target);
1061 targetCreatedPeer(target, peer);
1062 return peer;
1063 }
1064
1065 public MenuPeer createMenu(Menu target) {
1066 XMenuPeer peer = new XMenuPeer(target);
1067 //vb157120: looks like we don't need to map menu items
1068 //in new menus implementation
1069 //targetCreatedPeer(target, peer);
1070 return peer;
1071 }
1072
1073 public PopupMenuPeer createPopupMenu(PopupMenu target) {
1074 XPopupMenuPeer peer = new XPopupMenuPeer(target);
1075 targetCreatedPeer(target, peer);
1076 return peer;
1077 }
1078
1079 public synchronized MouseInfoPeer getMouseInfoPeer() {
1080 if (xPeer == null) {
1081 xPeer = new XMouseInfoPeer();
1082 }
1083 return xPeer;
1084 }
1085
1086 public XEmbeddedFramePeer createEmbeddedFrame(XEmbeddedFrame target)
1087 {
1088 XEmbeddedFramePeer peer = new XEmbeddedFramePeer(target);
1089 targetCreatedPeer(target, peer);
1090 return peer;
1091 }
1092
1093 XEmbedChildProxyPeer createEmbedProxy(XEmbedChildProxy target) {
1094 XEmbedChildProxyPeer peer = new XEmbedChildProxyPeer(target);
1095 targetCreatedPeer(target, peer);
1096 return peer;
1097 }
1098
1099 public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() throws HeadlessException {
1100 return XKeyboardFocusManagerPeer.getInstance();
1101 }
1102
1103 /**
1104 * Returns a new custom cursor.
1105 */
1106 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name)
1107 throws IndexOutOfBoundsException {
1108 return new XCustomCursor(cursor, hotSpot, name);
1109 }
1110
1111 public TrayIconPeer createTrayIcon(TrayIcon target)
1112 throws HeadlessException, AWTException
1113 {
1114 TrayIconPeer peer = new XTrayIconPeer(target);
1115 targetCreatedPeer(target, peer);
1116 return peer;
1117 }
1118
1119 public SystemTrayPeer createSystemTray(SystemTray target) throws HeadlessException {
1120 SystemTrayPeer peer = new XSystemTrayPeer(target);
1121 return peer;
1122 }
1123
1124 public boolean isTraySupported() {
1125 XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance();
1126 if (peer != null) {
1127 return peer.isAvailable();
1128 }
1129 return false;
1130 }
1131
1132 @Override
1133 public DataTransferer getDataTransferer() {
1134 return XDataTransferer.getInstanceImpl();
1135 }
1136
1137 /**
1138 * Returns the supported cursor size
1139 */
1140 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) {
1141 return XCustomCursor.getBestCursorSize(
1142 java.lang.Math.max(1,preferredWidth), java.lang.Math.max(1,preferredHeight));
1143 }
1144
1145
1146 public int getMaximumCursorColors() {
1147 return 2; // Black and white.
1148 }
1149
1150 public Map mapInputMethodHighlight(InputMethodHighlight highlight) {
1151 return XInputMethod.mapInputMethodHighlight(highlight);
1152 }
1153 @Override
1154 public boolean getLockingKeyState(int key) {
1155 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK ||
1156 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) {
1157 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
1158 }
1159 awtLock();
1160 try {
1161 return getModifierState( key );
1162 } finally {
1163 awtUnlock();
1164 }
1165 }
1166
1167 public Clipboard getSystemClipboard() {
1168 SecurityManager security = System.getSecurityManager();
1169 if (security != null) {
1170 security.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
1171 }
1172 synchronized (this) {
1173 if (clipboard == null) {
1174 clipboard = new XClipboard("System", "CLIPBOARD");
1175 }
1176 }
1177 return clipboard;
1178 }
1179
1180 public Clipboard getSystemSelection() {
1181 SecurityManager security = System.getSecurityManager();
1182 if (security != null) {
1183 security.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
1184 }
1185 synchronized (this) {
1186 if (selection == null) {
1187 selection = new XClipboard("Selection", "PRIMARY");
1188 }
1189 }
1190 return selection;
1191 }
1192
1193 public void beep() {
1194 awtLock();
1195 try {
1196 XlibWrapper.XBell(getDisplay(), 0);
1197 XlibWrapper.XFlush(getDisplay());
1198 } finally {
1199 awtUnlock();
1200 }
1201 }
1202
1203 public PrintJob getPrintJob(final Frame frame, final String doctitle,
1204 final Properties props) {
1205
1206 if (frame == null) {
1207 throw new NullPointerException("frame must not be null");
1208 }
1209
1210 PrintJob2D printJob = new PrintJob2D(frame, doctitle, props);
1211
1212 if (printJob.printDialog() == false) {
1213 printJob = null;
1214 }
1215 return printJob;
1216 }
1217
1218 public PrintJob getPrintJob(final Frame frame, final String doctitle,
1219 final JobAttributes jobAttributes,
1220 final PageAttributes pageAttributes)
1221 {
1222 if (frame == null) {
1223 throw new NullPointerException("frame must not be null");
1224 }
1225
1226 PrintJob2D printJob = new PrintJob2D(frame, doctitle,
1227 jobAttributes, pageAttributes);
1228
1229 if (printJob.printDialog() == false) {
1230 printJob = null;
1231 }
1232
1233 return printJob;
1234 }
1235
1236 static void XSync() {
1237 awtLock();
1238 try {
1239 XlibWrapper.XSync(getDisplay(),0);
1240 } finally {
1241 awtUnlock();
1242 }
1243 }
1244
1245 public int getScreenResolution() {
1246 long display = getDisplay();
1247 awtLock();
1248 try {
1249 return (int) ((XlibWrapper.DisplayWidth(display,
1250 XlibWrapper.DefaultScreen(display)) * 25.4) /
1251 XlibWrapper.DisplayWidthMM(display,
1252 XlibWrapper.DefaultScreen(display)));
1253 } finally {
1254 awtUnlock();
1255 }
1256 }
1257
1258 static native long getDefaultXColormap();
1259 static native long getDefaultScreenData();
1260
1261 static ColorModel screenmodel;
1262
1263 static ColorModel getStaticColorModel() {
1264 if (screenmodel == null) {
1265 screenmodel = config.getColorModel ();
1266 }
1267 return screenmodel;
1268 }
1269
1270 public ColorModel getColorModel() {
1271 return getStaticColorModel();
1272 }
1273
1274 /**
1275 * Returns a new input method adapter descriptor for native input methods.
1276 */
1277 public InputMethodDescriptor getInputMethodAdapterDescriptor() throws AWTException {
1278 return new XInputMethodDescriptor();
1279 }
1280
1281 /**
1282 * Returns whether enableInputMethods should be set to true for peered
1283 * TextComponent instances on this platform. True by default.
1284 */
1285 @Override
1286 public boolean enableInputMethodsForTextComponent() {
1287 return true;
1288 }
1289
1290 static int getMultiClickTime() {
1291 if (awt_multiclick_time == 0) {
1292 initializeMultiClickTime();
1293 }
1294 return awt_multiclick_time;
1295 }
1296 static void initializeMultiClickTime() {
1297 awtLock();
1298 try {
1299 try {
1300 String multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(), "*", "multiClickTime");
1301 if (multiclick_time_query != null) {
1302 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query);
1303 } else {
1304 multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(),
1305 "OpenWindows", "MultiClickTimeout");
1306 if (multiclick_time_query != null) {
1307 /* Note: OpenWindows.MultiClickTimeout is in tenths of
1308 a second, so we need to multiply by 100 to convert to
1309 milliseconds */
1310 awt_multiclick_time = (int)Long.parseLong(multiclick_time_query) * 100;
1311 } else {
1312 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1313 }
1314 }
1315 } catch (NumberFormatException nf) {
1316 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1317 } catch (NullPointerException npe) {
1318 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1319 }
1320 } finally {
1321 awtUnlock();
1322 }
1323 if (awt_multiclick_time == 0) {
1324 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1325 }
1326 }
1327
1328 public boolean isFrameStateSupported(int state)
1329 throws HeadlessException
1330 {
1331 if (state == Frame.NORMAL || state == Frame.ICONIFIED) {
1332 return true;
1333 } else {
1334 return XWM.getWM().supportsExtendedState(state);
1335 }
1336 }
1337
1338 static void dumpPeers() {
1339 if (log.isLoggable(PlatformLogger.Level.FINE)) {
1340 log.fine("Mapped windows:");
1341 Iterator iter = winMap.entrySet().iterator();
1342 while (iter.hasNext()) {
1343 Map.Entry entry = (Map.Entry)iter.next();
1344 log.fine(entry.getKey() + "->" + entry.getValue());
1345 if (entry.getValue() instanceof XComponentPeer) {
1346 Component target = (Component)((XComponentPeer)entry.getValue()).getTarget();
1347 log.fine("\ttarget: " + target);
1348 }
1349 }
1350
1351 SunToolkit.dumpPeers(log);
1352
1353 log.fine("Mapped special peers:");
1354 iter = specialPeerMap.entrySet().iterator();
1355 while (iter.hasNext()) {
1356 Map.Entry entry = (Map.Entry)iter.next();
1357 log.fine(entry.getKey() + "->" + entry.getValue());
1358 }
1359
1360 log.fine("Mapped dispatchers:");
1361 iter = winToDispatcher.entrySet().iterator();
1362 while (iter.hasNext()) {
1363 Map.Entry entry = (Map.Entry)iter.next();
1364 log.fine(entry.getKey() + "->" + entry.getValue());
1365 }
1366 }
1367 }
1368
1369 /* Protected with awt_lock. */
1370 private static boolean initialized;
1371 private static boolean timeStampUpdated;
1372 private static long timeStamp;
1373
1374 private static final XEventDispatcher timeFetcher =
1375 new XEventDispatcher() {
1376 public void dispatchEvent(XEvent ev) {
1377 switch (ev.get_type()) {
1378 case XConstants.PropertyNotify:
1379 XPropertyEvent xpe = ev.get_xproperty();
1380
1381 awtLock();
1382 try {
1383 timeStamp = xpe.get_time();
1384 timeStampUpdated = true;
1385 awtLockNotifyAll();
1386 } finally {
1387 awtUnlock();
1388 }
1389
1390 break;
1391 }
1392 }
1393 };
1394
1395 private static XAtom _XA_JAVA_TIME_PROPERTY_ATOM;
1396
1397 static long getCurrentServerTime() {
1398 awtLock();
1399 try {
1400 try {
1401 if (!initialized) {
1402 XToolkit.addEventDispatcher(XBaseWindow.getXAWTRootWindow().getWindow(),
1403 timeFetcher);
1404 _XA_JAVA_TIME_PROPERTY_ATOM = XAtom.get("_SUNW_JAVA_AWT_TIME");
1405 initialized = true;
1406 }
1407 timeStampUpdated = false;
1408 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
1409 XBaseWindow.getXAWTRootWindow().getWindow(),
1410 _XA_JAVA_TIME_PROPERTY_ATOM.getAtom(), XAtom.XA_ATOM, 32,
1411 XConstants.PropModeAppend,
1412 0, 0);
1413 XlibWrapper.XFlush(XToolkit.getDisplay());
1414
1415 if (isToolkitThread()) {
1416 XEvent event = new XEvent();
1417 try {
1418 XlibWrapper.XWindowEvent(XToolkit.getDisplay(),
1419 XBaseWindow.getXAWTRootWindow().getWindow(),
1420 XConstants.PropertyChangeMask,
1421 event.pData);
1422 timeFetcher.dispatchEvent(event);
1423 }
1424 finally {
1425 event.dispose();
1426 }
1427 }
1428 else {
1429 while (!timeStampUpdated) {
1430 awtLockWait();
1431 }
1432 }
1433 } catch (InterruptedException ie) {
1434 // Note: the returned timeStamp can be incorrect in this case.
1435 if (log.isLoggable(PlatformLogger.Level.FINE)) {
1436 log.fine("Catched exception, timeStamp may not be correct (ie = " + ie + ")");
1437 }
1438 }
1439 } finally {
1440 awtUnlock();
1441 }
1442 return timeStamp;
1443 }
1444 protected void initializeDesktopProperties() {
1445 desktopProperties.put("DnD.Autoscroll.initialDelay",
1446 Integer.valueOf(50));
1447 desktopProperties.put("DnD.Autoscroll.interval",
1448 Integer.valueOf(50));
1449 desktopProperties.put("DnD.Autoscroll.cursorHysteresis",
1450 Integer.valueOf(5));
1451 desktopProperties.put("Shell.shellFolderManager",
1452 "sun.awt.shell.ShellFolderManager");
1453 // Don't want to call getMultiClickTime() if we are headless
1454 if (!GraphicsEnvironment.isHeadless()) {
1455 desktopProperties.put("awt.multiClickInterval",
1456 Integer.valueOf(getMultiClickTime()));
1457 desktopProperties.put("awt.mouse.numButtons",
1458 Integer.valueOf(getNumberOfButtons()));
1459 }
1460 }
1461
1462 /**
1463 * This method runs through the XPointer and XExtendedPointer array.
1464 * XExtendedPointer has priority because on some systems XPointer
1465 * (which is assigned to the virtual pointer) reports the maximum
1466 * capabilities of the mouse pointer (i.e. 32 physical buttons).
1467 */
1468 private native int getNumberOfButtonsImpl();
1469
1470 @Override
1471 public int getNumberOfButtons(){
1472 awtLock();
1473 try {
1474 if (numberOfButtons == 0) {
1475 numberOfButtons = getNumberOfButtonsImpl();
1476 numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
1477 //4th and 5th buttons are for wheel and shouldn't be reported as buttons.
1478 //If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
1479 //If we have 3 physical buttons and a wheel, we report 3 buttons.
1480 //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
1481 if (numberOfButtons >=5) {
1482 numberOfButtons -= 2;
1483 } else if (numberOfButtons == 4 || numberOfButtons ==5){
1484 numberOfButtons = 3;
1485 }
1486 }
1487 //Assume don't have to re-query the number again and again.
1488 return numberOfButtons;
1489 } finally {
1490 awtUnlock();
1491 }
1492 }
1493
1494 static int getNumberOfButtonsForMask() {
1495 return Math.min(XConstants.MAX_BUTTONS, ((SunToolkit) (Toolkit.getDefaultToolkit())).getNumberOfButtons());
1496 }
1497
1498 private final static String prefix = "DnD.Cursor.";
1499 private final static String postfix = ".32x32";
1500 private static final String dndPrefix = "DnD.";
1501
1502 protected Object lazilyLoadDesktopProperty(String name) {
1503 if (name.startsWith(prefix)) {
1504 String cursorName = name.substring(prefix.length(), name.length()) + postfix;
1505
1506 try {
1507 return Cursor.getSystemCustomCursor(cursorName);
1508 } catch (AWTException awte) {
1509 throw new RuntimeException("cannot load system cursor: " + cursorName, awte);
1510 }
1511 }
1512
1513 if (name.equals("awt.dynamicLayoutSupported")) {
1514 return Boolean.valueOf(isDynamicLayoutSupported());
1515 }
1516
1517 if (initXSettingsIfNeeded(name)) {
1518 return desktopProperties.get(name);
1519 }
1520
1521 return super.lazilyLoadDesktopProperty(name);
1522 }
1523
1524 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
1525 if (name == null) {
1526 // See JavaDoc for the Toolkit.addPropertyChangeListener() method
1527 return;
1528 }
1529 initXSettingsIfNeeded(name);
1530 super.addPropertyChangeListener(name, pcl);
1531 }
1532
1533 /**
1534 * Initializes XAWTXSettings if a property for a given property name is provided by
1535 * XSettings and they are not initialized yet.
1536 *
1537 * @return true if the method has initialized XAWTXSettings.
1538 */
1539 private boolean initXSettingsIfNeeded(final String propName) {
1540 if (!loadedXSettings &&
1541 (propName.startsWith("gnome.") ||
1542 propName.equals(SunToolkit.DESKTOPFONTHINTS) ||
1543 propName.startsWith(dndPrefix)))
1544 {
1545 loadedXSettings = true;
1546 if (!GraphicsEnvironment.isHeadless()) {
1547 loadXSettings();
1548 /* If no desktop font hint could be retrieved, check for
1549 * KDE running KWin and retrieve settings from fontconfig.
1550 * If that isn't found let SunToolkit will see if there's a
1551 * system property set by a user.
1552 */
1553 if (desktopProperties.get(SunToolkit.DESKTOPFONTHINTS) == null) {
1554 if (XWM.isKDE2()) {
1555 Object hint = FontConfigManager.getFontConfigAAHint();
1556 if (hint != null) {
1557 /* set the fontconfig/KDE property so that
1558 * getDesktopHints() below will see it
1559 * and set the public property.
1560 */
1561 desktopProperties.put(UNIXToolkit.FONTCONFIGAAHINT,
1562 hint);
1563 }
1564 }
1565 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS,
1566 SunToolkit.getDesktopFontHints());
1567 }
1568
1569 return true;
1570 }
1571 }
1572 return false;
1573 }
1574
1575 private void loadXSettings() {
1576 xs = new XAWTXSettings();
1577 }
1578
1579 /**
1580 * Callback from the native side indicating some, or all, of the
1581 * desktop properties have changed and need to be reloaded.
1582 * <code>data</code> is the byte array directly from the x server and
1583 * may be in little endian format.
1584 * <p>
1585 * NB: This could be called from any thread if triggered by
1586 * <code>loadXSettings</code>. It is called from the System EDT
1587 * if triggered by an XSETTINGS change.
1588 */
1589 void parseXSettings(int screen_XXX_ignored,Map updatedSettings) {
1590
1591 if (updatedSettings == null || updatedSettings.isEmpty()) {
1592 return;
1593 }
1594
1595 Iterator i = updatedSettings.entrySet().iterator();
1596 while (i.hasNext()) {
1597 Map.Entry e = (Map.Entry)i.next();
1598 String name = (String)e.getKey();
1599
1600 name = "gnome." + name;
1601 setDesktopProperty(name, e.getValue());
1602 if (log.isLoggable(PlatformLogger.Level.FINE)) {
1603 log.fine("name = " + name + " value = " + e.getValue());
1604 }
1605
1606 // XXX: we probably want to do something smarter. In
1607 // particular, "Net" properties are of interest to the
1608 // "core" AWT itself. E.g.
1609 //
1610 // Net/DndDragThreshold -> ???
1611 // Net/DoubleClickTime -> awt.multiClickInterval
1612 }
1613
1614 setDesktopProperty(SunToolkit.DESKTOPFONTHINTS,
1615 SunToolkit.getDesktopFontHints());
1616
1617 Integer dragThreshold = null;
1618 synchronized (this) {
1619 dragThreshold = (Integer)desktopProperties.get("gnome.Net/DndDragThreshold");
1620 }
1621 if (dragThreshold != null) {
1622 setDesktopProperty("DnD.gestureMotionThreshold", dragThreshold);
1623 }
1624
1625 }
1626
1627
1628
1629 static int altMask;
1630 static int metaMask;
1631 static int numLockMask;
1632 static int modeSwitchMask;
1633 static int modLockIsShiftLock;
1634
1635 /* Like XKeysymToKeycode, but ensures that keysym is the primary
1636 * symbol on the keycode returned. Returns zero otherwise.
1637 */
1638 static int keysymToPrimaryKeycode(long sym) {
1639 awtLock();
1640 try {
1641 int code = XlibWrapper.XKeysymToKeycode(getDisplay(), sym);
1642 if (code == 0) {
1643 return 0;
1644 }
1645 long primary = XlibWrapper.XKeycodeToKeysym(getDisplay(), code, 0);
1646 if (sym != primary) {
1647 return 0;
1648 }
1649 return code;
1650 } finally {
1651 awtUnlock();
1652 }
1653 }
1654 static boolean getModifierState( int jkc ) {
1655 int iKeyMask = 0;
1656 long ks = XKeysym.javaKeycode2Keysym( jkc );
1657 int kc = XlibWrapper.XKeysymToKeycode(getDisplay(), ks);
1658 if (kc == 0) {
1659 return false;
1660 }
1661 awtLock();
1662 try {
1663 XModifierKeymap modmap = new XModifierKeymap(
1664 XlibWrapper.XGetModifierMapping(getDisplay()));
1665
1666 int nkeys = modmap.get_max_keypermod();
1667
1668 long map_ptr = modmap.get_modifiermap();
1669 for( int k = 0; k < 8; k++ ) {
1670 for (int i = 0; i < nkeys; ++i) {
1671 int keycode = Native.getUByte(map_ptr, k * nkeys + i);
1672 if (keycode == 0) {
1673 continue; // ignore zero keycode
1674 }
1675 if (kc == keycode) {
1676 iKeyMask = 1 << k;
1677 break;
1678 }
1679 }
1680 if( iKeyMask != 0 ) {
1681 break;
1682 }
1683 }
1684 XlibWrapper.XFreeModifiermap(modmap.pData);
1685 if (iKeyMask == 0 ) {
1686 return false;
1687 }
1688 // Now we know to which modifier is assigned the keycode
1689 // correspondent to the keysym correspondent to the java
1690 // keycode. We are going to check a state of this modifier.
1691 // If a modifier is a weird one, we cannot help it.
1692 long window = 0;
1693 try{
1694 // get any application window
1695 window = ((Long)(winMap.firstKey())).longValue();
1696 }catch(NoSuchElementException nex) {
1697 // get root window
1698 window = getDefaultRootWindow();
1699 }
1700 boolean res = XlibWrapper.XQueryPointer(getDisplay(), window,
1701 XlibWrapper.larg1, //root
1702 XlibWrapper.larg2, //child
1703 XlibWrapper.larg3, //root_x
1704 XlibWrapper.larg4, //root_y
1705 XlibWrapper.larg5, //child_x
1706 XlibWrapper.larg6, //child_y
1707 XlibWrapper.larg7);//mask
1708 int mask = Native.getInt(XlibWrapper.larg7);
1709 return ((mask & iKeyMask) != 0);
1710 } finally {
1711 awtUnlock();
1712 }
1713 }
1714
1715 /* Assign meaning - alt, meta, etc. - to X modifiers mod1 ... mod5.
1716 * Only consider primary symbols on keycodes attached to modifiers.
1717 */
1718 static void setupModifierMap() {
1719 final int metaL = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_L);
1720 final int metaR = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_R);
1721 final int altL = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_L);
1722 final int altR = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_R);
1723 final int numLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Num_Lock);
1724 final int modeSwitch = keysymToPrimaryKeycode(XKeySymConstants.XK_Mode_switch);
1725 final int shiftLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Shift_Lock);
1726 final int capsLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Caps_Lock);
1727
1728 final int modmask[] = { XConstants.ShiftMask, XConstants.LockMask, XConstants.ControlMask, XConstants.Mod1Mask,
1729 XConstants.Mod2Mask, XConstants.Mod3Mask, XConstants.Mod4Mask, XConstants.Mod5Mask };
1730
1731 log.fine("In setupModifierMap");
1732 awtLock();
1733 try {
1734 XModifierKeymap modmap = new XModifierKeymap(
1735 XlibWrapper.XGetModifierMapping(getDisplay()));
1736
1737 int nkeys = modmap.get_max_keypermod();
1738
1739 long map_ptr = modmap.get_modifiermap();
1740
1741 for (int modn = XConstants.Mod1MapIndex;
1742 modn <= XConstants.Mod5MapIndex;
1743 ++modn)
1744 {
1745 for (int i = 0; i < nkeys; ++i) {
1746 /* for each keycode attached to this modifier */
1747 int keycode = Native.getUByte(map_ptr, modn * nkeys + i);
1748
1749 if (keycode == 0) {
1750 break;
1751 }
1752 if (metaMask == 0 &&
1753 (keycode == metaL || keycode == metaR))
1754 {
1755 metaMask = modmask[modn];
1756 break;
1757 }
1758 if (altMask == 0 && (keycode == altL || keycode == altR)) {
1759 altMask = modmask[modn];
1760 break;
1761 }
1762 if (numLockMask == 0 && keycode == numLock) {
1763 numLockMask = modmask[modn];
1764 break;
1765 }
1766 if (modeSwitchMask == 0 && keycode == modeSwitch) {
1767 modeSwitchMask = modmask[modn];
1768 break;
1769 }
1770 continue;
1771 }
1772 }
1773 modLockIsShiftLock = 0;
1774 for (int j = 0; j < nkeys; ++j) {
1775 int keycode = Native.getUByte(map_ptr, XConstants.LockMapIndex * nkeys + j);
1776 if (keycode == 0) {
1777 break;
1778 }
1779 if (keycode == shiftLock) {
1780 modLockIsShiftLock = 1;
1781 break;
1782 }
1783 if (keycode == capsLock) {
1784 break;
1785 }
1786 }
1787 XlibWrapper.XFreeModifiermap(modmap.pData);
1788 } finally {
1789 awtUnlock();
1790 }
1791 if (log.isLoggable(PlatformLogger.Level.FINE)) {
1792 log.fine("metaMask = " + metaMask);
1793 log.fine("altMask = " + altMask);
1794 log.fine("numLockMask = " + numLockMask);
1795 log.fine("modeSwitchMask = " + modeSwitchMask);
1796 log.fine("modLockIsShiftLock = " + modLockIsShiftLock);
1797 }
1798 }
1799
1800
1801 private static SortedMap timeoutTasks;
1802
1803 /**
1804 * Removed the task from the list of waiting-to-be called tasks.
1805 * If the task has been scheduled several times removes only first one.
1806 */
1807 static void remove(Runnable task) {
1808 if (task == null) {
1809 throw new NullPointerException("task is null");
1810 }
1811 awtLock();
1812 try {
1813 if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1814 timeoutTaskLog.finer("Removing task " + task);
1815 }
1816 if (timeoutTasks == null) {
1817 if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1818 timeoutTaskLog.finer("Task is not scheduled");
1819 }
1820 return;
1821 }
1822 Collection values = timeoutTasks.values();
1823 Iterator iter = values.iterator();
1824 while (iter.hasNext()) {
1825 java.util.List list = (java.util.List)iter.next();
1826 boolean removed = false;
1827 if (list.contains(task)) {
1828 list.remove(task);
1829 if (list.isEmpty()) {
1830 iter.remove();
1831 }
1832 break;
1833 }
1834 }
1835 } finally {
1836 awtUnlock();
1837 }
1838 }
1839
1840 static native void wakeup_poll();
1841
1842 /**
1843 * Registers a Runnable which <code>run()</code> method will be called
1844 * once on the toolkit thread when a specified interval of time elapses.
1845 *
1846 * @param task a Runnable which <code>run</code> method will be called
1847 * on the toolkit thread when <code>interval</code> milliseconds
1848 * elapse
1849 * @param interval an interal in milliseconds
1850 *
1851 * @throws NullPointerException if <code>task</code> is <code>null</code>
1852 * @throws IllegalArgumentException if <code>interval</code> is not positive
1853 */
1854 static void schedule(Runnable task, long interval) {
1855 if (task == null) {
1856 throw new NullPointerException("task is null");
1857 }
1858 if (interval <= 0) {
1859 throw new IllegalArgumentException("interval " + interval + " is not positive");
1860 }
1861
1862 awtLock();
1863 try {
1864 if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1865 timeoutTaskLog.finer("XToolkit.schedule(): current time={0}" +
1866 "; interval={1}" +
1867 "; task being added={2}" + "; tasks before addition={3}",
1868 Long.valueOf(System.currentTimeMillis()), Long.valueOf(interval), task, timeoutTasks);
1869 }
1870
1871 if (timeoutTasks == null) {
1872 timeoutTasks = new TreeMap();
1873 }
1874
1875 Long time = Long.valueOf(System.currentTimeMillis() + interval);
1876 java.util.List tasks = (java.util.List)timeoutTasks.get(time);
1877 if (tasks == null) {
1878 tasks = new ArrayList(1);
1879 timeoutTasks.put(time, tasks);
1880 }
1881 tasks.add(task);
1882
1883
1884 if (timeoutTasks.get(timeoutTasks.firstKey()) == tasks && tasks.size() == 1) {
1885 // Added task became first task - poll won't know
1886 // about it so we need to wake it up
1887 wakeup_poll();
1888 }
1889 } finally {
1890 awtUnlock();
1891 }
1892 }
1893
1894 private long getNextTaskTime() {
1895 awtLock();
1896 try {
1897 if (timeoutTasks == null || timeoutTasks.isEmpty()) {
1898 return -1L;
1899 }
1900 return (Long)timeoutTasks.firstKey();
1901 } finally {
1902 awtUnlock();
1903 }
1904 }
1905
1906 /**
1907 * Executes mature timeout tasks registered with schedule().
1908 * Called from run() under awtLock.
1909 */
1910 private static void callTimeoutTasks() {
1911 if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1912 timeoutTaskLog.finer("XToolkit.callTimeoutTasks(): current time={0}" +
1913 "; tasks={1}", Long.valueOf(System.currentTimeMillis()), timeoutTasks);
1914 }
1915
1916 if (timeoutTasks == null || timeoutTasks.isEmpty()) {
1917 return;
1918 }
1919
1920 Long currentTime = Long.valueOf(System.currentTimeMillis());
1921 Long time = (Long)timeoutTasks.firstKey();
1922
1923 while (time.compareTo(currentTime) <= 0) {
1924 java.util.List tasks = (java.util.List)timeoutTasks.remove(time);
1925
1926 for (Iterator iter = tasks.iterator(); iter.hasNext();) {
1927 Runnable task = (Runnable)iter.next();
1928
1929 if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1930 timeoutTaskLog.finer("XToolkit.callTimeoutTasks(): current time={0}" +
1931 "; about to run task={1}", Long.valueOf(currentTime), task);
1932 }
1933
1934 try {
1935 task.run();
1936 } catch (ThreadDeath td) {
1937 throw td;
1938 } catch (Throwable thr) {
1939 processException(thr);
1940 }
1941 }
1942
1943 if (timeoutTasks.isEmpty()) {
1944 break;
1945 }
1946 time = (Long)timeoutTasks.firstKey();
1947 }
1948 }
1949
1950 static long getAwtDefaultFg() {
1951 return awt_defaultFg;
1952 }
1953
1954 static boolean isLeftMouseButton(MouseEvent me) {
1955 switch (me.getID()) {
1956 case MouseEvent.MOUSE_PRESSED:
1957 case MouseEvent.MOUSE_RELEASED:
1958 return (me.getButton() == MouseEvent.BUTTON1);
1959 case MouseEvent.MOUSE_ENTERED:
1960 case MouseEvent.MOUSE_EXITED:
1961 case MouseEvent.MOUSE_CLICKED:
1962 case MouseEvent.MOUSE_DRAGGED:
1963 return ((me.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0);
1964 }
1965 return false;
1966 }
1967
1968 static boolean isRightMouseButton(MouseEvent me) {
1969 int numButtons = ((Integer)getDefaultToolkit().getDesktopProperty("awt.mouse.numButtons")).intValue();
1970 switch (me.getID()) {
1971 case MouseEvent.MOUSE_PRESSED:
1972 case MouseEvent.MOUSE_RELEASED:
1973 return ((numButtons == 2 && me.getButton() == MouseEvent.BUTTON2) ||
1974 (numButtons > 2 && me.getButton() == MouseEvent.BUTTON3));
1975 case MouseEvent.MOUSE_ENTERED:
1976 case MouseEvent.MOUSE_EXITED:
1977 case MouseEvent.MOUSE_CLICKED:
1978 case MouseEvent.MOUSE_DRAGGED:
1979 return ((numButtons == 2 && (me.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) ||
1980 (numButtons > 2 && (me.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0));
1981 }
1982 return false;
1983 }
1984
1985 static long reset_time_utc;
1986 static final long WRAP_TIME_MILLIS = 0x00000000FFFFFFFFL;
1987
1988 /*
1989 * This function converts between the X server time (number of milliseconds
1990 * since the last server reset) and the UTC time for the 'when' field of an
1991 * InputEvent (or another event type with a timestamp).
1992 */
1993 static long nowMillisUTC_offset(long server_offset) {
1994 // ported from awt_util.c
1995 /*
1996 * Because Time is of type 'unsigned long', it is possible that Time will
1997 * never wrap when using 64-bit Xlib. However, if a 64-bit client
1998 * connects to a 32-bit server, I suspect the values will still wrap. So
1999 * we should not attempt to remove the wrap checking even if _LP64 is
2000 * true.
2001 */
2002
2003 long current_time_utc = System.currentTimeMillis();
2004 if (log.isLoggable(PlatformLogger.Level.FINER)) {
2005 log.finer("reset_time=" + reset_time_utc + ", current_time=" + current_time_utc
2006 + ", server_offset=" + server_offset + ", wrap_time=" + WRAP_TIME_MILLIS);
2007 }
2008
2009 if ((current_time_utc - reset_time_utc) > WRAP_TIME_MILLIS) {
2010 reset_time_utc = System.currentTimeMillis() - getCurrentServerTime();
2011 }
2012
2013 if (log.isLoggable(PlatformLogger.Level.FINER)) {
2014 log.finer("result = " + (reset_time_utc + server_offset));
2015 }
2016 return reset_time_utc + server_offset;
2017 }
2018
2019 /**
2020 * @see sun.awt.SunToolkit#needsXEmbedImpl
2021 */
2022 protected boolean needsXEmbedImpl() {
2023 // XToolkit implements supports for XEmbed-client protocol and
2024 // requires the supports from the embedding host for it to work.
2025 return true;
2026 }
2027
2028 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
2029 return (modalityType == null) ||
2030 (modalityType == Dialog.ModalityType.MODELESS) ||
2031 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
2032 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
2033 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
2034 }
2035
2036 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
2037 return (exclusionType == null) ||
2038 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
2039 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
2040 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
2041 }
2042
2043 static EventQueue getEventQueue(Object target) {
2044 AppContext appContext = targetToAppContext(target);
2045 if (appContext != null) {
2046 return (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
2047 }
2048 return null;
2049 }
2050
2051 static void removeSourceEvents(EventQueue queue,
2052 Object source,
2053 boolean removeAllEvents) {
2054 AWTAccessor.getEventQueueAccessor()
2055 .removeSourceEvents(queue, source, removeAllEvents);
2056 }
2057
2058 public boolean isAlwaysOnTopSupported() {
2059 for (XLayerProtocol proto : XWM.getWM().getProtocols(XLayerProtocol.class)) {
2060 if (proto.supportsLayer(XLayerProtocol.LAYER_ALWAYS_ON_TOP)) {
2061 return true;
2062 }
2063 }
2064 return false;
2065 }
2066
2067 public boolean useBufferPerWindow() {
2068 return XToolkit.getBackingStoreType() == XConstants.NotUseful;
2069 }
2070
2071 /**
2072 * Returns one of XConstants: NotUseful, WhenMapped or Always.
2073 * If backing store is not available on at least one screen, or
2074 * java2d uses DGA(which conflicts with backing store) on at least one screen,
2075 * or the string system property "sun.awt.backingStore" is neither "Always"
2076 * nor "WhenMapped", then the method returns XConstants.NotUseful.
2077 * Otherwise, if the system property "sun.awt.backingStore" is "WhenMapped",
2078 * then the method returns XConstants.WhenMapped.
2079 * Otherwise (i.e., if the system property "sun.awt.backingStore" is "Always"),
2080 * the method returns XConstants.Always.
2081 */
2082 static int getBackingStoreType() {
2083 return backingStoreType;
2084 }
2085
2086 private static void setBackingStoreType() {
2087 String prop = AccessController.doPrivileged(
2088 new sun.security.action.GetPropertyAction("sun.awt.backingStore"));
2089
2090 if (prop == null) {
2091 backingStoreType = XConstants.NotUseful;
2092 if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2093 backingStoreLog.config("The system property sun.awt.backingStore is not set" +
2094 ", by default backingStore=NotUseful");
2095 }
2096 return;
2097 }
2098
2099 if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2100 backingStoreLog.config("The system property sun.awt.backingStore is " + prop);
2101 }
2102 prop = prop.toLowerCase();
2103 if (prop.equals("always")) {
2104 backingStoreType = XConstants.Always;
2105 } else if (prop.equals("whenmapped")) {
2106 backingStoreType = XConstants.WhenMapped;
2107 } else {
2108 backingStoreType = XConstants.NotUseful;
2109 }
2110
2111 if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2112 backingStoreLog.config("backingStore(as provided by the system property)=" +
2113 ( backingStoreType == XConstants.NotUseful ? "NotUseful"
2114 : backingStoreType == XConstants.WhenMapped ?
2115 "WhenMapped" : "Always") );
2116 }
2117
2118 if (sun.java2d.x11.X11SurfaceData.isDgaAvailable()) {
2119 backingStoreType = XConstants.NotUseful;
2120
2121 if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2122 backingStoreLog.config("DGA is available, backingStore=NotUseful");
2123 }
2124
2125 return;
2126 }
2127
2128 awtLock();
2129 try {
2130 int screenCount = XlibWrapper.ScreenCount(getDisplay());
2131 for (int i = 0; i < screenCount; i++) {
2132 if (XlibWrapper.DoesBackingStore(XlibWrapper.ScreenOfDisplay(getDisplay(), i))
2133 == XConstants.NotUseful) {
2134 backingStoreType = XConstants.NotUseful;
2135
2136 if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2137 backingStoreLog.config("Backing store is not available on the screen " +
2138 i + ", backingStore=NotUseful");
2139 }
2140
2141 return;
2142 }
2143 }
2144 } finally {
2145 awtUnlock();
2146 }
2147 }
2148
2149 /**
2150 * One of XConstants: NotUseful, WhenMapped or Always.
2151 */
2152 private static int backingStoreType;
2153
2154 static final int XSUN_KP_BEHAVIOR = 1;
2155 static final int XORG_KP_BEHAVIOR = 2;
2156 static final int IS_SUN_KEYBOARD = 1;
2157 static final int IS_NONSUN_KEYBOARD = 2;
2158 static final int IS_KANA_KEYBOARD = 1;
2159 static final int IS_NONKANA_KEYBOARD = 2;
2160
2161
2162 static int awt_IsXsunKPBehavior = 0;
2163 static boolean awt_UseXKB = false;
2164 static boolean awt_UseXKB_Calls = false;
2165 static int awt_XKBBaseEventCode = 0;
2166 static int awt_XKBEffectiveGroup = 0; // so far, I don't use it leaving all calculations
2167 // to XkbTranslateKeyCode
2168 static long awt_XKBDescPtr = 0;
2169
2170 /**
2171 * Check for Xsun convention regarding numpad keys.
2172 * Xsun and some other servers (i.e. derived from Xsun)
2173 * under certain conditions process numpad keys unlike Xorg.
2174 */
2175 static boolean isXsunKPBehavior() {
2176 awtLock();
2177 try {
2178 if( awt_IsXsunKPBehavior == 0 ) {
2179 if( XlibWrapper.IsXsunKPBehavior(getDisplay()) ) {
2180 awt_IsXsunKPBehavior = XSUN_KP_BEHAVIOR;
2181 }else{
2182 awt_IsXsunKPBehavior = XORG_KP_BEHAVIOR;
2183 }
2184 }
2185 return awt_IsXsunKPBehavior == XSUN_KP_BEHAVIOR ? true : false;
2186 } finally {
2187 awtUnlock();
2188 }
2189 }
2190
2191 static int sunOrNotKeyboard = 0;
2192 static int kanaOrNotKeyboard = 0;
2193 static void resetKeyboardSniffer() {
2194 sunOrNotKeyboard = 0;
2195 kanaOrNotKeyboard = 0;
2196 }
2197 static boolean isSunKeyboard() {
2198 if( sunOrNotKeyboard == 0 ) {
2199 if( XlibWrapper.IsSunKeyboard( getDisplay() )) {
2200 sunOrNotKeyboard = IS_SUN_KEYBOARD;
2201 }else{
2202 sunOrNotKeyboard = IS_NONSUN_KEYBOARD;
2203 }
2204 }
2205 return (sunOrNotKeyboard == IS_SUN_KEYBOARD);
2206 }
2207 static boolean isKanaKeyboard() {
2208 if( kanaOrNotKeyboard == 0 ) {
2209 if( XlibWrapper.IsKanaKeyboard( getDisplay() )) {
2210 kanaOrNotKeyboard = IS_KANA_KEYBOARD;
2211 }else{
2212 kanaOrNotKeyboard = IS_NONKANA_KEYBOARD;
2213 }
2214 }
2215 return (kanaOrNotKeyboard == IS_KANA_KEYBOARD);
2216 }
2217 static boolean isXKBenabled() {
2218 awtLock();
2219 try {
2220 return awt_UseXKB;
2221 } finally {
2222 awtUnlock();
2223 }
2224 }
2225
2226 /**
2227 Query XKEYBOARD extension.
2228 If possible, initialize xkb library.
2229 */
2230 static boolean tryXKB() {
2231 awtLock();
2232 try {
2233 String name = "XKEYBOARD";
2234 // First, if there is extension at all.
2235 awt_UseXKB = XlibWrapper.XQueryExtension( getDisplay(), name, XlibWrapper.larg1, XlibWrapper.larg2, XlibWrapper.larg3);
2236 if( awt_UseXKB ) {
2237 // There is a keyboard extension. Check if a client library is compatible.
2238 // If not, don't use xkb calls.
2239 // In this case we still may be Xkb-capable application.
2240 awt_UseXKB_Calls = XlibWrapper.XkbLibraryVersion( XlibWrapper.larg1, XlibWrapper.larg2);
2241 if( awt_UseXKB_Calls ) {
2242 awt_UseXKB_Calls = XlibWrapper.XkbQueryExtension( getDisplay(), XlibWrapper.larg1, XlibWrapper.larg2,
2243 XlibWrapper.larg3, XlibWrapper.larg4, XlibWrapper.larg5);
2244 if( awt_UseXKB_Calls ) {
2245 awt_XKBBaseEventCode = Native.getInt(XlibWrapper.larg2);
2246 XlibWrapper.XkbSelectEvents (getDisplay(),
2247 XConstants.XkbUseCoreKbd,
2248 XConstants.XkbNewKeyboardNotifyMask |
2249 XConstants.XkbMapNotifyMask ,//|
2250 //XConstants.XkbStateNotifyMask,
2251 XConstants.XkbNewKeyboardNotifyMask |
2252 XConstants.XkbMapNotifyMask );//|
2253 //XConstants.XkbStateNotifyMask);
2254
2255 XlibWrapper.XkbSelectEventDetails(getDisplay(), XConstants.XkbUseCoreKbd,
2256 XConstants.XkbStateNotify,
2257 XConstants.XkbGroupStateMask,
2258 XConstants.XkbGroupStateMask);
2259 //XXX ? XkbGroupLockMask last, XkbAllStateComponentsMask before last?
2260 awt_XKBDescPtr = XlibWrapper.XkbGetMap(getDisplay(),
2261 XConstants.XkbKeyTypesMask |
2262 XConstants.XkbKeySymsMask |
2263 XConstants.XkbModifierMapMask |
2264 XConstants.XkbVirtualModsMask,
2265 XConstants.XkbUseCoreKbd);
2266
2267 XlibWrapper.XkbSetDetectableAutoRepeat(getDisplay(), true);
2268 }
2269 }
2270 }
2271 return awt_UseXKB;
2272 } finally {
2273 awtUnlock();
2274 }
2275 }
2276 static boolean canUseXKBCalls() {
2277 awtLock();
2278 try {
2279 return awt_UseXKB_Calls;
2280 } finally {
2281 awtUnlock();
2282 }
2283 }
2284 static int getXKBEffectiveGroup() {
2285 awtLock();
2286 try {
2287 return awt_XKBEffectiveGroup;
2288 } finally {
2289 awtUnlock();
2290 }
2291 }
2292 static int getXKBBaseEventCode() {
2293 awtLock();
2294 try {
2295 return awt_XKBBaseEventCode;
2296 } finally {
2297 awtUnlock();
2298 }
2299 }
2300 static long getXKBKbdDesc() {
2301 awtLock();
2302 try {
2303 return awt_XKBDescPtr;
2304 } finally {
2305 awtUnlock();
2306 }
2307 }
2308 void freeXKB() {
2309 awtLock();
2310 try {
2311 if (awt_UseXKB_Calls && awt_XKBDescPtr != 0) {
2312 XlibWrapper.XkbFreeKeyboard(awt_XKBDescPtr, 0xFF, true);
2313 awt_XKBDescPtr = 0;
2314 }
2315 } finally {
2316 awtUnlock();
2317 }
2318 }
2319 private void processXkbChanges(XEvent ev) {
2320 // mapping change --> refresh kbd map
2321 // state change --> get a new effective group; do I really need it
2322 // or that should be left for XkbTranslateKeyCode?
2323 XkbEvent xke = new XkbEvent( ev.getPData() );
2324 int xkb_type = xke.get_any().get_xkb_type();
2325 switch( xkb_type ) {
2326 case XConstants.XkbNewKeyboardNotify :
2327 if( awt_XKBDescPtr != 0 ) {
2328 freeXKB();
2329 }
2330 awt_XKBDescPtr = XlibWrapper.XkbGetMap(getDisplay(),
2331 XConstants.XkbKeyTypesMask |
2332 XConstants.XkbKeySymsMask |
2333 XConstants.XkbModifierMapMask |
2334 XConstants.XkbVirtualModsMask,
2335 XConstants.XkbUseCoreKbd);
2336 //System.out.println("XkbNewKeyboard:"+(xke.get_new_kbd()));
2337 break;
2338 case XConstants.XkbMapNotify :
2339 //TODO: provide a simple unit test.
2340 XlibWrapper.XkbGetUpdatedMap(getDisplay(),
2341 XConstants.XkbKeyTypesMask |
2342 XConstants.XkbKeySymsMask |
2343 XConstants.XkbModifierMapMask |
2344 XConstants.XkbVirtualModsMask,
2345 awt_XKBDescPtr);
2346 //System.out.println("XkbMap:"+(xke.get_map()));
2347 break;
2348 case XConstants.XkbStateNotify :
2349 // May use it later e.g. to obtain an effective group etc.
2350 //System.out.println("XkbState:"+(xke.get_state()));
2351 break;
2352 default:
2353 //System.out.println("XkbEvent of xkb_type "+xkb_type);
2354 break;
2355 }
2356 }
2357
2358 private static long eventNumber;
2359 public static long getEventNumber() {
2360 awtLock();
2361 try {
2362 return eventNumber;
2363 } finally {
2364 awtUnlock();
2365 }
2366 }
2367
2368 private static XEventDispatcher oops_waiter;
2369 private static boolean oops_updated;
2370 private static boolean oops_move;
2371
2372 /**
2373 * @inheritDoc
2374 */
2375 protected boolean syncNativeQueue(final long timeout) {
2376 XBaseWindow win = XBaseWindow.getXAWTRootWindow();
2377
2378 if (oops_waiter == null) {
2379 oops_waiter = new XEventDispatcher() {
2380 public void dispatchEvent(XEvent e) {
2381 if (e.get_type() == XConstants.ConfigureNotify) {
2382 // OOPS ConfigureNotify event catched
2383 oops_updated = true;
2384 awtLockNotifyAll();
2385 }
2386 }
2387 };
2388 }
2389
2390 awtLock();
2391 try {
2392 addEventDispatcher(win.getWindow(), oops_waiter);
2393
2394 oops_updated = false;
2395 long event_number = getEventNumber();
2396 // Generate OOPS ConfigureNotify event
2397 XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), oops_move ? 0 : 1, 0);
2398 // Change win position each time to avoid system optimization
2399 oops_move = !oops_move;
2400 XSync();
2401
2402 eventLog.finer("Generated OOPS ConfigureNotify event");
2403
2404 long start = System.currentTimeMillis();
2405 while (!oops_updated) {
2406 try {
2407 // Wait for OOPS ConfigureNotify event
2408 awtLockWait(timeout);
2409 } catch (InterruptedException e) {
2410 throw new RuntimeException(e);
2411 }
2412 // This "while" is a protection from spurious
2413 // wake-ups. However, we shouldn't wait for too long
2414 if ((System.currentTimeMillis() - start > timeout) && timeout >= 0) {
2415 throw new OperationTimedOut(Long.toString(System.currentTimeMillis() - start));
2416 }
2417 }
2418 // Don't take into account OOPS ConfigureNotify event
2419 return getEventNumber() - event_number > 1;
2420 } finally {
2421 removeEventDispatcher(win.getWindow(), oops_waiter);
2422 eventLog.finer("Exiting syncNativeQueue");
2423 awtUnlock();
2424 }
2425 }
2426 public void grab(Window w) {
2427 if (w.getPeer() != null) {
2428 ((XWindowPeer)w.getPeer()).setGrab(true);
2429 }
2430 }
2431
2432 public void ungrab(Window w) {
2433 if (w.getPeer() != null) {
2434 ((XWindowPeer)w.getPeer()).setGrab(false);
2435 }
2436 }
2437 /**
2438 * Returns if the java.awt.Desktop class is supported on the current
2439 * desktop.
2440 * <p>
2441 * The methods of java.awt.Desktop class are supported on the Gnome desktop.
2442 * Check if the running desktop is Gnome by checking the window manager.
2443 */
2444 public boolean isDesktopSupported(){
2445 return XDesktopPeer.isDesktopSupported();
2446 }
2447
2448 public DesktopPeer createDesktopPeer(Desktop target){
2449 return new XDesktopPeer();
2450 }
2451
2452 public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
2453 return areExtraMouseButtonsEnabled;
2454 }
2455
2456 @Override
2457 public boolean isWindowOpacitySupported() {
2458 XNETProtocol net_protocol = XWM.getWM().getNETProtocol();
2459
2460 if (net_protocol == null) {
2461 return false;
2462 }
2463
2464 return net_protocol.doOpacityProtocol();
2465 }
2466
2467 @Override
2468 public boolean isWindowShapingSupported() {
2469 return XlibUtil.isShapingSupported();
2470 }
2471
2472 @Override
2473 public boolean isWindowTranslucencySupported() {
2474 //NOTE: it may not be supported. The actual check is being performed
2475 // at com.sun.awt.AWTUtilities(). In X11 we need to check
2476 // whether there's any translucency-capable GC available.
2477 return true;
2478 }
2479
2480 @Override
2481 public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
2482 if (!(gc instanceof X11GraphicsConfig)) {
2483 return false;
2484 }
2485 return ((X11GraphicsConfig)gc).isTranslucencyCapable();
2486 }
2487
2488 /**
2489 * Returns the value of "sun.awt.disablegrab" property. Default
2490 * value is {@code false}.
2491 */
2492 public static boolean getSunAwtDisableGrab() {
2493 return AccessController.doPrivileged(new GetBooleanAction("sun.awt.disablegrab"));
2494 }
2495 }
--- EOF ---