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