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