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