1 /*
   2  * Copyright (c) 2002, 2018, 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.print.PrintJob2D;
  55 import sun.security.action.GetPropertyAction;
  56 import sun.security.action.GetBooleanAction;
  57 import sun.util.logging.PlatformLogger;
  58 import sun.security.util.SecurityConstants;
  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     static UIDefaults uidefaults;
 106     static final X11GraphicsEnvironment localEnv;
 107     private static final X11GraphicsDevice device;
 108     private static final X11GraphicsConfig config;
 109     private static final long display;
 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     /**
 118      * Should we check "_NET_WM_STRUT/_NET_WM_STRUT_PARTIAL" during insets
 119      * calculation.
 120      */
 121     private static Boolean checkSTRUT;
 122 
 123     static {
 124         initSecurityWarning();
 125         if (GraphicsEnvironment.isHeadless()) {
 126             localEnv = null;
 127             device = null;
 128             config = null;
 129             display = 0;
 130         } else {
 131             localEnv = (X11GraphicsEnvironment) GraphicsEnvironment
 132                 .getLocalGraphicsEnvironment();
 133             device = (X11GraphicsDevice) localEnv.getDefaultScreenDevice();
 134             config = (X11GraphicsConfig) device.getDefaultConfiguration();
 135             display = device.getDisplay();
 136             setupModifierMap();
 137             initIDs();
 138             setBackingStoreType();
 139         }
 140     }
 141 
 142     /*
 143      * Return (potentially) platform specific display timeout for the
 144      * tray icon
 145      */
 146     static native long getTrayIconDisplayTimeout();
 147 
 148     private native static void initIDs();
 149     native static void waitForEvents(long nextTaskTime);
 150     static Thread toolkitThread;
 151     static boolean isToolkitThread() {
 152         return Thread.currentThread() == toolkitThread;
 153     }
 154 
 155     static void initSecurityWarning() {
 156         // Enable warning only for internal builds
 157         String runtime = AccessController.doPrivileged(
 158                              new GetPropertyAction("java.runtime.version"));
 159         securityWarningEnabled = (runtime != null && runtime.contains("internal"));
 160     }
 161 
 162     static boolean isSecurityWarningEnabled() {
 163         return securityWarningEnabled;
 164     }
 165 
 166     static native void awt_output_flush();
 167 
 168     static final void  awtFUnlock() {
 169         awtUnlock();
 170         awt_output_flush();
 171     }
 172 
 173 
 174     private native void nativeLoadSystemColors(int[] systemColors);
 175 
 176     static UIDefaults getUIDefaults() {
 177         if (uidefaults == null) {
 178             initUIDefaults();
 179         }
 180         return uidefaults;
 181     }
 182 
 183     public void loadSystemColors(int[] systemColors) {
 184         nativeLoadSystemColors(systemColors);
 185         MotifColorUtilities.loadSystemColors(systemColors);
 186     }
 187 
 188 
 189 
 190     static void initUIDefaults() {
 191         try {
 192             // Load Defaults from MotifLookAndFeel
 193 
 194             // This dummy load is necessary to get SystemColor initialized. !!!!!!
 195             Color c = SystemColor.text;
 196 
 197             LookAndFeel lnf = new XAWTLookAndFeel();
 198             uidefaults = lnf.getDefaults();
 199         }
 200         catch (Exception e)
 201         {
 202             e.printStackTrace();
 203         }
 204     }
 205 
 206     /**
 207      * Returns the X11 Display of the default screen device.
 208      *
 209      * @return X11 Display
 210      * @throws AWTError thrown if local GraphicsEnvironment is null, which
 211      *         means we are in the headless environment
 212      */
 213     public static long getDisplay() {
 214         if (localEnv == null) {
 215             throw new AWTError("Local GraphicsEnvironment must not be null");
 216         }
 217         return display;
 218     }
 219 
 220     public static long getDefaultRootWindow() {
 221         awtLock();
 222         try {
 223             long res = XlibWrapper.RootWindow(XToolkit.getDisplay(),
 224                 XlibWrapper.DefaultScreen(XToolkit.getDisplay()));
 225 
 226             if (res == 0) {
 227                throw new IllegalStateException("Root window must not be null");
 228             }
 229             return res;
 230         } finally {
 231             awtUnlock();
 232         }
 233     }
 234 
 235     void init() {
 236         awtLock();
 237         try {
 238             XlibWrapper.XSupportsLocale();
 239             if (XlibWrapper.XSetLocaleModifiers("") == null) {
 240                 log.finer("X locale modifiers are not supported, using default");
 241             }
 242             tryXKB();
 243 
 244             AwtScreenData defaultScreen = new AwtScreenData(XToolkit.getDefaultScreenData());
 245             awt_defaultFg = defaultScreen.get_blackpixel();
 246 
 247             arrowCursor = XlibWrapper.XCreateFontCursor(XToolkit.getDisplay(),
 248                 XCursorFontConstants.XC_arrow);
 249             areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
 250             //set system property if not yet assigned
 251             System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
 252 
 253             // Detect display mode changes
 254             XlibWrapper.XSelectInput(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), XConstants.StructureNotifyMask);
 255             XToolkit.addEventDispatcher(XToolkit.getDefaultRootWindow(), new XEventDispatcher() {
 256                 @Override
 257                 public void dispatchEvent(XEvent ev) {
 258                     if (ev.get_type() == XConstants.ConfigureNotify) {
 259                         awtUnlock();
 260                         try {
 261                             ((X11GraphicsEnvironment)GraphicsEnvironment.
 262                              getLocalGraphicsEnvironment()).
 263                                 displayChanged();
 264                         } finally {
 265                             awtLock();
 266                         }
 267                     }
 268                 }
 269             });
 270         } finally {
 271             awtUnlock();
 272         }
 273         PrivilegedAction<Void> a = () -> {
 274             Thread shutdownThread = new Thread(sun.misc.ThreadGroupUtils.getRootThreadGroup(), "XToolkt-Shutdown-Thread") {
 275                     public void run() {
 276                         XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance();
 277                         if (peer != null) {
 278                             peer.dispose();
 279                         }
 280                         if (xs != null) {
 281                             ((XAWTXSettings)xs).dispose();
 282                         }
 283                         freeXKB();
 284                         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 285                             dumpPeers();
 286                         }
 287                     }
 288                 };
 289             shutdownThread.setContextClassLoader(null);
 290             Runtime.getRuntime().addShutdownHook(shutdownThread);
 291             return null;
 292         };
 293         AccessController.doPrivileged(a);
 294     }
 295 
 296     static String getCorrectXIDString(String val) {
 297         if (val != null) {
 298             return val.replace('.', '-');
 299         } else {
 300             return val;
 301         }
 302     }
 303 
 304     static native String getEnv(String key);
 305 
 306 
 307     static String getAWTAppClassName() {
 308         return awtAppClassName;
 309     }
 310 
 311     public XToolkit() {
 312         super();
 313         if (PerformanceLogger.loggingEnabled()) {
 314             PerformanceLogger.setTime("XToolkit construction");
 315         }
 316 
 317         if (!GraphicsEnvironment.isHeadless()) {
 318             String mainClassName = null;
 319 
 320             StackTraceElement trace[] = (new Throwable()).getStackTrace();
 321             int bottom = trace.length - 1;
 322             if (bottom >= 0) {
 323                 mainClassName = trace[bottom].getClassName();
 324             }
 325             if (mainClassName == null || mainClassName.equals("")) {
 326                 mainClassName = "AWT";
 327             }
 328             awtAppClassName = getCorrectXIDString(mainClassName);
 329 
 330             init();
 331             XWM.init();
 332             toolkitThread = AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
 333                 Thread thread = new Thread(sun.misc.ThreadGroupUtils.getRootThreadGroup(), XToolkit.this, "AWT-XAWT");
 334                 thread.setContextClassLoader(null);
 335                 thread.setPriority(Thread.NORM_PRIORITY + 1);
 336                 thread.setDaemon(true);
 337                 return thread;
 338             });
 339             toolkitThread.start();
 340         }
 341     }
 342 
 343     public ButtonPeer createButton(Button target) {
 344         ButtonPeer peer = new XButtonPeer(target);
 345         targetCreatedPeer(target, peer);
 346         return peer;
 347     }
 348 
 349     public FramePeer createLightweightFrame(LightweightFrame target) {
 350         FramePeer peer = new XLightweightFramePeer(target);
 351         targetCreatedPeer(target, peer);
 352         return peer;
 353     }
 354 
 355     public FramePeer createFrame(Frame target) {
 356         FramePeer peer = new XFramePeer(target);
 357         targetCreatedPeer(target, peer);
 358         return peer;
 359     }
 360 
 361     static void addToWinMap(long window, XBaseWindow xwin)
 362     {
 363         synchronized(winMap) {
 364             winMap.put(Long.valueOf(window),xwin);
 365         }
 366     }
 367 
 368     static void removeFromWinMap(long window, XBaseWindow xwin) {
 369         synchronized(winMap) {
 370             winMap.remove(Long.valueOf(window));
 371         }
 372     }
 373     static XBaseWindow windowToXWindow(long window) {
 374         synchronized(winMap) {
 375             return (XBaseWindow) winMap.get(Long.valueOf(window));
 376         }
 377     }
 378 
 379     static void addEventDispatcher(long window, XEventDispatcher dispatcher) {
 380         synchronized(winToDispatcher) {
 381             Long key = Long.valueOf(window);
 382             Collection dispatchers = (Collection)winToDispatcher.get(key);
 383             if (dispatchers == null) {
 384                 dispatchers = new Vector();
 385                 winToDispatcher.put(key, dispatchers);
 386             }
 387             dispatchers.add(dispatcher);
 388         }
 389     }
 390     static void removeEventDispatcher(long window, XEventDispatcher dispatcher) {
 391         synchronized(winToDispatcher) {
 392             Long key = Long.valueOf(window);
 393             Collection dispatchers = (Collection)winToDispatcher.get(key);
 394             if (dispatchers != null) {
 395                 dispatchers.remove(dispatcher);
 396             }
 397         }
 398     }
 399 
 400     private Point lastCursorPos;
 401 
 402     /**
 403      * Returns whether there is last remembered cursor position.  The
 404      * position is remembered from X mouse events on our peers.  The
 405      * position is stored in <code>p</code>.
 406      * @return true, if there is remembered last cursor position,
 407      * false otherwise
 408      */
 409     boolean getLastCursorPos(Point p) {
 410         awtLock();
 411         try {
 412             if (lastCursorPos == null) {
 413                 return false;
 414             }
 415             p.setLocation(lastCursorPos);
 416             return true;
 417         } finally {
 418             awtUnlock();
 419         }
 420     }
 421 
 422     private void processGlobalMotionEvent(XEvent e) {
 423         // Only our windows guaranteely generate MotionNotify, so we
 424         // should track enter/leave, to catch the moment when to
 425         // switch to XQueryPointer
 426         if (e.get_type() == XConstants.MotionNotify) {
 427             XMotionEvent ev = e.get_xmotion();
 428             awtLock();
 429             try {
 430                 if (lastCursorPos == null) {
 431                     lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
 432                 } else {
 433                     lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
 434                 }
 435             } finally {
 436                 awtUnlock();
 437             }
 438         } else if (e.get_type() == XConstants.LeaveNotify) {
 439             // Leave from our window
 440             awtLock();
 441             try {
 442                 lastCursorPos = null;
 443             } finally {
 444                 awtUnlock();
 445             }
 446         } else if (e.get_type() == XConstants.EnterNotify) {
 447             // Entrance into our window
 448             XCrossingEvent ev = e.get_xcrossing();
 449             awtLock();
 450             try {
 451                 if (lastCursorPos == null) {
 452                     lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
 453                 } else {
 454                     lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
 455                 }
 456             } finally {
 457                 awtUnlock();
 458             }
 459         }
 460     }
 461 
 462     public interface XEventListener {
 463         public void eventProcessed(XEvent e);
 464     }
 465 
 466     private Collection<XEventListener> listeners = new LinkedList<XEventListener>();
 467 
 468     public void addXEventListener(XEventListener listener) {
 469         synchronized (listeners) {
 470             listeners.add(listener);
 471         }
 472     }
 473 
 474     private void notifyListeners(XEvent xev) {
 475         synchronized (listeners) {
 476             if (listeners.size() == 0) return;
 477 
 478             XEvent copy = xev.clone();
 479             try {
 480                 for (XEventListener listener : listeners) {
 481                     listener.eventProcessed(copy);
 482                 }
 483             } finally {
 484                 copy.dispose();
 485             }
 486         }
 487     }
 488 
 489     private void dispatchEvent(XEvent ev) {
 490         final XAnyEvent xany = ev.get_xany();
 491 
 492         if (windowToXWindow(xany.get_window()) != null &&
 493              (ev.get_type() == XConstants.MotionNotify || ev.get_type() == XConstants.EnterNotify || ev.get_type() == XConstants.LeaveNotify))
 494         {
 495             processGlobalMotionEvent(ev);
 496         }
 497 
 498         if( ev.get_type() == XConstants.MappingNotify ) {
 499             // The 'window' field in this event is unused.
 500             // This application itself does nothing to initiate such an event
 501             // (no calls of XChangeKeyboardMapping etc.).
 502             // SunRay server sends this event to the application once on every
 503             // keyboard (not just layout) change which means, quite seldom.
 504             XlibWrapper.XRefreshKeyboardMapping(ev.pData);
 505             resetKeyboardSniffer();
 506             setupModifierMap();
 507         }
 508         XBaseWindow.dispatchToWindow(ev);
 509 
 510         Collection dispatchers = null;
 511         synchronized(winToDispatcher) {
 512             Long key = Long.valueOf(xany.get_window());
 513             dispatchers = (Collection)winToDispatcher.get(key);
 514             if (dispatchers != null) { // Clone it to avoid synchronization during dispatching
 515                 dispatchers = new Vector(dispatchers);
 516             }
 517         }
 518         if (dispatchers != null) {
 519             Iterator iter = dispatchers.iterator();
 520             while (iter.hasNext()) {
 521                 XEventDispatcher disp = (XEventDispatcher)iter.next();
 522                 disp.dispatchEvent(ev);
 523             }
 524         }
 525         notifyListeners(ev);
 526     }
 527 
 528     static void processException(Throwable thr) {
 529         if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 530             log.warning("Exception on Toolkit thread", thr);
 531         }
 532     }
 533 
 534     static native void awt_toolkit_init();
 535 
 536     public void run() {
 537         awt_toolkit_init();
 538         run(PRIMARY_LOOP);
 539     }
 540 
 541     public void run(boolean loop)
 542     {
 543         XEvent ev = new XEvent();
 544         while(true) {
 545             // Fix for 6829923: we should gracefully handle toolkit thread interruption
 546             if (Thread.currentThread().isInterrupted()) {
 547                 // We expect interruption from the AppContext.dispose() method only.
 548                 // If the thread is interrupted from another place, let's skip it
 549                 // for compatibility reasons. Probably some time later we'll remove
 550                 // the check for AppContext.isDisposed() and will unconditionally
 551                 // break the loop here.
 552                 if (AppContext.getAppContext().isDisposed()) {
 553                     break;
 554                 }
 555             }
 556             awtLock();
 557             try {
 558                 if (loop == SECONDARY_LOOP) {
 559                     // In the secondary loop we may have already acquired awt_lock
 560                     // several times, so waitForEvents() might be unable to release
 561                     // the awt_lock and this causes lock up.
 562                     // For now, we just avoid waitForEvents in the secondary loop.
 563                     if (!XlibWrapper.XNextSecondaryLoopEvent(getDisplay(),ev.pData)) {
 564                         break;
 565                     }
 566                 } else {
 567                     callTimeoutTasks();
 568                     // If no events are queued, waitForEvents() causes calls to
 569                     // awtUnlock(), awtJNI_ThreadYield, poll, awtLock(),
 570                     // so it spends most of its time in poll, without holding the lock.
 571                     while ((XlibWrapper.XEventsQueued(getDisplay(), XConstants.QueuedAfterReading) == 0) &&
 572                            (XlibWrapper.XEventsQueued(getDisplay(), XConstants.QueuedAfterFlush) == 0)) {
 573                         callTimeoutTasks();
 574                         waitForEvents(getNextTaskTime());
 575                     }
 576                     XlibWrapper.XNextEvent(getDisplay(),ev.pData);
 577                 }
 578 
 579                 if (ev.get_type() != XConstants.NoExpose) {
 580                     eventNumber++;
 581                 }
 582                 if (awt_UseXKB_Calls && ev.get_type() ==  awt_XKBBaseEventCode) {
 583                     processXkbChanges(ev);
 584                 }
 585 
 586                 if (XDropTargetEventProcessor.processEvent(ev) ||
 587                     XDragSourceContextPeer.processEvent(ev)) {
 588                     continue;
 589                 }
 590 
 591                 if (eventLog.isLoggable(PlatformLogger.Level.FINER)) {
 592                     eventLog.finer("{0}", ev);
 593                 }
 594 
 595                 // Check if input method consumes the event
 596                 long w = 0;
 597                 if (windowToXWindow(ev.get_xany().get_window()) != null) {
 598                     Component owner =
 599                         XKeyboardFocusManagerPeer.getInstance().getCurrentFocusOwner();
 600                     if (owner != null) {
 601                         XWindow ownerWindow = (XWindow) AWTAccessor.getComponentAccessor().getPeer(owner);
 602                         if (ownerWindow != null) {
 603                             w = ownerWindow.getContentWindow();
 604                         }
 605                     }
 606                 }
 607                 if (keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (
 608                         ev.get_type() == XConstants.KeyPress
 609                                 || ev.get_type() == XConstants.KeyRelease)) {
 610                     keyEventLog.fine("before XFilterEvent:" + ev);
 611                 }
 612                 if (XlibWrapper.XFilterEvent(ev.getPData(), w)) {
 613                     continue;
 614                 }
 615                 if (keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (
 616                         ev.get_type() == XConstants.KeyPress
 617                                 || ev.get_type() == XConstants.KeyRelease)) {
 618                     keyEventLog.fine(
 619                             "after XFilterEvent:" + ev); // IS THIS CORRECT?
 620                 }
 621 
 622                 dispatchEvent(ev);
 623             } catch (ThreadDeath td) {
 624                 XBaseWindow.ungrabInput();
 625                 return;
 626             } catch (Throwable thr) {
 627                 XBaseWindow.ungrabInput();
 628                 processException(thr);
 629             } finally {
 630                 awtUnlock();
 631             }
 632         }
 633     }
 634 
 635     /**
 636      * Listener installed to detect display changes.
 637      */
 638     private static final DisplayChangedListener displayChangedHandler =
 639             new DisplayChangedListener() {
 640                 @Override
 641                 public void displayChanged() {
 642                     // 7045370: Reset the cached values
 643                     XToolkit.screenWidth = -1;
 644                     XToolkit.screenHeight = -1;
 645                 }
 646 
 647                 @Override
 648                 public void paletteChanged() {
 649                 }
 650             };
 651 
 652     static {
 653         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
 654         if (ge instanceof SunGraphicsEnvironment) {
 655             ((SunGraphicsEnvironment) ge).addDisplayChangedListener(
 656                     displayChangedHandler);
 657         }
 658     }
 659 
 660     private static void initScreenSize() {
 661         if (screenWidth == -1 || screenHeight == -1) {
 662             awtLock();
 663             try {
 664                 XWindowAttributes pattr = new XWindowAttributes();
 665                 try {
 666                     XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 667                                                      XToolkit.getDefaultRootWindow(),
 668                                                      pattr.pData);
 669                     screenWidth  = (int) pattr.get_width();
 670                     screenHeight = (int) pattr.get_height();
 671                 } finally {
 672                     pattr.dispose();
 673                 }
 674             } finally {
 675                 awtUnlock();
 676             }
 677         }
 678     }
 679 
 680     static int getDefaultScreenWidth() {
 681         initScreenSize();
 682         return screenWidth;
 683     }
 684 
 685     static int getDefaultScreenHeight() {
 686         initScreenSize();
 687         return screenHeight;
 688     }
 689 
 690     protected int getScreenWidth() {
 691         return getDefaultScreenWidth();
 692     }
 693 
 694     protected int getScreenHeight() {
 695         return getDefaultScreenHeight();
 696     }
 697 
 698     private static Rectangle getWorkArea(long root)
 699     {
 700         XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA");
 701 
 702         long native_ptr = Native.allocateLongArray(4);
 703         try
 704         {
 705             boolean workareaPresent = XA_NET_WORKAREA.getAtomData(root,
 706                 XAtom.XA_CARDINAL, native_ptr, 4);
 707             if (workareaPresent)
 708             {
 709                 int rootX = (int)Native.getLong(native_ptr, 0);
 710                 int rootY = (int)Native.getLong(native_ptr, 1);
 711                 int rootWidth = (int)Native.getLong(native_ptr, 2);
 712                 int rootHeight = (int)Native.getLong(native_ptr, 3);
 713 
 714                 return new Rectangle(rootX, rootY, rootWidth, rootHeight);
 715             }
 716         }
 717         finally
 718         {
 719             XlibWrapper.unsafe.freeMemory(native_ptr);
 720         }
 721 
 722         return null;
 723     }
 724 
 725     /*
 726      * If the current window manager supports _NET protocol then the screen
 727      * insets are calculated using _NET_WORKAREA property of the root window.
 728      * <p>
 729      * Note that _NET_WORKAREA is a rectangular area and it does not work
 730      * well in the Xinerama mode.
 731      * <p>
 732      * We will trust the part of this rectangular area only if it starts at the
 733      * requested graphics configuration. Below is an example when the
 734      * _NET_WORKAREA intersects with the requested graphics configuration but
 735      * produces wrong result.
 736      *
 737      *         //<-x1,y1///////
 738      *         //            // ////////////////
 739      *         //  SCREEN1   // // SCREEN2    //
 740      *         // ********** // //     x2,y2->//
 741      *         //////////////// //            //
 742      *                          ////////////////
 743      *
 744      * When two screens overlap and the first contains a dock(*****), then
 745      * _NET_WORKAREA may start at point x1,y1 and end at point x2,y2.
 746      */
 747     public Insets getScreenInsets(GraphicsConfiguration gc)
 748     {
 749         XNETProtocol netProto = XWM.getWM().getNETProtocol();
 750         if ((netProto == null) || !netProto.active())
 751         {
 752             return super.getScreenInsets(gc);
 753         }
 754 
 755         XToolkit.awtLock();
 756         try
 757         {
 758             X11GraphicsConfig x11gc = (X11GraphicsConfig)gc;
 759             X11GraphicsDevice x11gd = (X11GraphicsDevice)x11gc.getDevice();
 760             long root = XlibUtil.getRootWindow(x11gd.getScreen());


 761             X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment)
 762                 GraphicsEnvironment.getLocalGraphicsEnvironment();
 763             if (x11ge.runningXinerama() && checkSTRUT()) {
 764                 // implementation based on _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL
 765                 Rectangle rootBounds = XlibUtil.getWindowGeometry(root);
 766                 Insets insets = getScreenInsetsManually(root, rootBounds,
 767                                                         gc.getBounds());
 768                 if ((insets.left | insets.top | insets.bottom | insets.right) != 0
 769                         || rootBounds == null) {
 770                     return insets;

 771                 }
 772             }
 773             Rectangle workArea = XToolkit.getWorkArea(root);
 774             Rectangle screen = gc.getBounds();
 775             if (workArea != null && screen.contains(workArea.getLocation())) {
 776                 workArea = workArea.intersection(screen);
 777                 int top = workArea.y - screen.y;
 778                 int left = workArea.x - screen.x;
 779                 int bottom = screen.height - workArea.height - top;
 780                 int right = screen.width - workArea.width - left;
 781                 return new Insets(top, left, bottom, right);
 782             }
 783             // Note that it is better to return zeros than inadequate values
 784             return new Insets(0, 0, 0, 0);
 785         }
 786         finally
 787         {
 788             XToolkit.awtUnlock();
 789         }
 790     }
 791 
 792     /**
 793      * Returns the value of "sun.awt.X11.checkSTRUT" property. Default value is
 794      * {@code false}.
 795      */
 796     private static boolean checkSTRUT() {
 797         if (checkSTRUT == null) {
 798             checkSTRUT = AccessController.doPrivileged(
 799                     new GetBooleanAction("sun.awt.X11.checkSTRUT"));
 800         }
 801         return checkSTRUT;
 802     }
 803 
 804     /*
 805      * Manual calculation of screen insets: get all the windows with
 806      * _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL hints and add these
 807      * hints' values to screen insets.
 808      *
 809      * This method should be called under XToolkit.awtLock()
 810      *
 811      * This method is unused by default because of two reasons:
 812      *  - Iteration over windows may be extremely slow, and execution of
 813      *    getScreenInsets() can be x100 slower than in one monitor config.
 814      *  - _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL are hints for the applications.
 815      *    WM should take into account these hints when "_NET_WORKAREA" is
 816      *    calculated, but the system panels do not necessarily contain these
 817      *    hints(Gnome 3 for example).
 818      */
 819     private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds)
 820     {
 821         /*
 822          * During the manual calculation of screen insets we iterate
 823          * all the X windows hierarchy starting from root window. This
 824          * constant is the max level inspected in this hierarchy.
 825          * 3 is a heuristic value: I suppose any the toolbar-like
 826          * window is a child of either root or desktop window.
 827          */
 828         final int MAX_NESTED_LEVEL = 3;
 829 
 830         XAtom XA_NET_WM_STRUT = XAtom.get("_NET_WM_STRUT");
 831         XAtom XA_NET_WM_STRUT_PARTIAL = XAtom.get("_NET_WM_STRUT_PARTIAL");
 832 
 833         Insets insets = new Insets(0, 0, 0, 0);
 834 
 835         java.util.List search = new LinkedList();
 836         search.add(root);
 837         search.add(0);
 838         while (!search.isEmpty())
 839         {
 840             long window = (Long)search.remove(0);
 841             int windowLevel = (Integer)search.remove(0);
 842 
 843             /*
 844              * Note that most of the modern window managers unmap
 845              * application window if it is iconified. Thus, any
 846              * _NET_WM_STRUT[_PARTIAL] hints for iconified windows
 847              * are not included to the screen insets.
 848              */
 849             if (XlibUtil.getWindowMapState(window) == XConstants.IsUnmapped)
 850             {
 851                 continue;
 852             }
 853 
 854             long native_ptr = Native.allocateLongArray(4);
 855             try
 856             {
 857                 // first, check if _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL are present
 858                 // if both are set on the window, _NET_WM_STRUT_PARTIAL is used (see _NET spec)
 859                 boolean strutPresent = XA_NET_WM_STRUT_PARTIAL.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
 860                 if (!strutPresent)
 861                 {
 862                     strutPresent = XA_NET_WM_STRUT.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
 863                 }
 864                 if (strutPresent)
 865                 {
 866                     // second, verify that window is located on the proper screen
 867                     Rectangle windowBounds = XlibUtil.getWindowGeometry(window);
 868                     if (windowLevel > 1)
 869                     {
 870                         windowBounds = XlibUtil.translateCoordinates(window, root, windowBounds);
 871                     }
 872                     // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect
 873                     // if the struts area intersects with screenBounds, however some window
 874                     // managers don't set this hint correctly, so we just get intersection with windowBounds
 875                     if (windowBounds != null && windowBounds.intersects(screenBounds))
 876                     {
 877                         int left = (int)Native.getLong(native_ptr, 0);
 878                         int right = (int)Native.getLong(native_ptr, 1);
 879                         int top = (int)Native.getLong(native_ptr, 2);
 880                         int bottom = (int)Native.getLong(native_ptr, 3);
 881 
 882                         /*
 883                          * struts could be relative to root window bounds, so
 884                          * make them relative to the screen bounds in this case
 885                          */
 886                         left = rootBounds.x + left > screenBounds.x ?
 887                                 rootBounds.x + left - screenBounds.x : 0;
 888                         right = rootBounds.x + rootBounds.width - right <
 889                                 screenBounds.x + screenBounds.width ?
 890                                 screenBounds.x + screenBounds.width -
 891                                 (rootBounds.x + rootBounds.width - right) : 0;
 892                         top = rootBounds.y + top > screenBounds.y ?
 893                                 rootBounds.y + top - screenBounds.y : 0;
 894                         bottom = rootBounds.y + rootBounds.height - bottom <
 895                                 screenBounds.y + screenBounds.height ?
 896                                 screenBounds.y + screenBounds.height -
 897                                 (rootBounds.y + rootBounds.height - bottom) : 0;
 898 
 899                         insets.left = Math.max(left, insets.left);
 900                         insets.right = Math.max(right, insets.right);
 901                         insets.top = Math.max(top, insets.top);
 902                         insets.bottom = Math.max(bottom, insets.bottom);
 903                     }
 904                 }
 905             }
 906             finally
 907             {
 908                 XlibWrapper.unsafe.freeMemory(native_ptr);
 909             }
 910 
 911             if (windowLevel < MAX_NESTED_LEVEL)
 912             {
 913                 Set<Long> children = XlibUtil.getChildWindows(window);
 914                 for (long child : children)
 915                 {
 916                     search.add(child);
 917                     search.add(windowLevel + 1);
 918                 }
 919             }
 920         }
 921 
 922         return insets;
 923     }
 924 
 925     /*
 926      * The current implementation of disabling background erasing for
 927      * canvases is that we don't set any native background color
 928      * (with XSetWindowBackground) for the canvas window. However,
 929      * this color is set in the peer constructor - see
 930      * XWindow.postInit() for details. That's why this method from
 931      * SunToolkit is not overridden in XToolkit: it's too late to
 932      * disable background erasing :(
 933      */
 934     /*
 935     @Override
 936     public void disableBackgroundErase(Canvas canvas) {
 937         XCanvasPeer peer = (XCanvasPeer)canvas.getPeer();
 938         if (peer == null) {
 939             throw new IllegalStateException("Canvas must have a valid peer");
 940         }
 941         peer.disableBackgroundErase();
 942     }
 943     */
 944 
 945     // Need this for XMenuItemPeer.
 946     protected static final Object targetToPeer(Object target) {
 947         Object p=null;
 948         if (target != null && !GraphicsEnvironment.isHeadless()) {
 949             p = specialPeerMap.get(target);
 950         }
 951         if (p != null) return p;
 952         else
 953             return SunToolkit.targetToPeer(target);
 954     }
 955 
 956     // Need this for XMenuItemPeer.
 957     protected static final void targetDisposedPeer(Object target, Object peer) {
 958         SunToolkit.targetDisposedPeer(target, peer);
 959     }
 960 
 961     public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
 962         return new XRobotPeer(screen.getDefaultConfiguration());
 963     }
 964 
 965 
 966   /*
 967      * On X, support for dynamic layout on resizing is governed by the
 968      * window manager.  If the window manager supports it, it happens
 969      * automatically.  The setter method for this property is
 970      * irrelevant on X.
 971      */
 972     public void setDynamicLayout(boolean b) {
 973         dynamicLayoutSetting = b;
 974     }
 975 
 976     protected boolean isDynamicLayoutSet() {
 977         return dynamicLayoutSetting;
 978     }
 979 
 980     /* Called from isDynamicLayoutActive() and from
 981      * lazilyLoadDynamicLayoutSupportedProperty()
 982      */
 983     protected boolean isDynamicLayoutSupported() {
 984         return XWM.getWM().supportsDynamicLayout();
 985     }
 986 
 987     public boolean isDynamicLayoutActive() {
 988         return isDynamicLayoutSupported();
 989     }
 990 
 991 
 992     public FontPeer getFontPeer(String name, int style){
 993         return new XFontPeer(name, style);
 994     }
 995 
 996     public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
 997         final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent());
 998         if (f != null) {
 999             return f.createDragSourceContextPeer(dge);
1000         }
1001 
1002         return XDragSourceContextPeer.createDragSourceContextPeer(dge);
1003     }
1004 
1005     public <T extends DragGestureRecognizer> T
1006     createDragGestureRecognizer(Class<T> recognizerClass,
1007                     DragSource ds,
1008                     Component c,
1009                     int srcActions,
1010                     DragGestureListener dgl)
1011     {
1012         final LightweightFrame f = SunToolkit.getLightweightFrame(c);
1013         if (f != null) {
1014             return f.createDragGestureRecognizer(recognizerClass, ds, c, srcActions, dgl);
1015         }
1016 
1017         if (MouseDragGestureRecognizer.class.equals(recognizerClass))
1018             return (T)new XMouseDragGestureRecognizer(ds, c, srcActions, dgl);
1019         else
1020             return null;
1021     }
1022 
1023     public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
1024         XCheckboxMenuItemPeer peer = new XCheckboxMenuItemPeer(target);
1025         //vb157120: looks like we don't need to map menu items
1026         //in new menus implementation
1027         //targetCreatedPeer(target, peer);
1028         return peer;
1029     }
1030 
1031     public MenuItemPeer createMenuItem(MenuItem target) {
1032         XMenuItemPeer peer = new XMenuItemPeer(target);
1033         //vb157120: looks like we don't need to map menu items
1034         //in new menus implementation
1035         //targetCreatedPeer(target, peer);
1036         return peer;
1037     }
1038 
1039     public TextFieldPeer createTextField(TextField target) {
1040         TextFieldPeer  peer = new XTextFieldPeer(target);
1041         targetCreatedPeer(target, peer);
1042         return peer;
1043     }
1044 
1045     public LabelPeer createLabel(Label target) {
1046         LabelPeer  peer = new XLabelPeer(target);
1047         targetCreatedPeer(target, peer);
1048         return peer;
1049     }
1050 
1051     public ListPeer createList(java.awt.List target) {
1052         ListPeer peer = new XListPeer(target);
1053         targetCreatedPeer(target, peer);
1054         return peer;
1055     }
1056 
1057     public CheckboxPeer createCheckbox(Checkbox target) {
1058         CheckboxPeer peer = new XCheckboxPeer(target);
1059         targetCreatedPeer(target, peer);
1060         return peer;
1061     }
1062 
1063     public ScrollbarPeer createScrollbar(Scrollbar target) {
1064         XScrollbarPeer peer = new XScrollbarPeer(target);
1065         targetCreatedPeer(target, peer);
1066         return peer;
1067     }
1068 
1069     public ScrollPanePeer createScrollPane(ScrollPane target) {
1070         XScrollPanePeer peer = new XScrollPanePeer(target);
1071         targetCreatedPeer(target, peer);
1072         return peer;
1073     }
1074 
1075     public TextAreaPeer createTextArea(TextArea target) {
1076         TextAreaPeer peer = new XTextAreaPeer(target);
1077         targetCreatedPeer(target, peer);
1078         return peer;
1079     }
1080 
1081     public ChoicePeer createChoice(Choice target) {
1082         XChoicePeer peer = new XChoicePeer(target);
1083         targetCreatedPeer(target, peer);
1084         return peer;
1085     }
1086 
1087     public CanvasPeer createCanvas(Canvas target) {
1088         XCanvasPeer peer = (isXEmbedServerRequested() ? new XEmbedCanvasPeer(target) : new XCanvasPeer(target));
1089         targetCreatedPeer(target, peer);
1090         return peer;
1091     }
1092 
1093     public PanelPeer createPanel(Panel target) {
1094         PanelPeer peer = new XPanelPeer(target);
1095         targetCreatedPeer(target, peer);
1096         return peer;
1097     }
1098 
1099     public WindowPeer createWindow(Window target) {
1100         WindowPeer peer = new XWindowPeer(target);
1101         targetCreatedPeer(target, peer);
1102         return peer;
1103     }
1104 
1105     public DialogPeer createDialog(Dialog target) {
1106         DialogPeer peer = new XDialogPeer(target);
1107         targetCreatedPeer(target, peer);
1108         return peer;
1109     }
1110 
1111     private static Boolean sunAwtDisableGtkFileDialogs = null;
1112 
1113     /**
1114      * Returns the value of "sun.awt.disableGtkFileDialogs" property. Default
1115      * value is {@code false}.
1116      */
1117     public synchronized static boolean getSunAwtDisableGtkFileDialogs() {
1118         if (sunAwtDisableGtkFileDialogs == null) {
1119             sunAwtDisableGtkFileDialogs = AccessController.doPrivileged(
1120                                               new GetBooleanAction("sun.awt.disableGtkFileDialogs"));
1121         }
1122         return sunAwtDisableGtkFileDialogs.booleanValue();
1123     }
1124 
1125     public FileDialogPeer createFileDialog(FileDialog target) {
1126         FileDialogPeer peer = null;
1127         // The current GtkFileChooser is available from GTK+ 2.4
1128         if (!getSunAwtDisableGtkFileDialogs() && checkGtkVersion(2, 4, 0)) {
1129             peer = new GtkFileDialogPeer(target);
1130         } else {
1131             peer = new XFileDialogPeer(target);
1132         }
1133         targetCreatedPeer(target, peer);
1134         return peer;
1135     }
1136 
1137     public MenuBarPeer createMenuBar(MenuBar target) {
1138         XMenuBarPeer peer = new XMenuBarPeer(target);
1139         targetCreatedPeer(target, peer);
1140         return peer;
1141     }
1142 
1143     public MenuPeer createMenu(Menu target) {
1144         XMenuPeer peer = new XMenuPeer(target);
1145         //vb157120: looks like we don't need to map menu items
1146         //in new menus implementation
1147         //targetCreatedPeer(target, peer);
1148         return peer;
1149     }
1150 
1151     public PopupMenuPeer createPopupMenu(PopupMenu target) {
1152         XPopupMenuPeer peer = new XPopupMenuPeer(target);
1153         targetCreatedPeer(target, peer);
1154         return peer;
1155     }
1156 
1157     public synchronized MouseInfoPeer getMouseInfoPeer() {
1158         if (xPeer == null) {
1159             xPeer = new XMouseInfoPeer();
1160         }
1161         return xPeer;
1162     }
1163 
1164     public XEmbeddedFramePeer createEmbeddedFrame(XEmbeddedFrame target)
1165     {
1166         XEmbeddedFramePeer peer = new XEmbeddedFramePeer(target);
1167         targetCreatedPeer(target, peer);
1168         return peer;
1169     }
1170 
1171     XEmbedChildProxyPeer createEmbedProxy(XEmbedChildProxy target) {
1172         XEmbedChildProxyPeer peer = new XEmbedChildProxyPeer(target);
1173         targetCreatedPeer(target, peer);
1174         return peer;
1175     }
1176 
1177     public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() throws HeadlessException {
1178         return XKeyboardFocusManagerPeer.getInstance();
1179     }
1180 
1181     /**
1182      * Returns a new custom cursor.
1183      */
1184     public Cursor createCustomCursor(Image cursor, Point hotSpot, String name)
1185       throws IndexOutOfBoundsException {
1186         return new XCustomCursor(cursor, hotSpot, name);
1187     }
1188 
1189     public TrayIconPeer createTrayIcon(TrayIcon target)
1190       throws HeadlessException, AWTException
1191     {
1192         TrayIconPeer peer = new XTrayIconPeer(target);
1193         targetCreatedPeer(target, peer);
1194         return peer;
1195     }
1196 
1197     public SystemTrayPeer createSystemTray(SystemTray target) throws HeadlessException {
1198         SystemTrayPeer peer = new XSystemTrayPeer(target);
1199         return peer;
1200     }
1201 
1202     public boolean isTraySupported() {
1203         XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance();
1204         if (peer != null) {
1205             return peer.isAvailable();
1206         }
1207         return false;
1208     }
1209 
1210     @Override
1211     public DataTransferer getDataTransferer() {
1212         return XDataTransferer.getInstanceImpl();
1213     }
1214 
1215     /**
1216      * Returns the supported cursor size
1217      */
1218     public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) {
1219         return XCustomCursor.getBestCursorSize(
1220                                                java.lang.Math.max(1,preferredWidth), java.lang.Math.max(1,preferredHeight));
1221     }
1222 
1223 
1224     public int getMaximumCursorColors() {
1225         return 2;  // Black and white.
1226     }
1227 
1228     public Map mapInputMethodHighlight(InputMethodHighlight highlight)     {
1229         return XInputMethod.mapInputMethodHighlight(highlight);
1230     }
1231     @Override
1232     public boolean getLockingKeyState(int key) {
1233         if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK ||
1234                key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) {
1235             throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
1236         }
1237         awtLock();
1238         try {
1239             return getModifierState( key );
1240         } finally {
1241             awtUnlock();
1242         }
1243     }
1244 
1245     public  Clipboard getSystemClipboard() {
1246         SecurityManager security = System.getSecurityManager();
1247         if (security != null) {
1248             security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
1249         }
1250         synchronized (this) {
1251             if (clipboard == null) {
1252                 clipboard = new XClipboard("System", "CLIPBOARD");
1253             }
1254         }
1255         return clipboard;
1256     }
1257 
1258     public Clipboard getSystemSelection() {
1259         SecurityManager security = System.getSecurityManager();
1260         if (security != null) {
1261             security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
1262         }
1263         synchronized (this) {
1264             if (selection == null) {
1265                 selection = new XClipboard("Selection", "PRIMARY");
1266             }
1267         }
1268         return selection;
1269     }
1270 
1271     public void beep() {
1272         awtLock();
1273         try {
1274             XlibWrapper.XBell(getDisplay(), 0);
1275             XlibWrapper.XFlush(getDisplay());
1276         } finally {
1277             awtUnlock();
1278         }
1279     }
1280 
1281     public PrintJob getPrintJob(final Frame frame, final String doctitle,
1282                                 final Properties props) {
1283 
1284         if (frame == null) {
1285             throw new NullPointerException("frame must not be null");
1286         }
1287 
1288         PrintJob2D printJob = new PrintJob2D(frame, doctitle, props);
1289 
1290         if (printJob.printDialog() == false) {
1291             printJob = null;
1292         }
1293         return printJob;
1294     }
1295 
1296     public PrintJob getPrintJob(final Frame frame, final String doctitle,
1297                 final JobAttributes jobAttributes,
1298                 final PageAttributes pageAttributes)
1299     {
1300         if (frame == null) {
1301             throw new NullPointerException("frame must not be null");
1302         }
1303 
1304         PrintJob2D printJob = new PrintJob2D(frame, doctitle,
1305                                              jobAttributes, pageAttributes);
1306 
1307         if (printJob.printDialog() == false) {
1308             printJob = null;
1309         }
1310 
1311         return printJob;
1312     }
1313 
1314     static void XSync() {
1315         awtLock();
1316         try {
1317             XlibWrapper.XSync(getDisplay(),0);
1318         } finally {
1319             awtUnlock();
1320         }
1321     }
1322 
1323     public int getScreenResolution() {
1324         long display = getDisplay();
1325         awtLock();
1326         try {
1327             return (int) ((XlibWrapper.DisplayWidth(display,
1328                 XlibWrapper.DefaultScreen(display)) * 25.4) /
1329                     XlibWrapper.DisplayWidthMM(display,
1330                 XlibWrapper.DefaultScreen(display)));
1331         } finally {
1332             awtUnlock();
1333         }
1334     }
1335 
1336     static native long getDefaultXColormap();
1337     static native long getDefaultScreenData();
1338 
1339     static ColorModel screenmodel;
1340 
1341     static ColorModel getStaticColorModel() {
1342         if (screenmodel == null) {
1343             screenmodel = config.getColorModel ();
1344         }
1345         return screenmodel;
1346     }
1347 
1348     public ColorModel getColorModel() {
1349         return getStaticColorModel();
1350     }
1351 
1352     /**
1353      * Returns a new input method adapter descriptor for native input methods.
1354      */
1355     public InputMethodDescriptor getInputMethodAdapterDescriptor() throws AWTException {
1356         return new XInputMethodDescriptor();
1357     }
1358 
1359     /**
1360      * Returns whether enableInputMethods should be set to true for peered
1361      * TextComponent instances on this platform. True by default.
1362      */
1363     @Override
1364     public boolean enableInputMethodsForTextComponent() {
1365         return true;
1366     }
1367 
1368     static int getMultiClickTime() {
1369         if (awt_multiclick_time == 0) {
1370             initializeMultiClickTime();
1371         }
1372         return awt_multiclick_time;
1373     }
1374     static void initializeMultiClickTime() {
1375         awtLock();
1376         try {
1377             try {
1378                 String multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(), "*", "multiClickTime");
1379                 if (multiclick_time_query != null) {
1380                     awt_multiclick_time = (int)Long.parseLong(multiclick_time_query);
1381                 } else {
1382                     multiclick_time_query = XlibWrapper.XGetDefault(XToolkit.getDisplay(),
1383                                                                     "OpenWindows", "MultiClickTimeout");
1384                     if (multiclick_time_query != null) {
1385                         /* Note: OpenWindows.MultiClickTimeout is in tenths of
1386                            a second, so we need to multiply by 100 to convert to
1387                            milliseconds */
1388                         awt_multiclick_time = (int)Long.parseLong(multiclick_time_query) * 100;
1389                     } else {
1390                         awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1391                     }
1392                 }
1393             } catch (NumberFormatException nf) {
1394                 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1395             } catch (NullPointerException npe) {
1396                 awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1397             }
1398         } finally {
1399             awtUnlock();
1400         }
1401         if (awt_multiclick_time == 0) {
1402             awt_multiclick_time = AWT_MULTICLICK_DEFAULT_TIME;
1403         }
1404     }
1405 
1406     public boolean isFrameStateSupported(int state)
1407       throws HeadlessException
1408     {
1409         if (state == Frame.NORMAL || state == Frame.ICONIFIED) {
1410             return true;
1411         } else {
1412             return XWM.getWM().supportsExtendedState(state);
1413         }
1414     }
1415 
1416     static void dumpPeers() {
1417         if (log.isLoggable(PlatformLogger.Level.FINE)) {
1418             log.fine("Mapped windows:");
1419             Iterator iter = winMap.entrySet().iterator();
1420             while (iter.hasNext()) {
1421                 Map.Entry entry = (Map.Entry)iter.next();
1422                 log.fine(entry.getKey() + "->" + entry.getValue());
1423                 if (entry.getValue() instanceof XComponentPeer) {
1424                     Component target = (Component)((XComponentPeer)entry.getValue()).getTarget();
1425                     log.fine("\ttarget: " + target);
1426                 }
1427             }
1428 
1429             SunToolkit.dumpPeers(log);
1430 
1431             log.fine("Mapped special peers:");
1432             iter = specialPeerMap.entrySet().iterator();
1433             while (iter.hasNext()) {
1434                 Map.Entry entry = (Map.Entry)iter.next();
1435                 log.fine(entry.getKey() + "->" + entry.getValue());
1436             }
1437 
1438             log.fine("Mapped dispatchers:");
1439             iter = winToDispatcher.entrySet().iterator();
1440             while (iter.hasNext()) {
1441                 Map.Entry entry = (Map.Entry)iter.next();
1442                 log.fine(entry.getKey() + "->" + entry.getValue());
1443             }
1444         }
1445     }
1446 
1447     /* Protected with awt_lock. */
1448     private static boolean initialized;
1449     private static boolean timeStampUpdated;
1450     private static long timeStamp;
1451 
1452     private static final XEventDispatcher timeFetcher =
1453     new XEventDispatcher() {
1454             public void dispatchEvent(XEvent ev) {
1455                 switch (ev.get_type()) {
1456                   case XConstants.PropertyNotify:
1457                       XPropertyEvent xpe = ev.get_xproperty();
1458 
1459                       awtLock();
1460                       try {
1461                           timeStamp = xpe.get_time();
1462                           timeStampUpdated = true;
1463                           awtLockNotifyAll();
1464                       } finally {
1465                           awtUnlock();
1466                       }
1467 
1468                       break;
1469                 }
1470             }
1471         };
1472 
1473     private static XAtom _XA_JAVA_TIME_PROPERTY_ATOM;
1474 
1475     static long getCurrentServerTime() {
1476         awtLock();
1477         try {
1478             try {
1479                 if (!initialized) {
1480                     XToolkit.addEventDispatcher(XBaseWindow.getXAWTRootWindow().getWindow(),
1481                                                 timeFetcher);
1482                     _XA_JAVA_TIME_PROPERTY_ATOM = XAtom.get("_SUNW_JAVA_AWT_TIME");
1483                     initialized = true;
1484                 }
1485                 timeStampUpdated = false;
1486                 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
1487                                             XBaseWindow.getXAWTRootWindow().getWindow(),
1488                                             _XA_JAVA_TIME_PROPERTY_ATOM.getAtom(), XAtom.XA_ATOM, 32,
1489                                             XConstants.PropModeAppend,
1490                                             0, 0);
1491                 XlibWrapper.XFlush(XToolkit.getDisplay());
1492 
1493                 if (isToolkitThread()) {
1494                     XEvent event = new XEvent();
1495                     try {
1496                         XlibWrapper.XWindowEvent(XToolkit.getDisplay(),
1497                                                  XBaseWindow.getXAWTRootWindow().getWindow(),
1498                                                  XConstants.PropertyChangeMask,
1499                                                  event.pData);
1500                         timeFetcher.dispatchEvent(event);
1501                     }
1502                     finally {
1503                         event.dispose();
1504                     }
1505                 }
1506                 else {
1507                     while (!timeStampUpdated) {
1508                         awtLockWait();
1509                     }
1510                 }
1511             } catch (InterruptedException ie) {
1512             // Note: the returned timeStamp can be incorrect in this case.
1513                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
1514                     log.fine("Catched exception, timeStamp may not be correct (ie = " + ie + ")");
1515                 }
1516             }
1517         } finally {
1518             awtUnlock();
1519         }
1520         return timeStamp;
1521     }
1522     protected void initializeDesktopProperties() {
1523         desktopProperties.put("DnD.Autoscroll.initialDelay",
1524                               Integer.valueOf(50));
1525         desktopProperties.put("DnD.Autoscroll.interval",
1526                               Integer.valueOf(50));
1527         desktopProperties.put("DnD.Autoscroll.cursorHysteresis",
1528                               Integer.valueOf(5));
1529         desktopProperties.put("Shell.shellFolderManager",
1530                               "sun.awt.shell.ShellFolderManager");
1531         // Don't want to call getMultiClickTime() if we are headless
1532         if (!GraphicsEnvironment.isHeadless()) {
1533             desktopProperties.put("awt.multiClickInterval",
1534                                   Integer.valueOf(getMultiClickTime()));
1535             desktopProperties.put("awt.mouse.numButtons",
1536                                   Integer.valueOf(getNumberOfButtons()));
1537         }
1538     }
1539 
1540     /**
1541      * This method runs through the XPointer and XExtendedPointer array.
1542      * XExtendedPointer has priority because on some systems XPointer
1543      * (which is assigned to the virtual pointer) reports the maximum
1544      * capabilities of the mouse pointer (i.e. 32 physical buttons).
1545      */
1546     private native int getNumberOfButtonsImpl();
1547 
1548     @Override
1549     public int getNumberOfButtons(){
1550         awtLock();
1551         try {
1552             if (numberOfButtons == 0) {
1553                 numberOfButtons = getNumberOfButtonsImpl();
1554                 numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
1555                 //4th and 5th buttons are for wheel and shouldn't be reported as buttons.
1556                 //If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
1557                 //If we have 3 physical buttons and a wheel, we report 3 buttons.
1558                 //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
1559                 if (numberOfButtons >=5) {
1560                     numberOfButtons -= 2;
1561                 } else if (numberOfButtons == 4 || numberOfButtons ==5){
1562                     numberOfButtons = 3;
1563                 }
1564             }
1565             //Assume don't have to re-query the number again and again.
1566             return numberOfButtons;
1567         } finally {
1568             awtUnlock();
1569         }
1570     }
1571 
1572     static int getNumberOfButtonsForMask() {
1573         return Math.min(XConstants.MAX_BUTTONS, ((SunToolkit) (Toolkit.getDefaultToolkit())).getNumberOfButtons());
1574     }
1575 
1576     private final static String prefix  = "DnD.Cursor.";
1577     private final static String postfix = ".32x32";
1578     private static final String dndPrefix  = "DnD.";
1579 
1580     protected Object lazilyLoadDesktopProperty(String name) {
1581         if (name.startsWith(prefix)) {
1582             String cursorName = name.substring(prefix.length(), name.length()) + postfix;
1583 
1584             try {
1585                 return Cursor.getSystemCustomCursor(cursorName);
1586             } catch (AWTException awte) {
1587                 throw new RuntimeException("cannot load system cursor: " + cursorName, awte);
1588             }
1589         }
1590 
1591         if (name.equals("awt.dynamicLayoutSupported")) {
1592             return  Boolean.valueOf(isDynamicLayoutSupported());
1593         }
1594 
1595         if (initXSettingsIfNeeded(name)) {
1596             return desktopProperties.get(name);
1597         }
1598 
1599         return super.lazilyLoadDesktopProperty(name);
1600     }
1601 
1602     public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
1603         if (name == null) {
1604             // See JavaDoc for the Toolkit.addPropertyChangeListener() method
1605             return;
1606         }
1607         initXSettingsIfNeeded(name);
1608         super.addPropertyChangeListener(name, pcl);
1609     }
1610 
1611     /**
1612      * Initializes XAWTXSettings if a property for a given property name is provided by
1613      * XSettings and they are not initialized yet.
1614      *
1615      * @return true if the method has initialized XAWTXSettings.
1616      */
1617     private boolean initXSettingsIfNeeded(final String propName) {
1618         if (!loadedXSettings &&
1619             (propName.startsWith("gnome.") ||
1620              propName.equals(SunToolkit.DESKTOPFONTHINTS) ||
1621              propName.startsWith(dndPrefix)))
1622         {
1623             loadedXSettings = true;
1624             if (!GraphicsEnvironment.isHeadless()) {
1625                 loadXSettings();
1626                 /* If no desktop font hint could be retrieved, check for
1627                  * KDE running KWin and retrieve settings from fontconfig.
1628                  * If that isn't found let SunToolkit will see if there's a
1629                  * system property set by a user.
1630                  */
1631                 if (desktopProperties.get(SunToolkit.DESKTOPFONTHINTS) == null) {
1632                     if (XWM.isKDE2()) {
1633                         Object hint = fcManager.getFontConfigAAHint();
1634                         if (hint != null) {
1635                             /* set the fontconfig/KDE property so that
1636                              * getDesktopHints() below will see it
1637                              * and set the public property.
1638                              */
1639                             desktopProperties.put(UNIXToolkit.FONTCONFIGAAHINT,
1640                                                   hint);
1641                         }
1642                     }
1643                     desktopProperties.put(SunToolkit.DESKTOPFONTHINTS,
1644                                           SunToolkit.getDesktopFontHints());
1645                 }
1646 
1647                 return true;
1648             }
1649         }
1650         return false;
1651     }
1652 
1653     private void loadXSettings() {
1654        xs = new XAWTXSettings();
1655     }
1656 
1657     /**
1658      * Callback from the native side indicating some, or all, of the
1659      * desktop properties have changed and need to be reloaded.
1660      * <code>data</code> is the byte array directly from the x server and
1661      * may be in little endian format.
1662      * <p>
1663      * NB: This could be called from any thread if triggered by
1664      * <code>loadXSettings</code>.  It is called from the System EDT
1665      * if triggered by an XSETTINGS change.
1666      */
1667     void parseXSettings(int screen_XXX_ignored,Map updatedSettings) {
1668 
1669         if (updatedSettings == null || updatedSettings.isEmpty()) {
1670             return;
1671         }
1672 
1673         Iterator i = updatedSettings.entrySet().iterator();
1674         while (i.hasNext()) {
1675             Map.Entry e = (Map.Entry)i.next();
1676             String name = (String)e.getKey();
1677 
1678             name = "gnome." + name;
1679             setDesktopProperty(name, e.getValue());
1680             if (log.isLoggable(PlatformLogger.Level.FINE)) {
1681                 log.fine("name = " + name + " value = " + e.getValue());
1682             }
1683 
1684             // XXX: we probably want to do something smarter.  In
1685             // particular, "Net" properties are of interest to the
1686             // "core" AWT itself.  E.g.
1687             //
1688             // Net/DndDragThreshold -> ???
1689             // Net/DoubleClickTime  -> awt.multiClickInterval
1690         }
1691 
1692         setDesktopProperty(SunToolkit.DESKTOPFONTHINTS,
1693                            SunToolkit.getDesktopFontHints());
1694 
1695         Integer dragThreshold = null;
1696         synchronized (this) {
1697             dragThreshold = (Integer)desktopProperties.get("gnome.Net/DndDragThreshold");
1698         }
1699         if (dragThreshold != null) {
1700             setDesktopProperty("DnD.gestureMotionThreshold", dragThreshold);
1701         }
1702 
1703     }
1704 
1705 
1706 
1707     static int altMask;
1708     static int metaMask;
1709     static int numLockMask;
1710     static int modeSwitchMask;
1711     static int modLockIsShiftLock;
1712 
1713     /* Like XKeysymToKeycode, but ensures that keysym is the primary
1714     * symbol on the keycode returned.  Returns zero otherwise.
1715     */
1716     static int keysymToPrimaryKeycode(long sym) {
1717         awtLock();
1718         try {
1719             int code = XlibWrapper.XKeysymToKeycode(getDisplay(), sym);
1720             if (code == 0) {
1721                 return 0;
1722             }
1723             long primary = XlibWrapper.XKeycodeToKeysym(getDisplay(), code, 0);
1724             if (sym != primary) {
1725                 return 0;
1726             }
1727             return code;
1728         } finally {
1729             awtUnlock();
1730         }
1731     }
1732     static boolean getModifierState( int jkc ) {
1733         int iKeyMask = 0;
1734         long ks = XKeysym.javaKeycode2Keysym( jkc );
1735         int  kc = XlibWrapper.XKeysymToKeycode(getDisplay(), ks);
1736         if (kc == 0) {
1737             return false;
1738         }
1739         awtLock();
1740         try {
1741             XModifierKeymap modmap = new XModifierKeymap(
1742                  XlibWrapper.XGetModifierMapping(getDisplay()));
1743 
1744             int nkeys = modmap.get_max_keypermod();
1745 
1746             long map_ptr = modmap.get_modifiermap();
1747             for( int k = 0; k < 8; k++ ) {
1748                 for (int i = 0; i < nkeys; ++i) {
1749                     int keycode = Native.getUByte(map_ptr, k * nkeys + i);
1750                     if (keycode == 0) {
1751                         continue; // ignore zero keycode
1752                     }
1753                     if (kc == keycode) {
1754                         iKeyMask = 1 << k;
1755                         break;
1756                     }
1757                 }
1758                 if( iKeyMask != 0 ) {
1759                     break;
1760                 }
1761             }
1762             XlibWrapper.XFreeModifiermap(modmap.pData);
1763             if (iKeyMask == 0 ) {
1764                 return false;
1765             }
1766             // Now we know to which modifier is assigned the keycode
1767             // correspondent to the keysym correspondent to the java
1768             // keycode. We are going to check a state of this modifier.
1769             // If a modifier is a weird one, we cannot help it.
1770             long window = 0;
1771             try{
1772                 // get any application window
1773                 window = ((Long)(winMap.firstKey())).longValue();
1774             }catch(NoSuchElementException nex) {
1775                 // get root window
1776                 window = getDefaultRootWindow();
1777             }
1778             boolean res = XlibWrapper.XQueryPointer(getDisplay(), window,
1779                                             XlibWrapper.larg1, //root
1780                                             XlibWrapper.larg2, //child
1781                                             XlibWrapper.larg3, //root_x
1782                                             XlibWrapper.larg4, //root_y
1783                                             XlibWrapper.larg5, //child_x
1784                                             XlibWrapper.larg6, //child_y
1785                                             XlibWrapper.larg7);//mask
1786             int mask = Native.getInt(XlibWrapper.larg7);
1787             return ((mask & iKeyMask) != 0);
1788         } finally {
1789             awtUnlock();
1790         }
1791     }
1792 
1793     /* Assign meaning - alt, meta, etc. - to X modifiers mod1 ... mod5.
1794      * Only consider primary symbols on keycodes attached to modifiers.
1795      */
1796     static void setupModifierMap() {
1797         final int metaL = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_L);
1798         final int metaR = keysymToPrimaryKeycode(XKeySymConstants.XK_Meta_R);
1799         final int altL = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_L);
1800         final int altR = keysymToPrimaryKeycode(XKeySymConstants.XK_Alt_R);
1801         final int numLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Num_Lock);
1802         final int modeSwitch = keysymToPrimaryKeycode(XKeySymConstants.XK_Mode_switch);
1803         final int shiftLock = keysymToPrimaryKeycode(XKeySymConstants.XK_Shift_Lock);
1804         final int capsLock  = keysymToPrimaryKeycode(XKeySymConstants.XK_Caps_Lock);
1805 
1806         final int modmask[] = { XConstants.ShiftMask, XConstants.LockMask, XConstants.ControlMask, XConstants.Mod1Mask,
1807             XConstants.Mod2Mask, XConstants.Mod3Mask, XConstants.Mod4Mask, XConstants.Mod5Mask };
1808 
1809         log.fine("In setupModifierMap");
1810         awtLock();
1811         try {
1812             XModifierKeymap modmap = new XModifierKeymap(
1813                  XlibWrapper.XGetModifierMapping(getDisplay()));
1814 
1815             int nkeys = modmap.get_max_keypermod();
1816 
1817             long map_ptr = modmap.get_modifiermap();
1818 
1819             for (int modn = XConstants.Mod1MapIndex;
1820                  modn <= XConstants.Mod5MapIndex;
1821                  ++modn)
1822             {
1823                 for (int i = 0; i < nkeys; ++i) {
1824                     /* for each keycode attached to this modifier */
1825                     int keycode = Native.getUByte(map_ptr, modn * nkeys + i);
1826 
1827                     if (keycode == 0) {
1828                         break;
1829                     }
1830                     if (metaMask == 0 &&
1831                         (keycode == metaL || keycode == metaR))
1832                     {
1833                         metaMask = modmask[modn];
1834                         break;
1835                     }
1836                     if (altMask == 0 && (keycode == altL || keycode == altR)) {
1837                         altMask = modmask[modn];
1838                         break;
1839                     }
1840                     if (numLockMask == 0 && keycode == numLock) {
1841                         numLockMask = modmask[modn];
1842                         break;
1843                     }
1844                     if (modeSwitchMask == 0 && keycode == modeSwitch) {
1845                         modeSwitchMask = modmask[modn];
1846                         break;
1847                     }
1848                     continue;
1849                 }
1850             }
1851             modLockIsShiftLock = 0;
1852             for (int j = 0; j < nkeys; ++j) {
1853                 int keycode = Native.getUByte(map_ptr, XConstants.LockMapIndex * nkeys + j);
1854                 if (keycode == 0) {
1855                     break;
1856                 }
1857                 if (keycode == shiftLock) {
1858                     modLockIsShiftLock = 1;
1859                     break;
1860                 }
1861                 if (keycode == capsLock) {
1862                     break;
1863                 }
1864             }
1865             XlibWrapper.XFreeModifiermap(modmap.pData);
1866         } finally {
1867             awtUnlock();
1868         }
1869         if (log.isLoggable(PlatformLogger.Level.FINE)) {
1870             log.fine("metaMask = " + metaMask);
1871             log.fine("altMask = " + altMask);
1872             log.fine("numLockMask = " + numLockMask);
1873             log.fine("modeSwitchMask = " + modeSwitchMask);
1874             log.fine("modLockIsShiftLock = " + modLockIsShiftLock);
1875         }
1876     }
1877 
1878 
1879     private static SortedMap timeoutTasks;
1880 
1881     /**
1882      * Removed the task from the list of waiting-to-be called tasks.
1883      * If the task has been scheduled several times removes only first one.
1884      */
1885     static void remove(Runnable task) {
1886         if (task == null) {
1887             throw new NullPointerException("task is null");
1888         }
1889         awtLock();
1890         try {
1891             if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1892                 timeoutTaskLog.finer("Removing task " + task);
1893             }
1894             if (timeoutTasks == null) {
1895                 if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1896                     timeoutTaskLog.finer("Task is not scheduled");
1897                 }
1898                 return;
1899             }
1900             Collection values = timeoutTasks.values();
1901             Iterator iter = values.iterator();
1902             while (iter.hasNext()) {
1903                 java.util.List list = (java.util.List)iter.next();
1904                 boolean removed = false;
1905                 if (list.contains(task)) {
1906                     list.remove(task);
1907                     if (list.isEmpty()) {
1908                         iter.remove();
1909                     }
1910                     break;
1911                 }
1912             }
1913         } finally {
1914             awtUnlock();
1915         }
1916     }
1917 
1918     static native void wakeup_poll();
1919 
1920     /**
1921      * Registers a Runnable which <code>run()</code> method will be called
1922      * once on the toolkit thread when a specified interval of time elapses.
1923      *
1924      * @param task a Runnable which <code>run</code> method will be called
1925      *        on the toolkit thread when <code>interval</code> milliseconds
1926      *        elapse
1927      * @param interval an interal in milliseconds
1928      *
1929      * @throws NullPointerException if <code>task</code> is <code>null</code>
1930      * @throws IllegalArgumentException if <code>interval</code> is not positive
1931      */
1932     static void schedule(Runnable task, long interval) {
1933         if (task == null) {
1934             throw new NullPointerException("task is null");
1935         }
1936         if (interval <= 0) {
1937             throw new IllegalArgumentException("interval " + interval + " is not positive");
1938         }
1939 
1940         awtLock();
1941         try {
1942             if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1943                 timeoutTaskLog.finer("XToolkit.schedule(): current time={0}" +
1944                                      ";  interval={1}" +
1945                                      ";  task being added={2}" + ";  tasks before addition={3}",
1946                                      Long.valueOf(System.currentTimeMillis()), Long.valueOf(interval), task, timeoutTasks);
1947             }
1948 
1949             if (timeoutTasks == null) {
1950                 timeoutTasks = new TreeMap();
1951             }
1952 
1953             Long time = Long.valueOf(System.currentTimeMillis() + interval);
1954             java.util.List tasks = (java.util.List)timeoutTasks.get(time);
1955             if (tasks == null) {
1956                 tasks = new ArrayList(1);
1957                 timeoutTasks.put(time, tasks);
1958             }
1959             tasks.add(task);
1960 
1961 
1962             if (timeoutTasks.get(timeoutTasks.firstKey()) == tasks && tasks.size() == 1) {
1963                 // Added task became first task - poll won't know
1964                 // about it so we need to wake it up
1965                 wakeup_poll();
1966             }
1967         }  finally {
1968             awtUnlock();
1969         }
1970     }
1971 
1972     private long getNextTaskTime() {
1973         awtLock();
1974         try {
1975             if (timeoutTasks == null || timeoutTasks.isEmpty()) {
1976                 return -1L;
1977             }
1978             return (Long)timeoutTasks.firstKey();
1979         } finally {
1980             awtUnlock();
1981         }
1982     }
1983 
1984     /**
1985      * Executes mature timeout tasks registered with schedule().
1986      * Called from run() under awtLock.
1987      */
1988     private static void callTimeoutTasks() {
1989         if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
1990             timeoutTaskLog.finer("XToolkit.callTimeoutTasks(): current time={0}" +
1991                                  ";  tasks={1}", Long.valueOf(System.currentTimeMillis()), timeoutTasks);
1992         }
1993 
1994         if (timeoutTasks == null || timeoutTasks.isEmpty()) {
1995             return;
1996         }
1997 
1998         Long currentTime = Long.valueOf(System.currentTimeMillis());
1999         Long time = (Long)timeoutTasks.firstKey();
2000 
2001         while (time.compareTo(currentTime) <= 0) {
2002             java.util.List tasks = (java.util.List)timeoutTasks.remove(time);
2003 
2004             for (Iterator iter = tasks.iterator(); iter.hasNext();) {
2005                 Runnable task = (Runnable)iter.next();
2006 
2007                 if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) {
2008                     timeoutTaskLog.finer("XToolkit.callTimeoutTasks(): current time={0}" +
2009                                          ";  about to run task={1}", Long.valueOf(currentTime), task);
2010                 }
2011 
2012                 try {
2013                     task.run();
2014                 } catch (ThreadDeath td) {
2015                     throw td;
2016                 } catch (Throwable thr) {
2017                     processException(thr);
2018                 }
2019             }
2020 
2021             if (timeoutTasks.isEmpty()) {
2022                 break;
2023             }
2024             time = (Long)timeoutTasks.firstKey();
2025         }
2026     }
2027 
2028     static long getAwtDefaultFg() {
2029         return awt_defaultFg;
2030     }
2031 
2032     static boolean isLeftMouseButton(MouseEvent me) {
2033         switch (me.getID()) {
2034           case MouseEvent.MOUSE_PRESSED:
2035           case MouseEvent.MOUSE_RELEASED:
2036               return (me.getButton() == MouseEvent.BUTTON1);
2037           case MouseEvent.MOUSE_ENTERED:
2038           case MouseEvent.MOUSE_EXITED:
2039           case MouseEvent.MOUSE_CLICKED:
2040           case MouseEvent.MOUSE_DRAGGED:
2041               return ((me.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0);
2042         }
2043         return false;
2044     }
2045 
2046     static boolean isRightMouseButton(MouseEvent me) {
2047         int numButtons = ((Integer)getDefaultToolkit().getDesktopProperty("awt.mouse.numButtons")).intValue();
2048         switch (me.getID()) {
2049           case MouseEvent.MOUSE_PRESSED:
2050           case MouseEvent.MOUSE_RELEASED:
2051               return ((numButtons == 2 && me.getButton() == MouseEvent.BUTTON2) ||
2052                        (numButtons > 2 && me.getButton() == MouseEvent.BUTTON3));
2053           case MouseEvent.MOUSE_ENTERED:
2054           case MouseEvent.MOUSE_EXITED:
2055           case MouseEvent.MOUSE_CLICKED:
2056           case MouseEvent.MOUSE_DRAGGED:
2057               return ((numButtons == 2 && (me.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) ||
2058                       (numButtons > 2 && (me.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0));
2059         }
2060         return false;
2061     }
2062 
2063     static long reset_time_utc;
2064     static final long WRAP_TIME_MILLIS = 0x00000000FFFFFFFFL;
2065 
2066     /*
2067      * This function converts between the X server time (number of milliseconds
2068      * since the last server reset) and the UTC time for the 'when' field of an
2069      * InputEvent (or another event type with a timestamp).
2070      */
2071     static long nowMillisUTC_offset(long server_offset) {
2072         // ported from awt_util.c
2073         /*
2074          * Because Time is of type 'unsigned long', it is possible that Time will
2075          * never wrap when using 64-bit Xlib. However, if a 64-bit client
2076          * connects to a 32-bit server, I suspect the values will still wrap. So
2077          * we should not attempt to remove the wrap checking even if _LP64 is
2078          * true.
2079          */
2080 
2081         long current_time_utc = System.currentTimeMillis();
2082         if (log.isLoggable(PlatformLogger.Level.FINER)) {
2083             log.finer("reset_time=" + reset_time_utc + ", current_time=" + current_time_utc
2084                       + ", server_offset=" + server_offset + ", wrap_time=" + WRAP_TIME_MILLIS);
2085         }
2086 
2087         if ((current_time_utc - reset_time_utc) > WRAP_TIME_MILLIS) {
2088             reset_time_utc = System.currentTimeMillis() - getCurrentServerTime();
2089         }
2090 
2091         if (log.isLoggable(PlatformLogger.Level.FINER)) {
2092             log.finer("result = " + (reset_time_utc + server_offset));
2093         }
2094         return reset_time_utc + server_offset;
2095     }
2096 
2097     /**
2098      * @see sun.awt.SunToolkit#needsXEmbedImpl
2099      */
2100     protected boolean needsXEmbedImpl() {
2101         // XToolkit implements supports for XEmbed-client protocol and
2102         // requires the supports from the embedding host for it to work.
2103         return true;
2104     }
2105 
2106     public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
2107         return (modalityType == null) ||
2108                (modalityType == Dialog.ModalityType.MODELESS) ||
2109                (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
2110                (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
2111                (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
2112     }
2113 
2114     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
2115         return (exclusionType == null) ||
2116                (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
2117                (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
2118                (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
2119     }
2120 
2121     static EventQueue getEventQueue(Object target) {
2122         AppContext appContext = targetToAppContext(target);
2123         if (appContext != null) {
2124             return (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
2125         }
2126         return null;
2127     }
2128 
2129     static void removeSourceEvents(EventQueue queue,
2130                                    Object source,
2131                                    boolean removeAllEvents) {
2132         AWTAccessor.getEventQueueAccessor()
2133             .removeSourceEvents(queue, source, removeAllEvents);
2134     }
2135 
2136     public boolean isAlwaysOnTopSupported() {
2137         for (XLayerProtocol proto : XWM.getWM().getProtocols(XLayerProtocol.class)) {
2138             if (proto.supportsLayer(XLayerProtocol.LAYER_ALWAYS_ON_TOP)) {
2139                 return true;
2140             }
2141         }
2142         return false;
2143     }
2144 
2145     public boolean useBufferPerWindow() {
2146         return XToolkit.getBackingStoreType() == XConstants.NotUseful;
2147     }
2148 
2149     /**
2150      * Returns one of XConstants: NotUseful, WhenMapped or Always.
2151      * If backing store is not available on at least one screen, or
2152      * java2d uses DGA(which conflicts with backing store) on at least one screen,
2153      * or the string system property "sun.awt.backingStore" is neither "Always"
2154      * nor "WhenMapped", then the method returns XConstants.NotUseful.
2155      * Otherwise, if the system property "sun.awt.backingStore" is "WhenMapped",
2156      * then the method returns XConstants.WhenMapped.
2157      * Otherwise (i.e., if the system property "sun.awt.backingStore" is "Always"),
2158      * the method returns XConstants.Always.
2159      */
2160     static int getBackingStoreType() {
2161         return backingStoreType;
2162     }
2163 
2164     private static void setBackingStoreType() {
2165         String prop = (String)AccessController.doPrivileged(
2166                 new sun.security.action.GetPropertyAction("sun.awt.backingStore"));
2167 
2168         if (prop == null) {
2169             backingStoreType = XConstants.NotUseful;
2170             if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2171                 backingStoreLog.config("The system property sun.awt.backingStore is not set" +
2172                                        ", by default backingStore=NotUseful");
2173             }
2174             return;
2175         }
2176 
2177         if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2178             backingStoreLog.config("The system property sun.awt.backingStore is " + prop);
2179         }
2180         prop = prop.toLowerCase();
2181         if (prop.equals("always")) {
2182             backingStoreType = XConstants.Always;
2183         } else if (prop.equals("whenmapped")) {
2184             backingStoreType = XConstants.WhenMapped;
2185         } else {
2186             backingStoreType = XConstants.NotUseful;
2187         }
2188 
2189         if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2190             backingStoreLog.config("backingStore(as provided by the system property)=" +
2191                                    ( backingStoreType == XConstants.NotUseful ? "NotUseful"
2192                                      : backingStoreType == XConstants.WhenMapped ?
2193                                      "WhenMapped" : "Always") );
2194         }
2195 
2196         if (sun.java2d.x11.X11SurfaceData.isDgaAvailable()) {
2197             backingStoreType = XConstants.NotUseful;
2198 
2199             if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2200                 backingStoreLog.config("DGA is available, backingStore=NotUseful");
2201             }
2202 
2203             return;
2204         }
2205 
2206         awtLock();
2207         try {
2208             int screenCount = XlibWrapper.ScreenCount(getDisplay());
2209             for (int i = 0; i < screenCount; i++) {
2210                 if (XlibWrapper.DoesBackingStore(XlibWrapper.ScreenOfDisplay(getDisplay(), i))
2211                         == XConstants.NotUseful) {
2212                     backingStoreType = XConstants.NotUseful;
2213 
2214                     if (backingStoreLog.isLoggable(PlatformLogger.Level.CONFIG)) {
2215                         backingStoreLog.config("Backing store is not available on the screen " +
2216                                                i + ", backingStore=NotUseful");
2217                     }
2218 
2219                     return;
2220                 }
2221             }
2222         } finally {
2223             awtUnlock();
2224         }
2225     }
2226 
2227     /**
2228      * One of XConstants: NotUseful, WhenMapped or Always.
2229      */
2230     private static int backingStoreType;
2231 
2232     static final int XSUN_KP_BEHAVIOR = 1;
2233     static final int XORG_KP_BEHAVIOR = 2;
2234     static final int    IS_SUN_KEYBOARD = 1;
2235     static final int IS_NONSUN_KEYBOARD = 2;
2236     static final int    IS_KANA_KEYBOARD = 1;
2237     static final int IS_NONKANA_KEYBOARD = 2;
2238 
2239 
2240     static int     awt_IsXsunKPBehavior = 0;
2241     static boolean awt_UseXKB         = false;
2242     static boolean awt_UseXKB_Calls   = false;
2243     static int     awt_XKBBaseEventCode = 0;
2244     static int     awt_XKBEffectiveGroup = 0; // so far, I don't use it leaving all calculations
2245                                               // to XkbTranslateKeyCode
2246     static long    awt_XKBDescPtr     = 0;
2247 
2248     /**
2249      * Check for Xsun convention regarding numpad keys.
2250      * Xsun and some other servers (i.e. derived from Xsun)
2251      * under certain conditions process numpad keys unlike Xorg.
2252      */
2253     static boolean isXsunKPBehavior() {
2254         awtLock();
2255         try {
2256             if( awt_IsXsunKPBehavior == 0 ) {
2257                 if( XlibWrapper.IsXsunKPBehavior(getDisplay()) ) {
2258                     awt_IsXsunKPBehavior = XSUN_KP_BEHAVIOR;
2259                 }else{
2260                     awt_IsXsunKPBehavior = XORG_KP_BEHAVIOR;
2261                 }
2262             }
2263             return awt_IsXsunKPBehavior == XSUN_KP_BEHAVIOR ? true : false;
2264         } finally {
2265             awtUnlock();
2266         }
2267     }
2268 
2269     static int  sunOrNotKeyboard = 0;
2270     static int kanaOrNotKeyboard = 0;
2271     static void resetKeyboardSniffer() {
2272         sunOrNotKeyboard  = 0;
2273         kanaOrNotKeyboard = 0;
2274     }
2275     static boolean isSunKeyboard() {
2276         if( sunOrNotKeyboard == 0 ) {
2277             if( XlibWrapper.IsSunKeyboard( getDisplay() )) {
2278                 sunOrNotKeyboard = IS_SUN_KEYBOARD;
2279             }else{
2280                 sunOrNotKeyboard = IS_NONSUN_KEYBOARD;
2281             }
2282         }
2283         return (sunOrNotKeyboard == IS_SUN_KEYBOARD);
2284     }
2285     static boolean isKanaKeyboard() {
2286         if( kanaOrNotKeyboard == 0 ) {
2287             if( XlibWrapper.IsKanaKeyboard( getDisplay() )) {
2288                 kanaOrNotKeyboard = IS_KANA_KEYBOARD;
2289             }else{
2290                 kanaOrNotKeyboard = IS_NONKANA_KEYBOARD;
2291             }
2292         }
2293         return (kanaOrNotKeyboard == IS_KANA_KEYBOARD);
2294     }
2295     static boolean isXKBenabled() {
2296         awtLock();
2297         try {
2298             return awt_UseXKB;
2299         } finally {
2300             awtUnlock();
2301         }
2302     }
2303 
2304     /**
2305       Query XKEYBOARD extension.
2306       If possible, initialize xkb library.
2307     */
2308     static boolean tryXKB() {
2309         awtLock();
2310         try {
2311             String name = "XKEYBOARD";
2312             // First, if there is extension at all.
2313             awt_UseXKB = XlibWrapper.XQueryExtension( getDisplay(), name, XlibWrapper.larg1, XlibWrapper.larg2, XlibWrapper.larg3);
2314             if( awt_UseXKB ) {
2315                 // There is a keyboard extension. Check if a client library is compatible.
2316                 // If not, don't use xkb calls.
2317                 // In this case we still may be Xkb-capable application.
2318                 awt_UseXKB_Calls = XlibWrapper.XkbLibraryVersion( XlibWrapper.larg1, XlibWrapper.larg2);
2319                 if( awt_UseXKB_Calls ) {
2320                     awt_UseXKB_Calls = XlibWrapper.XkbQueryExtension( getDisplay(),  XlibWrapper.larg1, XlibWrapper.larg2,
2321                                      XlibWrapper.larg3, XlibWrapper.larg4, XlibWrapper.larg5);
2322                     if( awt_UseXKB_Calls ) {
2323                         awt_XKBBaseEventCode = Native.getInt(XlibWrapper.larg2);
2324                         XlibWrapper.XkbSelectEvents (getDisplay(),
2325                                          XConstants.XkbUseCoreKbd,
2326                                          XConstants.XkbNewKeyboardNotifyMask |
2327                                                  XConstants.XkbMapNotifyMask ,//|
2328                                                  //XConstants.XkbStateNotifyMask,
2329                                          XConstants.XkbNewKeyboardNotifyMask |
2330                                                  XConstants.XkbMapNotifyMask );//|
2331                                                  //XConstants.XkbStateNotifyMask);
2332 
2333                         XlibWrapper.XkbSelectEventDetails(getDisplay(), XConstants.XkbUseCoreKbd,
2334                                                      XConstants.XkbStateNotify,
2335                                                      XConstants.XkbGroupStateMask,
2336                                                      XConstants.XkbGroupStateMask);
2337                                                      //XXX ? XkbGroupLockMask last, XkbAllStateComponentsMask before last?
2338                         awt_XKBDescPtr = XlibWrapper.XkbGetMap(getDisplay(),
2339                                                      XConstants.XkbKeyTypesMask    |
2340                                                      XConstants.XkbKeySymsMask     |
2341                                                      XConstants.XkbModifierMapMask |
2342                                                      XConstants.XkbVirtualModsMask,
2343                                                      XConstants.XkbUseCoreKbd);
2344 
2345                         XlibWrapper.XkbSetDetectableAutoRepeat(getDisplay(), true);
2346                     }
2347                 }
2348             }
2349             return awt_UseXKB;
2350         } finally {
2351             awtUnlock();
2352         }
2353     }
2354     static boolean canUseXKBCalls() {
2355         awtLock();
2356         try {
2357             return awt_UseXKB_Calls;
2358         } finally {
2359             awtUnlock();
2360         }
2361     }
2362     static int getXKBEffectiveGroup() {
2363         awtLock();
2364         try {
2365             return awt_XKBEffectiveGroup;
2366         } finally {
2367             awtUnlock();
2368         }
2369     }
2370     static int getXKBBaseEventCode() {
2371         awtLock();
2372         try {
2373             return awt_XKBBaseEventCode;
2374         } finally {
2375             awtUnlock();
2376         }
2377     }
2378     static long getXKBKbdDesc() {
2379         awtLock();
2380         try {
2381             return awt_XKBDescPtr;
2382         } finally {
2383             awtUnlock();
2384         }
2385     }
2386     void freeXKB() {
2387         awtLock();
2388         try {
2389             if (awt_UseXKB_Calls && awt_XKBDescPtr != 0) {
2390                 XlibWrapper.XkbFreeKeyboard(awt_XKBDescPtr, 0xFF, true);
2391                 awt_XKBDescPtr = 0;
2392             }
2393         } finally {
2394             awtUnlock();
2395         }
2396     }
2397     private void processXkbChanges(XEvent ev) {
2398         // mapping change --> refresh kbd map
2399         // state change --> get a new effective group; do I really need it
2400         //  or that should be left for XkbTranslateKeyCode?
2401         XkbEvent xke = new XkbEvent( ev.getPData() );
2402         int xkb_type = xke.get_any().get_xkb_type();
2403         switch( xkb_type ) {
2404             case XConstants.XkbNewKeyboardNotify :
2405                  if( awt_XKBDescPtr != 0 ) {
2406                      freeXKB();
2407                  }
2408                  awt_XKBDescPtr = XlibWrapper.XkbGetMap(getDisplay(),
2409                                               XConstants.XkbKeyTypesMask    |
2410                                               XConstants.XkbKeySymsMask     |
2411                                               XConstants.XkbModifierMapMask |
2412                                               XConstants.XkbVirtualModsMask,
2413                                               XConstants.XkbUseCoreKbd);
2414                  //System.out.println("XkbNewKeyboard:"+(xke.get_new_kbd()));
2415                  break;
2416             case XConstants.XkbMapNotify :
2417                  //TODO: provide a simple unit test.
2418                  XlibWrapper.XkbGetUpdatedMap(getDisplay(),
2419                                               XConstants.XkbKeyTypesMask    |
2420                                               XConstants.XkbKeySymsMask     |
2421                                               XConstants.XkbModifierMapMask |
2422                                               XConstants.XkbVirtualModsMask,
2423                                               awt_XKBDescPtr);
2424                  //System.out.println("XkbMap:"+(xke.get_map()));
2425                  break;
2426             case XConstants.XkbStateNotify :
2427                  // May use it later e.g. to obtain an effective group etc.
2428                  //System.out.println("XkbState:"+(xke.get_state()));
2429                  break;
2430             default:
2431                  //System.out.println("XkbEvent of xkb_type "+xkb_type);
2432                  break;
2433         }
2434     }
2435 
2436     private static long eventNumber;
2437     public static long getEventNumber() {
2438         awtLock();
2439         try {
2440             return eventNumber;
2441         } finally {
2442             awtUnlock();
2443         }
2444     }
2445 
2446     private static XEventDispatcher oops_waiter;
2447     private static boolean oops_updated;
2448     private static int oops_position = 0;
2449 
2450     /**
2451      * @inheritDoc
2452      */
2453     protected boolean syncNativeQueue(final long timeout) {
2454         XBaseWindow win = XBaseWindow.getXAWTRootWindow();
2455 
2456         if (oops_waiter == null) {
2457             oops_waiter = new XEventDispatcher() {
2458                     public void dispatchEvent(XEvent e) {
2459                         if (e.get_type() == XConstants.ConfigureNotify) {
2460                             // OOPS ConfigureNotify event catched
2461                             oops_updated = true;
2462                             awtLockNotifyAll();
2463                         }
2464                     }
2465                 };
2466         }
2467 
2468         awtLock();
2469         try {
2470             addEventDispatcher(win.getWindow(), oops_waiter);
2471 
2472             oops_updated = false;
2473             long event_number = getEventNumber();
2474             // Generate OOPS ConfigureNotify event
2475             XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), ++oops_position, 0);
2476             // Change win position each time to avoid system optimization
2477             if (oops_position > 50) {
2478                 oops_position = 0;
2479             }
2480 
2481             XSync();
2482 
2483             eventLog.finer("Generated OOPS ConfigureNotify event");
2484 
2485             long start = System.currentTimeMillis();
2486             while (!oops_updated) {
2487                 try {
2488                     // Wait for OOPS ConfigureNotify event
2489                     awtLockWait(timeout);
2490                 } catch (InterruptedException e) {
2491                     throw new RuntimeException(e);
2492                 }
2493                 // This "while" is a protection from spurious
2494                 // wake-ups.  However, we shouldn't wait for too long
2495                 if ((System.currentTimeMillis() - start > timeout) && timeout >= 0) {
2496                     throw new OperationTimedOut(Long.toString(System.currentTimeMillis() - start));
2497                 }
2498             }
2499             // Don't take into account OOPS ConfigureNotify event
2500             return getEventNumber() - event_number > 1;
2501         } finally {
2502             removeEventDispatcher(win.getWindow(), oops_waiter);
2503             eventLog.finer("Exiting syncNativeQueue");
2504             awtUnlock();
2505         }
2506     }
2507     public void grab(Window w) {
2508         if (w.getPeer() != null) {
2509             ((XWindowPeer)w.getPeer()).setGrab(true);
2510         }
2511     }
2512 
2513     public void ungrab(Window w) {
2514         if (w.getPeer() != null) {
2515            ((XWindowPeer)w.getPeer()).setGrab(false);
2516         }
2517     }
2518     /**
2519      * Returns if the java.awt.Desktop class is supported on the current
2520      * desktop.
2521      * <p>
2522      * The methods of java.awt.Desktop class are supported on the Gnome desktop.
2523      * Check if the running desktop is Gnome by checking the window manager.
2524      */
2525     public boolean isDesktopSupported(){
2526         return XDesktopPeer.isDesktopSupported();
2527     }
2528 
2529     public DesktopPeer createDesktopPeer(Desktop target){
2530         return new XDesktopPeer();
2531     }
2532 
2533     public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
2534         return areExtraMouseButtonsEnabled;
2535     }
2536 
2537     @Override
2538     public boolean isWindowOpacitySupported() {
2539         XNETProtocol net_protocol = XWM.getWM().getNETProtocol();
2540 
2541         if (net_protocol == null) {
2542             return false;
2543         }
2544 
2545         return net_protocol.doOpacityProtocol();
2546     }
2547 
2548     @Override
2549     public boolean isWindowShapingSupported() {
2550         return XlibUtil.isShapingSupported();
2551     }
2552 
2553     @Override
2554     public boolean isWindowTranslucencySupported() {
2555         //NOTE: it may not be supported. The actual check is being performed
2556         //      at com.sun.awt.AWTUtilities(). In X11 we need to check
2557         //      whether there's any translucency-capable GC available.
2558         return true;
2559     }
2560 
2561     @Override
2562     public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
2563         if (!(gc instanceof X11GraphicsConfig)) {
2564             return false;
2565         }
2566         return ((X11GraphicsConfig)gc).isTranslucencyCapable();
2567     }
2568 
2569     /**
2570      * Returns the value of "sun.awt.disablegrab" property. Default
2571      * value is {@code false}.
2572      */
2573     public static boolean getSunAwtDisableGrab() {
2574         return AccessController.doPrivileged(new GetBooleanAction("sun.awt.disablegrab"));
2575     }
2576 }
--- EOF ---