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