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