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