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