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