/* * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/** * Class incapsulating knowledge about window managers in general * Descendants should provide some information about specific window manager.
*/ finalclass XWM
{
String[] names = new String[atomInitList.length]; for (int index = 0; index < names.length; index++) {
names[index] = (String)atomInitList[index][1];
}
int atomSize = XAtom.getAtomSize(); long atoms = unsafe.allocateMemory(names.length*atomSize);
XToolkit.awtLock(); try { int status = XlibWrapper.XInternAtoms(XToolkit.getDisplay(), names, false, atoms); if (status == 0) { return;
} for (int atom = 0, atomPtr = 0; atom < names.length; atom++, atomPtr += atomSize) {
((XAtom)(atomInitList[atom][0])).setValues(XToolkit.getDisplay(), names[atom], XAtom.getAtom(atoms + atomPtr));
}
} finally {
XToolkit.awtUnlock();
unsafe.freeMemory(atoms);
}
}
/* * MUST BE CALLED UNDER AWTLOCK. * * If *any* window manager is running? * * According to ICCCM 2.0 section 4.3. * WM will acquire ownership of a selection named WM_Sn, where n is * the screen number. * * No selection owner, but, perhaps it is not ICCCM compliant WM * (e.g. CDE/Sawfish). * Try selecting for SubstructureRedirect, that only one client * can select for, and if the request fails, than some other WM is * already running. * * We also treat eXcursion as NO_WM.
*/ privatestaticboolean isNoWM() { /* * Quick checks for specific servers.
*/
String vendor_string = XlibWrapper.ServerVendor(XToolkit.getDisplay()); if (vendor_string.contains("eXcursion")) { /* * Use NO_WM since in all other aspects eXcursion is like not * having a window manager running. I.e. it does not reparent * top level shells.
*/ if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("eXcursion means NO_WM");
} returntrue;
}
XSetWindowAttributes substruct = new XSetWindowAttributes(); try { /* * Let's check an owner of WM_Sn selection for the default screen.
*/ finallong default_screen_number =
XlibWrapper.DefaultScreen(XToolkit.getDisplay()); final String selection_name = "WM_S" + default_screen_number;
long selection_owner =
XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(),
XAtom.get(selection_name).getAtom()); if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("selection owner of " + selection_name
+ " is " + selection_owner);
}
if (selection_owner != XConstants.None) { returnfalse;
}
/* * If no WM is running then our selection for SubstructureRedirect * succeeded and needs to be undone (hey we are *not* a WM ;-).
*/ if (!winmgr_running) {
substruct.set_event_mask(0);
XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
XToolkit.getDefaultRootWindow(),
XConstants.CWEventMask,
substruct.pData); if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("It looks like there is no WM thus NO_WM");
}
}
static XAtom XA_ENLIGHTENMENT_COMMS = new XAtom("ENLIGHTENMENT_COMMS", false); /* * Helper function for isEnlightenment(). * Enlightenment uses STRING property for its comms window id. Gaaa! * The property is ENLIGHTENMENT_COMMS, STRING/8 and the string format * is "WINID %8x". Gee, I haven't been using scanf for *ages*... :-)
*/ staticlong getECommsWindowIDProperty(long window) {
if (!XA_ENLIGHTENMENT_COMMS.isInterned()) { return 0;
}
WindowPropertyGetter getter = new WindowPropertyGetter(window, XA_ENLIGHTENMENT_COMMS, 0, 14, false,
XAtom.XA_STRING); try { int status = getter.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); if (status != XConstants.Success || getter.getData() == 0) { return 0;
}
// Convert data to String, ASCII byte[] bytes = XlibWrapper.getStringBytes(getter.getData());
String id = new String(bytes);
if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("ENLIGHTENMENT_COMMS is " + id);
}
// Parse WINID
Pattern winIdPat = Pattern.compile("WINID\\s+(\\p{XDigit}{0,8})"); try {
Matcher match = winIdPat.matcher(id); if (match.matches()) { if (log.isLoggable(PlatformLogger.Level.FINEST)) {
log.finest("Match group count: " + match.groupCount());
}
String longId = match.group(1); if (log.isLoggable(PlatformLogger.Level.FINEST)) {
log.finest("Match group 1 " + longId);
} long winid = Long.parseLong(longId, 16); if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("Enlightenment communication window " + winid);
} return winid;
} else {
log.finer("ENLIGHTENMENT_COMMS has wrong format"); return 0;
}
} catch (Exception e) { if (log.isLoggable(PlatformLogger.Level.FINER)) {
e.printStackTrace();
} return 0;
}
} finally {
getter.dispose();
}
}
/* * Is Enlightenment WM running? Congruent to awt_wm_checkAnchor, but * uses STRING property peculiar to Enlightenment.
*/ staticboolean isEnlightenment() {
long root_xref = getECommsWindowIDProperty(XToolkit.getDefaultRootWindow()); if (root_xref == 0) { returnfalse;
}
long self_xref = getECommsWindowIDProperty(root_xref); if (self_xref != root_xref) { returnfalse;
}
returntrue;
}
/* * Is CDE running? * * XXX: This is hairy... CDE is MWM as well. It seems we simply test * for default setup and will be bitten if user changes things... * * Check for _DT_SM_WINDOW_INFO(_DT_SM_WINDOW_INFO) on root. Take the * second element of the property and check for presence of * _DT_SM_STATE_INFO(_DT_SM_STATE_INFO) on that window. * * XXX: Any header that defines this structures???
*/ staticfinal XAtom XA_DT_SM_WINDOW_INFO = new XAtom("_DT_SM_WINDOW_INFO", false); staticfinal XAtom XA_DT_SM_STATE_INFO = new XAtom("_DT_SM_STATE_INFO", false); staticboolean isCDE() {
if (!XA_DT_SM_WINDOW_INFO.isInterned()) { if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("{0} is not interned", XA_DT_SM_WINDOW_INFO);
} returnfalse;
}
WindowPropertyGetter getter = new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
XA_DT_SM_WINDOW_INFO, 0, 2, false, XA_DT_SM_WINDOW_INFO); try { int status = getter.execute(); if (status != XConstants.Success || getter.getData() == 0) {
log.finer("Getting of _DT_SM_WINDOW_INFO is not successful"); returnfalse;
} if (getter.getActualType() != XA_DT_SM_WINDOW_INFO.getAtom()
|| getter.getActualFormat() != 32
|| getter.getNumberOfItems() != 2 || getter.getBytesAfter() != 0)
{
log.finer("Wrong format of _DT_SM_WINDOW_INFO"); returnfalse;
}
long wmwin = Native.getWindow(getter.getData(), 1); //unsafe.getInt(getter.getData()+4);
if (wmwin == 0) {
log.fine("WARNING: DT_SM_WINDOW_INFO exists but returns zero windows"); returnfalse;
}
/* Now check that this window has _DT_SM_STATE_INFO (ignore contents) */ if (!XA_DT_SM_STATE_INFO.isInterned()) { if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("{0} is not interned", XA_DT_SM_STATE_INFO);
} returnfalse;
}
WindowPropertyGetter getter2 = new WindowPropertyGetter(wmwin, XA_DT_SM_STATE_INFO, 0, 1, false, XA_DT_SM_STATE_INFO); try {
status = getter2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
if (status != XConstants.Success || getter2.getData() == 0) {
log.finer("Getting of _DT_SM_STATE_INFO is not successful"); returnfalse;
} if (getter2.getActualType() != XA_DT_SM_STATE_INFO.getAtom()
|| getter2.getActualFormat() != 32)
{
log.finer("Wrong format of _DT_SM_STATE_INFO"); returnfalse;
}
/* * Is MWM running? (Note that CDE will test positive as well). * * Check for _MOTIF_WM_INFO(_MOTIF_WM_INFO) on root. Take the * second element of the property and check for presence of * _DT_SM_STATE_INFO(_DT_SM_STATE_INFO) on that window.
*/ staticfinal XAtom XA_MOTIF_WM_INFO = new XAtom("_MOTIF_WM_INFO", false); staticfinal XAtom XA_DT_WORKSPACE_CURRENT = new XAtom("_DT_WORKSPACE_CURRENT", false); staticboolean isMotif() {
if (!(XA_MOTIF_WM_INFO.isInterned()/* && XA_DT_WORKSPACE_CURRENT.isInterned()*/) ) { returnfalse;
}
WindowPropertyGetter getter = new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
XA_MOTIF_WM_INFO, 0,
MWMConstants.PROP_MOTIF_WM_INFO_ELEMENTS, false, XA_MOTIF_WM_INFO); try { int status = getter.execute();
long wmwin = Native.getLong(getter.getData(), 1); if (wmwin != 0) { if (XA_DT_WORKSPACE_CURRENT.isInterned()) { /* Now check that this window has _DT_WORKSPACE_CURRENT */
XAtom[] curws = XA_DT_WORKSPACE_CURRENT.getAtomListProperty(wmwin); if (curws.length == 0) { returnfalse;
} returntrue;
} else { // No DT_WORKSPACE, however in our tests MWM sometimes can be without desktop - // and that is still MWM. So simply check for the validity of this window // (through WM_STATE property).
WindowPropertyGetter state_getter = new WindowPropertyGetter(wmwin,
XA_WM_STATE,
0, 1, false,
XA_WM_STATE); try { if (state_getter.execute() == XConstants.Success &&
state_getter.getData() != 0 &&
state_getter.getActualType() == XA_WM_STATE.getAtom())
{ returntrue;
}
} finally {
state_getter.dispose();
}
}
}
} finally {
getter.dispose();
} returnfalse;
}
/* * 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 * was immediately deleted by IceWM. * * But messing with PropertyNotify here is way too much trouble, so * approximate the check by setting the property in this function and * checking if it still exists later on. * * Gaa, dirty dances...
*/ staticfinal XAtom XA_ICEWM_WINOPTHINT = new XAtom("_ICEWM_WINOPTHINT", false); staticfinalchar[] opt = { 'A','W','T','_','I','C','E','W','M','_','T','E','S','T','\0', 'a','l','l','W','o','r','k','s','p','a','c','e','s','\0', '0','\0'
}; staticboolean prepareIsIceWM() { /* * Choose something innocuous: "AWT_ICEWM_TEST allWorkspaces 0". * IceWM expects "class\0option\0arg\0" with zero bytes as delimiters.
*/
if (!XA_ICEWM_WINOPTHINT.isInterned()) { if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT);
} returnfalse;
}
/* * Is IceWM running? * * Note well: Only call this if awt_wm_prepareIsIceWM succeeded, or a * false positive will be reported.
*/ staticboolean isIceWM() { if (!XA_ICEWM_WINOPTHINT.isInterned()) { if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT);
} returnfalse;
}
WindowPropertyGetter getter = new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
XA_ICEWM_WINOPTHINT, 0, 0xFFFF, true, XA_ICEWM_WINOPTHINT); try { int status = getter.execute(); boolean res = (status == XConstants.Success && getter.getActualType() != 0); if (log.isLoggable(PlatformLogger.Level.FINER)) {
log.finer("Status getting XA_ICEWM_WINOPTHINT: " + !res);
} return !res || isNetWMName("IceWM");
} finally {
getter.dispose();
}
}
/* * Is OpenLook WM running? * * This one is pretty lame, but the only property peculiar to OLWM is * _SUN_WM_PROTOCOLS(ATOM[]). Fortunately, olwm deletes it on exit.
*/ staticfinal XAtom XA_SUN_WM_PROTOCOLS = new XAtom("_SUN_WM_PROTOCOLS", false); staticboolean isOpenLook() { if (!XA_SUN_WM_PROTOCOLS.isInterned()) { returnfalse;
}
XAtom[] list = XA_SUN_WM_PROTOCOLS.getAtomListProperty(XToolkit.getDefaultRootWindow()); return (list.length != 0);
}
/* * Make an educated guess about running window manager. * XXX: ideally, we should detect wm restart.
*/ staticint 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;
} staticint getWMID() { if (insLog.isLoggable(PlatformLogger.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;
}
XSetWindowAttributes substruct = new XSetWindowAttributes();
XToolkit.awtLock(); try { if (isNoWM()) {
awt_wmgr = XWM.NO_WM; return awt_wmgr;
}
// Initialize _NET protocol - used to detect Window Manager. // Later, WM will initialize its own version of protocol
XNETProtocol l_net_protocol = g_net_protocol = new XNETProtocol();
l_net_protocol.detect(); if (log.isLoggable(PlatformLogger.Level.FINE) && l_net_protocol.active()) {
log.fine("_NET_WM_NAME is " + l_net_protocol.getWMName());
}
XWINProtocol win = g_win_protocol = new XWINProtocol();
win.detect();
/* actual check for IceWM to follow below */ boolean doIsIceWM = prepareIsIceWM(); /* and let IceWM to act */
/* * Ok, some WM is out there. Check which one by testing for * "distinguishing" atoms.
*/ if (isEnlightenment()) {
awt_wmgr = XWM.ENLIGHTEN_WM;
} elseif (isMetacity()) {
awt_wmgr = XWM.METACITY_WM;
} elseif (isMutter()) {
awt_wmgr = XWM.MUTTER_WM;
} elseif (isSawfish()) {
awt_wmgr = XWM.SAWFISH_WM;
} elseif (isKDE2()) {
awt_wmgr =XWM.KDE2_WM;
} elseif (isCompiz()) {
awt_wmgr = XWM.COMPIZ_WM;
} elseif (isLookingGlass()) {
awt_wmgr = LG3D_WM;
} elseif (isCWM()) {
awt_wmgr = CWM_WM;
} elseif (doIsIceWM && isIceWM()) {
awt_wmgr = XWM.ICE_WM;
} elseif (isUnityCompiz()) {
awt_wmgr = XWM.UNITY_COMPIZ_WM;
} /* * We don't check for legacy WM when we already know that WM * supports WIN or _NET wm spec.
*/ elseif (l_net_protocol.active()) {
awt_wmgr = XWM.OTHER_WM;
} elseif (win.active()) {
awt_wmgr = XWM.OTHER_WM;
} /* * Check for legacy WMs.
*/ elseif (isCDE()) { /* XXX: must come before isMotif */
awt_wmgr = XWM.CDE_WM;
} elseif (isMotif()) {
awt_wmgr = XWM.MOTIF_WM;
} elseif (isOpenLook()) {
awt_wmgr = XWM.OPENLOOK_WM;
} else {
awt_wmgr = XWM.OTHER_WM;
}
/*****************************************************************************\ * * Size and decoration hints ... *
\*****************************************************************************/
/* * Remove size hints specified by the mask. * XXX: Why do we need this in the first place???
*/ staticvoid removeSizeHints(XDecoratedPeer window, long mask) {
mask &= XUtilConstants.PMaxSize | XUtilConstants.PMinSize;
/* * If MWM_DECOR_ALL bit is set, then the rest of the bit-mask is taken * to be subtracted from the decorations. Normalize decoration spec * so that we can map motif decor to something else bit-by-bit in the * rest of the code.
*/ staticint normalizeMotifDecor(int decorations) { if ((decorations & MWMConstants.MWM_DECOR_ALL) == 0) { return decorations;
} int d = MWMConstants.MWM_DECOR_BORDER | MWMConstants.MWM_DECOR_RESIZEH
| MWMConstants.MWM_DECOR_TITLE
| MWMConstants.MWM_DECOR_MENU | MWMConstants.MWM_DECOR_MINIMIZE
| MWMConstants.MWM_DECOR_MAXIMIZE;
d &= ~decorations; return d;
}
/* * If MWM_FUNC_ALL bit is set, then the rest of the bit-mask is taken * to be subtracted from the functions. Normalize function spec * so that we can map motif func to something else bit-by-bit in the * rest of the code.
*/ staticint normalizeMotifFunc(int functions) { if ((functions & MWMConstants.MWM_FUNC_ALL) == 0) { return functions;
} int f = MWMConstants.MWM_FUNC_RESIZE |
MWMConstants.MWM_FUNC_MOVE |
MWMConstants.MWM_FUNC_MAXIMIZE |
MWMConstants.MWM_FUNC_MINIMIZE |
MWMConstants.MWM_FUNC_CLOSE;
f &= ~functions; return f;
}
/* * Infer OL properties from MWM decorations. * Use _OL_DECOR_DEL(ATOM[]) to remove unwanted ones.
*/ staticvoid setOLDecor(XWindow window, boolean resizable, int decorations) { if (window == null) { return;
}
XAtomList decorDel = new XAtomList();
decorations = normalizeMotifDecor(decorations); if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("Setting OL_DECOR to " + Integer.toBinaryString(decorations));
} if ((decorations & MWMConstants.MWM_DECOR_TITLE) == 0) {
decorDel.add(XA_OL_DECOR_HEADER);
} if ((decorations & (MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE)) == 0) {
decorDel.add(XA_OL_DECOR_RESIZE);
} if ((decorations & (MWMConstants.MWM_DECOR_MENU |
MWMConstants.MWM_DECOR_MAXIMIZE |
MWMConstants.MWM_DECOR_MINIMIZE)) == 0)
{
decorDel.add(XA_OL_DECOR_CLOSE);
} if (decorDel.size() == 0) {
insLog.finer("Deleting OL_DECOR");
XA_OL_DECOR_DEL.DeleteProperty(window);
} else { if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("Setting OL_DECOR to " + decorDel);
}
XA_OL_DECOR_DEL.setAtomListProperty(window, decorDel);
}
}
/* * Set MWM decorations. Set MWM functions depending on resizability.
*/ staticvoid setMotifDecor(XWindow window, boolean resizable, int decorations, int functions) { /* Apparently some WMs don't implement MWM_*_ALL semantic correctly */ if ((decorations & MWMConstants.MWM_DECOR_ALL) != 0
&& (decorations != MWMConstants.MWM_DECOR_ALL))
{
decorations = normalizeMotifDecor(decorations);
} if ((functions & MWMConstants.MWM_FUNC_ALL) != 0
&& (functions != MWMConstants.MWM_FUNC_ALL))
{
functions = normalizeMotifFunc(functions);
}
if (stateLog.isLoggable(PlatformLogger.Level.FINER)) {
stateLog.finer("Setting MWM_HINTS to " + hints);
}
window.setMWMHints(hints);
}
/* * Under some window managers if shell is already mapped, we MUST * unmap and later remap in order to effect the changes we make in the * window manager decorations. * * N.B. This unmapping / remapping of the shell exposes a bug in * X/Motif or the Motif Window Manager. When you attempt to map a * widget which is positioned (partially) off-screen, the window is * relocated to be entirely on screen. Good idea. But if both the x * and the y coordinates are less than the origin (0,0), the first * (re)map will move the window to the origin, and any subsequent * (re)map will relocate the window at some other point on the screen. * I have written a short Motif test program to discover this bug. * This should occur infrequently and it does not cause any real * problem. So for now we'll let it be.
*/ staticboolean needRemap(XDecoratedPeer window) { // Don't remap EmbeddedFrame, // e.g. for TrayIcon it causes problems. return !window.isEmbedded();
}
/* * Set decoration hints on the shell to wdata->decor adjusted * appropriately if not resizable.
*/ staticvoid setShellDecor(XDecoratedPeer window) { int decorations = window.getDecorations(); int functions = window.getFunctions(); boolean resizable = window.isResizable();
/* Some WMs need remap to redecorate the window */ if (window.isShowing() && needRemap(window)) { /* * Do the re/mapping at the Xlib level. Since we essentially * work around a WM bug we don't want this hack to be exposed * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
*/
window.xSetVisible(false);
XToolkit.XSync();
window.xSetVisible(true);
}
}
/* * Make specified shell resizable.
*/ staticvoid setShellResizable(XDecoratedPeer window) { if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
insLog.fine("Setting shell resizable " + window);
}
XToolkit.awtLock(); try {
Rectangle shellBounds; if (getWMID() != UNITY_COMPIZ_WM) {
shellBounds = window.getShellBounds();
shellBounds.translate(-window.currentInsets.left,
-window.currentInsets.top);
} else {
shellBounds = window.getDimensions().getScreenBounds();
}
window.updateSizeHints(window.getDimensions());
requestWMExtents(window.getWindow());
XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(),
window.getShell(),
window.scaleUp(shellBounds.x),
window.scaleUp(shellBounds.y),
window.scaleUp(shellBounds.width),
window.scaleUp(shellBounds.height)); /* REMINDER: will need to revisit when setExtendedStateBounds is added */ //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. //We need to update frame's minimum size, not to reset it
removeSizeHints(window, XUtilConstants.PMaxSize);
window.updateMinimumSize();
boolean supportsDynamicLayout() { int wm = getWMID(); switch (wm) { case XWM.ENLIGHTEN_WM: case XWM.KDE2_WM: case XWM.SAWFISH_WM: case XWM.ICE_WM: case XWM.METACITY_WM: returntrue; case XWM.OPENLOOK_WM: case XWM.MOTIF_WM: case XWM.CDE_WM: returnfalse; default: returnfalse;
}
}
/** * Check if state is supported. * Note that a compound state is always reported as not supported. * Note also that MAXIMIZED_BOTH is considered not a compound state. * Therefore, a compound state is just ICONIFIED | anything else. *
*/
@SuppressWarnings("fallthrough") boolean supportsExtendedState(int state) { switch (state) { case Frame.MAXIMIZED_VERT: case Frame.MAXIMIZED_HORIZ: /* * WMs that talk NET/WIN protocol, but do not support * unidirectional maximization.
*/ if (getWMID() == METACITY_WM) { /* "This is a deliberate policy decision." -hp */ returnfalse;
} /* FALLTHROUGH */ case Frame.MAXIMIZED_BOTH: for (XStateProtocol proto : getProtocols(XStateProtocol.class)) { if (proto.supportsState(state)) { returntrue;
}
} /* FALLTHROUGH */ default: returnfalse;
}
}
/*****************************************************************************\ * * Reading state from different protocols *
\*****************************************************************************/
int getExtendedState(XWindowPeer window) { int state = 0; for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
state |= proto.getState(window);
} if (state != 0) { return state;
} else { return Frame.NORMAL;
}
}
/*****************************************************************************\ * * Notice window state change when WM changes a property on the window ... *
\*****************************************************************************/
/* * Check if property change is a window state protocol message.
*/ boolean isStateChange(XDecoratedPeer window, XPropertyEvent e) { if (!window.isShowing()) {
stateLog.finer("Window is not showing"); returnfalse;
}
int wm_state = window.getWMState(); if (wm_state == XUtilConstants.WithdrawnState) {
stateLog.finer("WithdrawnState"); returnfalse;
} else { if (stateLog.isLoggable(PlatformLogger.Level.FINER)) {
stateLog.finer("Window WM_STATE is " + wm_state);
}
} boolean is_state_change = false; if (e.get_atom() == XA_WM_STATE.getAtom()) {
is_state_change = true;
}
for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
is_state_change |= proto.isStateChange(e); if (stateLog.isLoggable(PlatformLogger.Level.FINEST)) {
stateLog.finest(proto + ": is state changed = " + is_state_change);
}
} return is_state_change;
}
/* * Returns current state (including extended) of a given window.
*/ int getState(XDecoratedPeer window) { int res = 0; finalint wm_state = window.getWMState(); if (wm_state == XUtilConstants.IconicState) {
res = Frame.ICONIFIED;
} else {
res = Frame.NORMAL;
}
res |= getExtendedState(window); return res;
}
/*****************************************************************************\ * * Setting/changing window state ... *
\*****************************************************************************/
/** * Moves window to the specified layer, layer is one of the constants defined * in XLayerProtocol
*/ void setLayer(XWindowPeer window, int layer) { for (XLayerProtocol proto : getProtocols(XLayerProtocol.class)) { if (proto.supportsLayer(layer)) {
proto.setLayer(window, layer);
}
}
XToolkit.XSync();
}
void setExtendedState(XWindowPeer window, int state) { for (XStateProtocol proto : getProtocols(XStateProtocol.class)) { if (proto.supportsState(state)) {
proto.setState(window, state); break;
}
}
if (!window.isShowing()) { /* * Purge KWM bits. * Not really tested with KWM, only with WindowMaker.
*/
XToolkit.awtLock(); try {
XlibWrapper.XDeleteProperty(XToolkit.getDisplay(),
window.getWindow(),
XA_KWM_WIN_ICONIFIED.getAtom());
XlibWrapper.XDeleteProperty(XToolkit.getDisplay(),
window.getWindow(),
XA_KWM_WIN_MAXIMIZED.getAtom());
} finally {
XToolkit.awtUnlock();
}
}
XToolkit.XSync();
}
/* * Work around for 4775545. * * If WM exits while the top-level is shaded, the shaded hint remains * on the top-level properties. When WM restarts and sees the shaded * window it can reparent it into a "pre-shaded" decoration frame * (Metacity does), and our insets logic will go crazy, b/c it will * see a huge negative bottom inset. There's no clean solution for * this, so let's just be weasels and drop the shaded hint if we * detect that WM exited. NB: we are in for a race condition with WM * restart here. NB2: e.g. WindowMaker saves the state in a private * property that this code knows nothing about, so this workaround is * not effective; other WMs might play similar tricks.
*/ void unshadeKludge(XDecoratedPeer window) { assert(window.isShowing());
for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
proto.unshadeKludge(window);
}
XToolkit.XSync();
}
void initializeProtocols() {
XNETProtocol net_protocol = g_net_protocol; if (net_protocol != null) { if (!net_protocol.active()) {
net_protocol = null;
} else { if (net_protocol.doStateProtocol()) {
addProtocol(XStateProtocol.class, net_protocol);
} if (net_protocol.doLayerProtocol()) {
addProtocol(XLayerProtocol.class, net_protocol);
}
}
}
XWINProtocol win = g_win_protocol; if (win != null) { if (win.active()) { if (win.doStateProtocol()) {
addProtocol(XStateProtocol.class, win);
} if (win.doLayerProtocol()) {
addProtocol(XLayerProtocol.class, win);
}
}
}
}
HashMap<Class<?>, Insets> storedInsets = new HashMap<>();
Insets guessInsets(XDecoratedPeer window) {
Insets res = 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 UNITY_COMPIZ_WM:
res = new Insets(28, 1, 1, 1); break; case MOTIF_WM: case OPENLOOK_WM: default:
res = defaultInsets;
}
} if (insLog.isLoggable(PlatformLogger.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(). * * Starting with 1.5 we have introduced an Environment variable * _JAVA_AWT_WM_STATIC_GRAVITY that can be set to indicate to Java * explicitly that the WM has this behaviour, example is FVWM.
*/
switch(getWMID()) { case XWM.ICE_WM: /* * See bug #228981 at IceWM's SourceForge pages. * Latest stable version 1.0.8-6 still has this problem.
*/ /** * Version 1.2.2 doesn't have this problem
*/ // Detect IceWM version if (g_net_protocol != null) {
String wm_name = g_net_protocol.getWMName();
Pattern pat = Pattern.compile("^IceWM (\\d+)\\.(\\d+)\\.(\\d+).*$"); try {
Matcher match = pat.matcher(wm_name); if (match.matches()) { int v1 = Integer.parseInt(match.group(1)); int v2 = Integer.parseInt(match.group(2)); int v3 = Integer.parseInt(match.group(3)); return !(v1 > 1 || (v1 == 1 && (v2 > 2 || (v2 == 2 && v3 >=2))));
}
} catch (Exception e) { returntrue;
}
} returntrue; case XWM.ENLIGHTEN_WM: /* At least E16 is buggy. */ returntrue; default: returnfalse;
}
}
/* * @return if WM implements the insets property - returns insets with values * specified in that property, null otherwise.
*/ publicstatic Insets getInsetsFromExtents(long window) { if (window == XConstants.None) { returnnull;
}
XNETProtocol net_protocol = getWM().getNETProtocol(); if (net_protocol != null && net_protocol.active()) {
Insets insets = getInsetsFromProp(window, XA_NET_FRAME_EXTENTS); if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
insLog.fine("_NET_FRAME_EXTENTS: {0}", insets);
}
if (insets != null) { return insets;
}
} switch(getWMID()) { case XWM.KDE2_WM: return getInsetsFromProp(window, XA_KDE_NET_WM_FRAME_STRUT); case XWM.ENLIGHTEN_WM: return getInsetsFromProp(window, XA_E_FRAME_SIZE); default: returnnull;
}
}
/** * Helper function reads property of type CARDINAL[4] = { left, right, top, bottom } * and converts it to Insets object.
*/ publicstatic Insets getInsetsFromProp(long window, XAtom atom) { if (window == XConstants.None) { returnnull;
}
/** * Asks WM to fill Frame Extents (insets) for the window.
*/ publicstaticvoid requestWMExtents(long window) { if (window == XConstants.None) { // not initialized return;
}
log.fine("Requesting FRAME_EXTENTS");
XClientMessageEvent msg = new XClientMessageEvent();
msg.zero();
msg.set_type(XConstants.ClientMessage);
msg.set_display(XToolkit.getDisplay());
msg.set_window(window);
msg.set_format(32);
XToolkit.awtLock(); try {
XNETProtocol net_protocol = getWM().getNETProtocol(); if (net_protocol != null && net_protocol.active()) {
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 have 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) { returntrue;
}
tries++;
XToolkit.XSync();
} while (tries < 50);
} finally {
XToolkit.awtUnlock();
} returnfalse;
}
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); if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.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 { returnnull;
} 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 */ if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
insLog.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 that 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())
{ if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
insLog.finest("Double reparenting detected, pattr({2})={0}, lwinAttr({3})={1}",
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());
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 returnnull;
} 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.
*/ if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
insLog.finest("Attrs before calculation: pattr({2})={0}, lwinAttr({3})={1}",
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()),
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.