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