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