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