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