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