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