1/*
2 * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.awt.X11;
27
28import java.awt.Dimension;
29import java.awt.GraphicsEnvironment;
30import java.awt.Point;
31import java.awt.Rectangle;
32
33import java.util.Collections;
34import java.util.HashSet;
35import java.util.Set;
36
37import sun.awt.X11GraphicsConfig;
38import sun.awt.X11GraphicsDevice;
39import sun.awt.X11GraphicsEnvironment;
40
41/*
42 * This class is a collection of utility methods that operate
43 * with native windows.
44 */
45public class XlibUtil
46{
47    /**
48     * The constructor is made private to eliminate any
49     * instances of this class
50    */
51    private XlibUtil()
52    {
53    }
54
55    /**
56     * Xinerama-aware version of XlibWrapper.RootWindow method.
57     */
58    public static long getRootWindow(int screenNumber)
59    {
60        XToolkit.awtLock();
61        try
62        {
63            X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment)
64                GraphicsEnvironment.getLocalGraphicsEnvironment();
65            if (x11ge.runningXinerama())
66            {
67                // all the Xinerama windows share the same root window
68                return XlibWrapper.RootWindow(XToolkit.getDisplay(), 0);
69            }
70            else
71            {
72                return XlibWrapper.RootWindow(XToolkit.getDisplay(), screenNumber);
73            }
74        }
75        finally
76        {
77            XToolkit.awtUnlock();
78        }
79    }
80
81    /**
82     * Checks if the given window is a root window for the given screen
83     */
84    static boolean isRoot(long rootCandidate, long screenNumber)
85    {
86        long root;
87
88        XToolkit.awtLock();
89        try
90        {
91            root = XlibWrapper.RootWindow(XToolkit.getDisplay(),
92                                          screenNumber);
93        }
94        finally
95        {
96            XToolkit.awtUnlock();
97        }
98
99        return root == rootCandidate;
100    }
101
102    /**
103     * Returns the bounds of the given window, in absolute coordinates
104     */
105    static Rectangle getWindowGeometry(long window, int scale)
106    {
107        XToolkit.awtLock();
108        try
109        {
110            int res = XlibWrapper.XGetGeometry(XToolkit.getDisplay(),
111                                               window,
112                                               XlibWrapper.larg1, // root_return
113                                               XlibWrapper.larg2, // x_return
114                                               XlibWrapper.larg3, // y_return
115                                               XlibWrapper.larg4, // width_return
116                                               XlibWrapper.larg5, // height_return
117                                               XlibWrapper.larg6, // border_width_return
118                                               XlibWrapper.larg7); // depth_return
119            if (res == 0)
120            {
121                return null;
122            }
123
124            int x = Native.getInt(XlibWrapper.larg2);
125            int y = Native.getInt(XlibWrapper.larg3);
126            long width = Native.getUInt(XlibWrapper.larg4);
127            long height = Native.getUInt(XlibWrapper.larg5);
128
129            return new Rectangle(scaleDown(x, scale), scaleDown(y, scale),
130                                 scaleDown((int) width, scale),
131                                 scaleDown((int) height, scale));
132        }
133        finally
134        {
135            XToolkit.awtUnlock();
136        }
137    }
138
139    /**
140     * Translates the given point from one window to another. Returns
141     * null if the translation is failed
142     */
143    static Point translateCoordinates(long src, long dst, Point p, int scale)
144    {
145        Point translated = null;
146
147        XToolkit.awtLock();
148        try
149        {
150            XTranslateCoordinates xtc =
151                new XTranslateCoordinates(src, dst, p.x * scale, p.y * scale);
152            try
153            {
154                int status = xtc.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
155                if ((status != 0) &&
156                    ((XErrorHandlerUtil.saved_error == null) ||
157                    (XErrorHandlerUtil.saved_error.get_error_code() == XConstants.Success)))
158                {
159                    translated = new Point(scaleDown(xtc.get_dest_x(), scale),
160                                           scaleDown(xtc.get_dest_y(), scale));
161                }
162            }
163            finally
164            {
165                xtc.dispose();
166            }
167        }
168        finally
169        {
170            XToolkit.awtUnlock();
171        }
172
173        return translated;
174    }
175
176    /**
177     * Translates the given rectangle from one window to another.
178     * Returns null if the translation is failed
179     */
180    static Rectangle translateCoordinates(long src, long dst, Rectangle r,
181                                          int scale)
182    {
183        Point translatedLoc = translateCoordinates(src, dst, r.getLocation(),
184                                                   scale);
185
186        if (translatedLoc == null)
187        {
188            return null;
189        }
190        else
191        {
192            return new Rectangle(translatedLoc, r.getSize());
193        }
194    }
195
196    /**
197     * Returns the parent for the given window
198     */
199    static long getParentWindow(long window)
200    {
201        XToolkit.awtLock();
202        try
203        {
204            XBaseWindow bw = XToolkit.windowToXWindow(window);
205            if (bw != null)
206            {
207                XBaseWindow pbw = bw.getParentWindow();
208                if (pbw != null)
209                {
210                    return pbw.getWindow();
211                }
212            }
213
214            XQueryTree qt = new XQueryTree(window);
215            try
216            {
217                if (qt.execute() == 0)
218                {
219                    return 0;
220                }
221                else
222                {
223                    return qt.get_parent();
224                }
225            }
226            finally
227            {
228                qt.dispose();
229            }
230        }
231        finally
232        {
233            XToolkit.awtUnlock();
234        }
235    }
236
237    /**
238     * Returns all the children for the given window
239     */
240    static Set<Long> getChildWindows(long window)
241    {
242        XToolkit.awtLock();
243        try
244        {
245            XBaseWindow bw = XToolkit.windowToXWindow(window);
246            if (bw != null)
247            {
248                return bw.getChildren();
249            }
250
251            XQueryTree xqt = new XQueryTree(window);
252            try
253            {
254                int status = xqt.execute();
255                if (status == 0)
256                {
257                    return Collections.emptySet();
258                }
259
260                long children = xqt.get_children();
261
262                if (children == 0)
263                {
264                    return Collections.emptySet();
265                }
266
267                int childrenCount = xqt.get_nchildren();
268
269                Set<Long> childrenSet = new HashSet<Long>(childrenCount);
270                for (int i = 0; i < childrenCount; i++)
271                {
272                    childrenSet.add(Native.getWindow(children, i));
273                }
274
275                return childrenSet;
276            }
277            finally
278            {
279                xqt.dispose();
280            }
281        }
282        finally
283        {
284            XToolkit.awtUnlock();
285        }
286    }
287
288    /**
289     * Checks if the given window is a Java window and is an
290     * instance of XWindowPeer
291     */
292    static boolean isXAWTToplevelWindow(long window)
293    {
294        return XToolkit.windowToXWindow(window) instanceof XWindowPeer;
295    }
296
297    /**
298     * NOTICE: Right now returns only decorated top-levels (not Window)
299     */
300    static boolean isToplevelWindow(long window)
301    {
302        if (XToolkit.windowToXWindow(window) instanceof XDecoratedPeer)
303        {
304            return true;
305        }
306
307        XToolkit.awtLock();
308        try
309        {
310            WindowPropertyGetter wpg =
311                new WindowPropertyGetter(window, XWM.XA_WM_STATE, 0, 1, false,
312                                         XWM.XA_WM_STATE);
313            try
314            {
315                wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
316                if (wpg.getActualType() == XWM.XA_WM_STATE.getAtom())
317                {
318                    return true;
319                }
320            }
321            finally
322            {
323                wpg.dispose();
324            }
325
326            return false;
327        }
328        finally
329        {
330            XToolkit.awtUnlock();
331        }
332    }
333
334    /**
335     * The same as isToplevelWindow(window), but doesn't treat
336     * XEmbeddedFramePeer as toplevel.
337     */
338    static boolean isTrueToplevelWindow(long window)
339    {
340        if (XToolkit.windowToXWindow(window) instanceof XEmbeddedFramePeer)
341        {
342            return false;
343        }
344
345        return isToplevelWindow(window);
346    }
347
348    static int getWindowMapState(long window)
349    {
350        XToolkit.awtLock();
351        XWindowAttributes wattr = new XWindowAttributes();
352        try
353        {
354            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
355            int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
356                                                          window, wattr.pData);
357            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
358            if ((status != 0) &&
359                ((XErrorHandlerUtil.saved_error == null) ||
360                (XErrorHandlerUtil.saved_error.get_error_code() == XConstants.Success)))
361            {
362                return wattr.get_map_state();
363            }
364        }
365        finally
366        {
367            wattr.dispose();
368            XToolkit.awtUnlock();
369        }
370
371        return XConstants.IsUnmapped;
372    }
373
374    /**
375     * XSHAPE extension support.
376     */
377
378    // The variable is declared static as the XSHAPE extension cannot
379    // be disabled at run-time, and thus is available all the time
380    // once the check is passed.
381    static Boolean isShapingSupported = null;
382
383    /**
384     *  Returns whether the XSHAPE extension available
385     *  @since 1.7
386     */
387    static synchronized boolean isShapingSupported() {
388
389        if (isShapingSupported == null) {
390            XToolkit.awtLock();
391            try {
392                isShapingSupported =
393                    XlibWrapper.XShapeQueryExtension(
394                            XToolkit.getDisplay(),
395                            XlibWrapper.larg1,
396                            XlibWrapper.larg2);
397            } finally {
398                XToolkit.awtUnlock();
399            }
400        }
401
402        return isShapingSupported.booleanValue();
403    }
404
405    static int getButtonMask(int button) {
406        // Button indices start with 1. The first bit in the button mask is the 8th.
407        // The state mask does not support button indicies > 5, so we need to
408        // cut there.
409        if (button <= 0 || button > XConstants.MAX_BUTTONS) {
410            return 0;
411        } else {
412            return 1 << (7 + button);
413        }
414    }
415
416    static int scaleDown(int x, int scale) {
417        return x / scale;
418    }
419}
420