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 {