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