1 /*
   2  * Copyright 2006-2008 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any 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 /*
  42  * This class is a collection of utility methods that operate
  43  * with native windows.
  44  */
  45 public 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 relative to its parent.
 104      */
 105     public static Rectangle getWindowGeometry(long window) {
 106         XToolkit.awtLock();
 107         try {
 108             return getWindowGeometry(window, XlibWrapper.larg1);
 109         } finally {
 110             XToolkit.awtUnlock();
 111         }
 112     }
 113 
 114     /**
 115      * Returns the bounds of the given window relative to its parent.
 116      * The unsafe memory pointed to by the rootWindowBuffer will
 117      * contain the root window of the given window.
 118      * WARNING: DO NOT USE XlibWrapper.larg[2..7] as the rootWindowBuffer!
 119      * Only larg1 or larg8 can be used, or some other allocated memory block.
 120      */
 121     public static Rectangle getWindowGeometry(long window, long rootWindowBuffer)
 122     {
 123         XToolkit.awtLock();
 124         try
 125         {
 126             int res = XlibWrapper.XGetGeometry(XToolkit.getDisplay(),
 127                                                window,
 128                                                rootWindowBuffer, // root_return
 129                                                XlibWrapper.larg2, // x_return
 130                                                XlibWrapper.larg3, // y_return
 131                                                XlibWrapper.larg4, // width_return
 132                                                XlibWrapper.larg5, // height_return
 133                                                XlibWrapper.larg6, // border_width_return
 134                                                XlibWrapper.larg7); // depth_return
 135             if (res == 0)
 136             {
 137                 return null;
 138             }
 139 
 140             int x = Native.getInt(XlibWrapper.larg2);
 141             int y = Native.getInt(XlibWrapper.larg3);
 142             long width = Native.getUInt(XlibWrapper.larg4);
 143             long height = Native.getUInt(XlibWrapper.larg5);
 144 
 145             return new Rectangle(x, y, (int)width, (int)height);
 146         }
 147         finally
 148         {
 149             XToolkit.awtUnlock();
 150         }
 151     }
 152 
 153     /**
 154      * Translates the given point from one window to another. Returns
 155      * null if the translation is failed
 156      */
 157     static Point translateCoordinates(long src, long dst, Point p)
 158     {
 159         Point translated = null;
 160 
 161         XToolkit.awtLock();
 162         try
 163         {
 164             XTranslateCoordinates xtc =
 165                 new XTranslateCoordinates(src, dst, p.x, p.y);
 166             try
 167             {
 168                 int status = xtc.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 169                 if ((status != 0) &&
 170                     ((XToolkit.saved_error == null) ||
 171                      (XToolkit.saved_error.get_error_code() == XConstants.Success)))
 172                 {
 173                     translated = new Point(xtc.get_dest_x(), xtc.get_dest_y());
 174                 }
 175             }
 176             finally
 177             {
 178                 xtc.dispose();
 179             }
 180         }
 181         finally
 182         {
 183             XToolkit.awtUnlock();
 184         }
 185 
 186         return translated;
 187     }
 188 
 189     /**
 190      * Translates the given rectangle from one window to another.
 191      * Returns null if the translation is failed
 192      */
 193     static Rectangle translateCoordinates(long src, long dst, Rectangle r)
 194     {
 195         Point translatedLoc = translateCoordinates(src, dst, r.getLocation());
 196         if (translatedLoc == null)
 197         {
 198             return null;
 199         }
 200         else
 201         {
 202             return new Rectangle(translatedLoc, r.getSize());
 203         }
 204     }
 205 
 206     /**
 207      * Returns the parent for the given window
 208      */
 209     static long getParentWindow(long window)
 210     {
 211         XToolkit.awtLock();
 212         try
 213         {
 214             XBaseWindow bw = XToolkit.windowToXWindow(window);
 215             if (bw != null)
 216             {
 217                 XBaseWindow pbw = bw.getParentWindow();
 218                 if (pbw != null)
 219                 {
 220                     return pbw.getWindow();
 221                 }
 222             }
 223 
 224             XQueryTree qt = new XQueryTree(window);
 225             try
 226             {
 227                 if (qt.execute() == 0)
 228                 {
 229                     return XConstants.None;
 230                 }
 231                 else
 232                 {
 233                     return qt.get_parent();
 234                 }
 235             }
 236             finally
 237             {
 238                 qt.dispose();
 239             }
 240         }
 241         finally
 242         {
 243             XToolkit.awtUnlock();
 244         }
 245     }
 246 
 247     /**
 248      * Returns all the children for the given window
 249      */
 250     static Set<Long> getChildWindows(long window)
 251     {
 252         XToolkit.awtLock();
 253         try
 254         {
 255             XBaseWindow bw = XToolkit.windowToXWindow(window);
 256             if (bw != null)
 257             {
 258                 return bw.getChildren();
 259             }
 260 
 261             XQueryTree xqt = new XQueryTree(window);
 262             try
 263             {
 264                 int status = xqt.execute();
 265                 if (status == 0)
 266                 {
 267                     return Collections.emptySet();
 268                 }
 269 
 270                 long children = xqt.get_children();
 271 
 272                 if (children == 0)
 273                 {
 274                     return Collections.emptySet();
 275                 }
 276 
 277                 int childrenCount = xqt.get_nchildren();
 278 
 279                 Set<Long> childrenSet = new HashSet<Long>(childrenCount);
 280                 for (int i = 0; i < childrenCount; i++)
 281                 {
 282                     childrenSet.add(Native.getWindow(children, i));
 283                 }
 284 
 285                 return childrenSet;
 286             }
 287             finally
 288             {
 289                 xqt.dispose();
 290             }
 291         }
 292         finally
 293         {
 294             XToolkit.awtUnlock();
 295         }
 296     }
 297 
 298     /**
 299      * Checks if the given window is a Java window and is an
 300      * instance of XWindowPeer
 301      */
 302     static boolean isXAWTToplevelWindow(long window)
 303     {
 304         return XToolkit.windowToXWindow(window) instanceof XWindowPeer;
 305     }
 306 
 307     /**
 308      * NOTICE: Right now returns only decorated top-levels (not Window)
 309      */
 310     static boolean isToplevelWindow(long window)
 311     {
 312         if (XToolkit.windowToXWindow(window) instanceof XDecoratedPeer)
 313         {
 314             return true;
 315         }
 316 
 317         XToolkit.awtLock();
 318         try
 319         {
 320             WindowPropertyGetter wpg =
 321                 new WindowPropertyGetter(window, XWM.XA_WM_STATE, 0, 1, false,
 322                                          XWM.XA_WM_STATE);
 323             try
 324             {
 325                 wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 326                 if (wpg.getActualType() == XWM.XA_WM_STATE.getAtom())
 327                 {
 328                     return true;
 329                 }
 330             }
 331             finally
 332             {
 333                 wpg.dispose();
 334             }
 335 
 336             return false;
 337         }
 338         finally
 339         {
 340             XToolkit.awtUnlock();
 341         }
 342     }
 343 
 344     /**
 345      * The same as isToplevelWindow(window), but doesn't treat
 346      * XEmbeddedFramePeer as toplevel.
 347      */
 348     static boolean isTrueToplevelWindow(long window)
 349     {
 350         if (XToolkit.windowToXWindow(window) instanceof XEmbeddedFramePeer)
 351         {
 352             return false;
 353         }
 354 
 355         return isToplevelWindow(window);
 356     }
 357 
 358     static int getWindowMapState(long window)
 359     {
 360         XToolkit.awtLock();
 361         XWindowAttributes wattr = new XWindowAttributes();
 362         try
 363         {
 364             XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 365             int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
 366                                                           window, wattr.pData);
 367             XToolkit.RESTORE_XERROR_HANDLER();
 368             if ((status != 0) &&
 369                 ((XToolkit.saved_error == null) ||
 370                  (XToolkit.saved_error.get_error_code() == XConstants.Success)))
 371             {
 372                 return wattr.get_map_state();
 373             }
 374         }
 375         finally
 376         {
 377             wattr.dispose();
 378             XToolkit.awtUnlock();
 379         }
 380 
 381         return XConstants.IsUnmapped;
 382     }
 383 
 384     /**
 385      * XSHAPE extension support.
 386      */
 387 
 388     // The variable is declared static as the XSHAPE extension cannot
 389     // be disabled at run-time, and thus is available all the time
 390     // once the check is passed.
 391     static Boolean isShapingSupported = null;
 392 
 393     /**
 394      *  Returns whether the XSHAPE extension available
 395      *  @since 1.7
 396      */
 397     static synchronized boolean isShapingSupported() {
 398 
 399         if (isShapingSupported == null) {
 400             XToolkit.awtLock();
 401             try {
 402                 isShapingSupported =
 403                     XlibWrapper.XShapeQueryExtension(
 404                             XToolkit.getDisplay(),
 405                             XlibWrapper.larg1,
 406                             XlibWrapper.larg2);
 407             } finally {
 408                 XToolkit.awtUnlock();
 409             }
 410         }
 411 
 412         return isShapingSupported.booleanValue();
 413     }
 414 
 415 }