src/solaris/classes/sun/awt/X11/XWM.java

Print this page

        

*** 28,49 **** * Ported from awt_wm.c, SCCS v1.11, author Valeriy Ushakov * Author: Denis Mikhalkin */ package sun.awt.X11; - import sun.misc.Unsafe; import java.awt.Insets; import java.awt.Frame; import java.awt.Rectangle; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Class incapsulating knowledge about window managers in general * Descendants should provide some information about specific window manager. */ final class XWM --- 28,52 ---- * Ported from awt_wm.c, SCCS v1.11, author Valeriy Ushakov * Author: Denis Mikhalkin */ package sun.awt.X11; 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; import java.util.logging.Level; import java.util.logging.Logger; 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. */ final class XWM
*** 134,145 **** } } 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; initializeProtocols(); if (log.isLoggable(Level.FINE)) log.fine("Window manager: " + toString()); --- 137,146 ----
*** 147,171 **** int getID() { return WMID; } - 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; static boolean isNetWMName(String name) { if (g_net_protocol != null) { --- 148,157 ----
*** 279,288 **** --- 265,275 ---- XToolkit.WITH_XERROR_HANDLER(detectWMHandler); XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), XConstants.CWEventMask, substruct.pData); + XToolkit.XSync(); XToolkit.RESTORE_XERROR_HANDLER(); /* * If no WM is running then our selection for SubstructureRedirect * succeeded and needs to be undone (hey we are *not* a WM ;-).
*** 558,577 **** /* * Is Metacity running? */ 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() { return (XWM.getWMID() == XWM.COMPIZ_WM || XWM.getWMID() == XWM.LG3D_WM); } /* * Prepare IceWM check. * * The only way to detect IceWM, seems to be by setting * _ICEWM_WINOPTHINT(_ICEWM_WINOPTHINT/8) on root and checking if it --- 545,580 ---- /* * Is Metacity running? */ static boolean isMetacity() { return isNetWMName("Metacity"); } ! //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. * * The only way to detect IceWM, seems to be by setting * _ICEWM_WINOPTHINT(_ICEWM_WINOPTHINT/8) on root and checking if it
*** 681,708 **** } }; /* * Make an educated guess about running window manager. ! * XXX: ideally, we should detect wm restart. */ ! static int awt_wmgr = XWM.UNDETERMINED_WM; ! static XWM wm; static XWM getWM() { if (wm == null) { ! wm = new XWM(awt_wmgr = getWMID()/*XWM.OTHER_WM*/); } return wm; } 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; } --- 684,728 ---- } }; /* * Make an educated guess about running window manager. ! * XXX: would be nice to synchronize access to these variables. */ ! private static int awt_wmgr = XWM.UNDETERMINED_WM; ! private static XWM wm; static XWM getWM() { if (wm == null) { ! 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); } if (awt_wmgr != XWM.UNDETERMINED_WM) { return awt_wmgr; }
*** 964,974 **** static void setShellResizable(XDecoratedPeer window) { if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell resizable " + window); XToolkit.awtLock(); try { Rectangle shellBounds = window.getShellBounds(); ! shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); window.updateSizeHints(window.getDimensions()); requestWMExtents(window.getWindow()); XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height); /* REMINDER: will need to revisit when setExtendedStateBounds is added */ --- 984,995 ---- static void setShellResizable(XDecoratedPeer window) { if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell resizable " + window); XToolkit.awtLock(); try { Rectangle shellBounds = window.getShellBounds(); ! Insets insets = window.getNativeInsets(); ! shellBounds.translate(-insets.left, -insets.top); window.updateSizeHints(window.getDimensions()); requestWMExtents(window.getWindow()); XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height); /* REMINDER: will need to revisit when setExtendedStateBounds is added */
*** 1046,1055 **** --- 1067,1077 ---- case XWM.OPENLOOK_WM: case XWM.MOTIF_WM: case XWM.CDE_WM: return false; default: + //XXX: so what about compiz? return false; } }
*** 1262,1295 **** } } } } ! 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; } } ! 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. * We work around this in MWindowPeer.pReshape(). * --- 1284,1310 ---- } } } } ! /** ! * 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; } } ! /* * Some buggy WMs ignore window gravity when processing * ConfigureRequest and position window as if the gravity is Static. * We work around this in MWindowPeer.pReshape(). *
*** 1399,1413 **** getter.dispose(); } } /** ! * Asks WM to fill Frame Extents (insets) for the window. */ ! public static void requestWMExtents(long window) { if (window == XConstants.None) { // not initialized ! return; } log.fine("Requesting FRAME_EXTENTS"); XClientMessageEvent msg = new XClientMessageEvent(); --- 1414,1430 ---- getter.dispose(); } } /** ! * Asks the WM to fill Frame Extents (insets) for the window. ! * ! * @return true if a request has been actually sent, false otherwise. */ ! public static boolean requestWMExtents(long window) { if (window == XConstants.None) { // not initialized ! return false; } log.fine("Requesting FRAME_EXTENTS"); XClientMessageEvent msg = new XClientMessageEvent();
*** 1423,1637 **** msg.set_message_type(XA_NET_REQUEST_FRAME_EXTENTS.getAtom()); XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), false, XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask, msg.getPData()); } if (getWMID() == XWM.KDE2_WM) { msg.set_message_type(XA_KDE_NET_WM_FRAME_STRUT.getAtom()); XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), false, XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask, msg.getPData()); } - // XXX: should we wait for response? XIfEvent() would be useful here :) } finally { XToolkit.awtUnlock(); msg.dispose(); } } ! /* 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 */ ! 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; - } - - 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); ! if (correctWM == null) { ! correctWM = new Insets(0,0,0,0); ! correctWM.top = -1; ! correctWM.left = -1; ! ! XWindowAttributes lwinAttr = new XWindowAttributes(); ! XWindowAttributes pattr = new XWindowAttributes(); ! 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) */ } finally { ! lwinAttr.dispose(); ! pattr.dispose(); } } ! if (storedInsets.get(win.getClass()) == null) { ! storedInsets.put(win.getClass(), correctWM); } ! return correctWM; } boolean isDesktopWindow( long w ) { if (g_net_protocol != null) { XAtomList wtype = XAtom.get("_NET_WM_WINDOW_TYPE").getAtomListPropertyList( w ); return wtype.contains( XAtom.get("_NET_WM_WINDOW_TYPE_DESKTOP") ); } else { --- 1440,1550 ---- msg.set_message_type(XA_NET_REQUEST_FRAME_EXTENTS.getAtom()); XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), 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()); XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), false, XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask, msg.getPData()); + return true; } } finally { XToolkit.awtUnlock(); msg.dispose(); } + return false; } ! /** ! * Indicates if the given atom represents a property containing the extents ! * of a frame. */ ! 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(); } ! // Synchronization: XWM.class ! private static Integer syncDelay = null; ! /** ! * 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()); } + }; ! /** ! * 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; ! ! XEvent event = null; ! do { ! XToolkit.awtLock(); ! try { ! XToolkit.XSync(); ! event = XlibWrapper.CheckIfEvent(XToolkit.getDisplay(), ! checkExtentsUpdateEventPredicate); } finally { ! XToolkit.awtUnlock(); } + 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 ); return wtype.contains( XAtom.get("_NET_WM_WINDOW_TYPE_DESKTOP") ); } else {