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