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