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