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