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