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