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