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