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