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