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