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