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