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