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