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