--- old/src/solaris/classes/sun/awt/X11/XWM.java 2009-08-11 19:21:28.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XWM.java 2009-08-11 19:21:28.000000000 +0400 @@ -30,10 +30,10 @@ */ package sun.awt.X11; -import sun.misc.Unsafe; import java.awt.Insets; import java.awt.Frame; import java.awt.Rectangle; +import java.security.AccessController; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; @@ -42,6 +42,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import sun.misc.Unsafe; +import sun.security.action.GetIntegerAction; + /** * Class incapsulating knowledge about window managers in general * Descendants should provide some information about specific window manager. @@ -136,8 +139,6 @@ int WMID; - static final Insets zeroInsets = new Insets(0, 0, 0, 0); - static final Insets defaultInsets = new Insets(25, 5, 5, 5); XWM(int WMID) { this.WMID = WMID; @@ -149,21 +150,6 @@ } - static Insets normalize(Insets insets) { - if (insets.top > 64 || insets.top < 0) { - insets.top = 28; - } - if (insets.left > 32 || insets.left < 0) { - insets.left = 6; - } - if (insets.right > 32 || insets.right < 0) { - insets.right = 6; - } - if (insets.bottom > 32 || insets.bottom < 0) { - insets.bottom = 6; - } - return insets; - } static XNETProtocol g_net_protocol = null; static XWINProtocol g_win_protocol = null; @@ -281,6 +267,7 @@ XToolkit.getDefaultRootWindow(), XConstants.CWEventMask, substruct.pData); + XToolkit.XSync(); XToolkit.RESTORE_XERROR_HANDLER(); /* @@ -560,16 +547,32 @@ */ static boolean isMetacity() { return isNetWMName("Metacity"); -// || ( -// XA_NET_SUPPORTING_WM_CHECK. -// getIntProperty(XToolkit.getDefaultRootWindow(), XA_NET_SUPPORTING_WM_CHECK. -// getIntProperty(XToolkit.getDefaultRootWindow(), XAtom.XA_CARDINAL)) == 0); } - static boolean isNonReparentingWM() { + //XXX: Perhaps we need to consider OTHER_WM as non-reparenting also? + public static boolean isNonReparentingWM() { return (XWM.getWMID() == XWM.COMPIZ_WM || XWM.getWMID() == XWM.LG3D_WM); } + /** + * Indicates if the window manager does not send a synthetic + * ConfigureNotify when the user resizes the window using the left or top + * border of the window. + * In that cases we receive a real event only. + * See 6261336. + */ + public static boolean isNoSyntheticConfigureNotifyOnLeftTopResize() { + switch (XWM.getWMID()) { + case XWM.CDE_WM: + case XWM.MOTIF_WM: + case XWM.METACITY_WM: + case XWM.SAWFISH_WM: + return true; + default: + return false; + } + } + /* * Prepare IceWM check. * @@ -683,24 +686,41 @@ /* * Make an educated guess about running window manager. - * XXX: ideally, we should detect wm restart. + * XXX: would be nice to synchronize access to these variables. */ - static int awt_wmgr = XWM.UNDETERMINED_WM; - static XWM wm; + private static int awt_wmgr = XWM.UNDETERMINED_WM; + private static XWM wm; static XWM getWM() { if (wm == null) { - wm = new XWM(awt_wmgr = getWMID()/*XWM.OTHER_WM*/); + wm = new XWM(awt_wmgr = getWMID()); } return wm; } + + /** + * Indicates if there's currently a window manager running. + */ + public static boolean isRunning() { + return XWM.getWMID() != XWM.NO_WM; + } + + /** + * Resets the currently detected window manager. + * Must be called whenever we detect that the currently running window + * manager exits. + */ + public static void reset() { + awt_wmgr = XWM.UNDETERMINED_WM; + g_net_protocol = null; + g_win_protocol = null; + wm = null; + } + + static int getWMID() { if (insLog.isLoggable(Level.FINEST)) { insLog.finest("awt_wmgr = " + awt_wmgr); } - /* - * Ideally, we should support cases when a different WM is started - * during a Java app lifetime. - */ if (awt_wmgr != XWM.UNDETERMINED_WM) { return awt_wmgr; @@ -966,7 +986,8 @@ XToolkit.awtLock(); try { Rectangle shellBounds = window.getShellBounds(); - shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); + Insets insets = window.getNativeInsets(); + shellBounds.translate(-insets.left, -insets.top); window.updateSizeHints(window.getDimensions()); requestWMExtents(window.getWindow()); XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), @@ -1048,6 +1069,7 @@ case XWM.CDE_WM: return false; default: + //XXX: so what about compiz? return false; } } @@ -1264,30 +1286,23 @@ } } - HashMap storedInsets = new HashMap(); - Insets guessInsets(XDecoratedPeer window) { - Insets res = (Insets)storedInsets.get(window.getClass()); - if (res == null) { - switch (WMID) { - case ENLIGHTEN_WM: - res = new Insets(19, 4, 4, 4); - break; - case CDE_WM: - res = new Insets(28, 6, 6, 6); - break; - case NO_WM: - case LG3D_WM: - res = zeroInsets; - break; - case MOTIF_WM: - case OPENLOOK_WM: - default: - res = defaultInsets; - } + /** + * Returns the "default" insets for the currently running window manager. + */ + public final Insets getDefaultInsets() { + switch (WMID) { + case ENLIGHTEN_WM: + return new Insets(19, 4, 4, 4); + case CDE_WM: + return new Insets(28, 6, 6, 6); + case NO_WM: + case LG3D_WM: + return XDecoratedPeer.ZERO_INSETS; + default: + return null; } - if (insLog.isLoggable(Level.FINEST)) insLog.finest("WM guessed insets: " + res); - return res; } + /* * Some buggy WMs ignore window gravity when processing * ConfigureRequest and position window as if the gravity is Static. @@ -1401,11 +1416,13 @@ } /** - * Asks WM to fill Frame Extents (insets) for the window. + * Asks the WM to fill Frame Extents (insets) for the window. + * + * @return true if a request has been actually sent, false otherwise. */ - public static void requestWMExtents(long window) { + public static boolean requestWMExtents(long window) { if (window == XConstants.None) { // not initialized - return; + return false; } log.fine("Requesting FRAME_EXTENTS"); @@ -1425,6 +1442,7 @@ false, XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask, msg.getPData()); + return true; } if (getWMID() == XWM.KDE2_WM) { msg.set_message_type(XA_KDE_NET_WM_FRAME_STRUT.getAtom()); @@ -1432,204 +1450,99 @@ false, XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask, msg.getPData()); + return true; } - // XXX: should we wait for response? XIfEvent() would be useful here :) } finally { XToolkit.awtUnlock(); msg.dispose(); } + return false; } - /* syncTopLEvelPos() is necessary to insure that the window manager has in - * fact moved us to our final position relative to the reParented WM window. - * We have noted a timing window which our shell has not been moved so we - * screw up the insets thinking they are 0,0. Wait (for a limited period of - * time to let the WM hava a chance to move us. - * @param window window ID of the shell, assuming it is the window - * which will NOT have zero coordinates after the complete - * reparenting + /** + * Indicates if the given atom represents a property containing the extents + * of a frame. */ - boolean syncTopLevelPos(long window, XWindowAttributes attrs) { - int tries = 0; - XToolkit.awtLock(); - try { - do { - XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), window, attrs.pData); - if (attrs.get_x() != 0 || attrs.get_y() != 0) { - return true; - } - tries++; - XToolkit.XSync(); - } while (tries < 50); - } - finally { - XToolkit.awtUnlock(); - } - return false; + public static boolean isExtentsPropertyAtom(long atom) { + return atom == XA_KDE_NET_WM_FRAME_STRUT.getAtom() + || atom == XA_NET_FRAME_EXTENTS.getAtom() + || atom == XA_E_FRAME_SIZE.getAtom(); } - Insets getInsets(XDecoratedPeer win, long window, long parent) { - /* - * Unfortunately the concept of "insets" borrowed to AWT - * from Win32 is *absolutely*, *unbelievably* foreign to - * X11. Few WMs provide the size of frame decor - * (i.e. insets) in a property they set on the client - * window, so we check if we can get away with just - * peeking at it. [Future versions of wm-spec might add a - * standardized hint for this]. - * - * Otherwise we do some special casing. Actually the - * fallback code ("default" case) seems to cover most of - * the existing WMs (modulo Reparent/Configure order - * perhaps?). - * - * Fallback code tries to account for the two most common cases: - * - * . single reparenting - * parent window is the WM frame - * [twm, olwm, sawfish] - * - * . double reparenting - * parent is a lining exactly the size of the client - * grandpa is the WM frame - * [mwm, e!, kwin, fvwm2 ... ] - */ - Insets correctWM = XWM.getInsetsFromExtents(window); - insLog.log(Level.FINER, "Got insets from property: {0}", correctWM); + // Synchronization: XWM.class + private static Integer syncDelay = null; - if (correctWM == null) { - correctWM = new Insets(0,0,0,0); + /** + * Retrieves the synchronization delay in milliseconds. + * + * Sending a request to the window manager and doing XSync(), we do not + * immediately get the requested result because the window manager is not + * the X server, but a separate process. An example of such request is the + * _NET_REQUEST_FRAME_EXTENTS: the _NET_FRAME_EXTENTS window property may + * be updated with a delay after the request has been dispatched to the X + * server via the XSync() method. + * + * To wait for the response we need a delay value. This method is supposed + * to return a reasonable value for such delay. The default value is + * considered fine when running on a local display. However, for + * connections over TCP, SSH, or other types of connections, the delay may + * have to be increased. For such purposes there's a private system + * property: sun.awt.wmsyncdelay that may be set to an integer value + * representing the number of milliseconds to wait for a window manager's + * reposnse. + */ + public static synchronized long getSyncDelay() { + if (syncDelay == null) { + syncDelay = AccessController.doPrivileged( + new GetIntegerAction("sun.awt.wmsyncdelay", 150)); + } + return syncDelay; + } + + private static XlibWrapper.CheckEventPredicate + checkExtentsUpdateEventPredicate = + new XlibWrapper.CheckEventPredicate() { + public boolean doesMatch(XEvent event) { + return event.get_type() == XConstants.PropertyNotify + && isExtentsPropertyAtom(event.get_xproperty().get_atom()); + } + }; - correctWM.top = -1; - correctWM.left = -1; + /** + * Waits for a PropertyNotify containing the requested frame extents. + * + * @return the PropertyNotify event, or null if nothing got dispatched + */ + public static XEvent waitForExtentsUpdateEvent() { + final long TRIES = 5; + long timeout = getSyncDelay(); + if (timeout < TRIES) { + timeout = TRIES; + } + final long delay = timeout / TRIES; - XWindowAttributes lwinAttr = new XWindowAttributes(); - XWindowAttributes pattr = new XWindowAttributes(); + XEvent event = null; + do { + XToolkit.awtLock(); try { - switch (XWM.getWMID()) { - /* should've been done in awt_wm_getInsetsFromProp */ - case XWM.ENLIGHTEN_WM: { - /* enlightenment does double reparenting */ - syncTopLevelPos(parent, lwinAttr); - correctWM.left = lwinAttr.get_x(); - correctWM.top = lwinAttr.get_y(); - /* - * Now get the actual dimensions of the parent window - * resolve the difference. We can't rely on the left - * to be equal to right or bottom... Enlightment - * breaks that assumption. - */ - XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - XlibUtil.getParentWindow(parent), - pattr.pData); - correctWM.right = pattr.get_width() - - (lwinAttr.get_width() + correctWM.left); - correctWM.bottom = pattr.get_height() - - (lwinAttr.get_height() + correctWM.top); - - break; - } - case XWM.ICE_WM: // for 1.2.2. - case XWM.KDE2_WM: /* should've been done in getInsetsFromProp */ - case XWM.CDE_WM: - case XWM.MOTIF_WM: { - /* these are double reparenting too */ - if (syncTopLevelPos(parent, lwinAttr)) { - correctWM.top = lwinAttr.get_y(); - correctWM.left = lwinAttr.get_x(); - correctWM.right = correctWM.left; - correctWM.bottom = correctWM.left; - } else { - return null; - } - break; - } - case XWM.SAWFISH_WM: - case XWM.OPENLOOK_WM: { - /* single reparenting */ - syncTopLevelPos(window, lwinAttr); - correctWM.top = lwinAttr.get_y(); - correctWM.left = lwinAttr.get_x(); - correctWM.right = correctWM.left; - correctWM.bottom = correctWM.left; - break; - } - case XWM.OTHER_WM: - default: { /* this is very similar to the E! case above */ - insLog.log(Level.FINEST, "Getting correct insets for OTHER_WM/default, parent: {0}", parent); - syncTopLevelPos(parent, lwinAttr); - int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - window, lwinAttr.pData); - status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - parent, pattr.pData); - if (lwinAttr.get_root() == parent) { - insLog.finest("our parent is root so insets should be zero"); - correctWM = new Insets(0, 0, 0, 0); - break; - } - - /* - * Check for double-reparenting WM. - * - * If the parent is exactly the same size as the - * top-level assume taht it's the "lining" window and - * that the grandparent is the actual frame (NB: we - * have already handled undecorated windows). - * - * XXX: what about timing issues that syncTopLevelPos - * is supposed to work around? - */ - if (lwinAttr.get_x() == 0 && lwinAttr.get_y() == 0 - && lwinAttr.get_width()+2*lwinAttr.get_border_width() == pattr.get_width() - && lwinAttr.get_height()+2*lwinAttr.get_border_width() == pattr.get_height()) - { - insLog.log(Level.FINEST, "Double reparenting detected, pattr({2})={0}, lwinAttr({3})={1}", - new Object[] {lwinAttr, pattr, parent, window}); - lwinAttr.set_x(pattr.get_x()); - lwinAttr.set_y(pattr.get_y()); - lwinAttr.set_border_width(lwinAttr.get_border_width()+pattr.get_border_width()); - - final long grand_parent = XlibUtil.getParentWindow(parent); - - if (grand_parent == lwinAttr.get_root()) { - // This is not double-reparenting in a - // general sense - we simply don't have - // correct insets - return null to try to - // get insets later - return null; - } else { - parent = grand_parent; - XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - parent, - pattr.pData); - } - } - /* - * XXX: To be absolutely correct, we'd need to take - * parent's border-width into account too, but the - * rest of the code is happily unaware about border - * widths and inner/outer distinction, so for the time - * being, just ignore it. - */ - insLog.log(Level.FINEST, "Attrs before calculation: pattr({2})={0}, lwinAttr({3})={1}", - new Object[] {lwinAttr, pattr, parent, window}); - correctWM = new Insets(lwinAttr.get_y() + lwinAttr.get_border_width(), - lwinAttr.get_x() + lwinAttr.get_border_width(), - pattr.get_height() - (lwinAttr.get_y() + lwinAttr.get_height() + 2*lwinAttr.get_border_width()), - pattr.get_width() - (lwinAttr.get_x() + lwinAttr.get_width() + 2*lwinAttr.get_border_width())); - break; - } /* default */ - } /* switch (runningWM) */ + XToolkit.XSync(); + event = XlibWrapper.CheckIfEvent(XToolkit.getDisplay(), + checkExtentsUpdateEventPredicate); } finally { - lwinAttr.dispose(); - pattr.dispose(); + XToolkit.awtUnlock(); } - } - if (storedInsets.get(win.getClass()) == null) { - storedInsets.put(win.getClass(), correctWM); - } - return correctWM; + if (event != null) { + break; + } + try { + Thread.sleep(delay); + } catch (InterruptedException ex) { + } + } while ((timeout -= delay) > 0); + + return event; } + boolean isDesktopWindow( long w ) { if (g_net_protocol != null) { XAtomList wtype = XAtom.get("_NET_WM_WINDOW_TYPE").getAtomListPropertyList( w );