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