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