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