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