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