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