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 }