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