JBR-2698 setAutoRequestFocus(false) breaks focus logic under i3 window manager on Linux

(cherry picked from commit ebcdeb7d80)
This commit is contained in:
Dmitry Batrak
2020-09-09 18:28:51 +03:00
committed by jbrbot
parent 7e9cb225c7
commit e460ca2aa7
4 changed files with 36 additions and 16 deletions

View File

@@ -77,7 +77,6 @@ public class XBaseWindow {
private static XAtom wm_client_leader;
private long userTime;
private static long globalUserTime;
static enum InitialiseState {
@@ -654,7 +653,7 @@ public class XBaseWindow {
try {
this.visible = visible;
if (visible) {
setUserTimeFromGlobal();
setUserTimeBeforeShowing();
XlibWrapper.XMapWindow(XToolkit.getDisplay(), getWindow());
}
else {
@@ -1014,7 +1013,7 @@ public class XBaseWindow {
public void handleVisibilityEvent(XEvent xev) {
}
public void handleKeyPress(XEvent xev) {
setUserTime(xev.get_xkey().get_time());
setUserTime(xev.get_xkey().get_time(), true);
}
public void handleKeyRelease(XEvent xev) {
}
@@ -1047,7 +1046,7 @@ public class XBaseWindow {
if (!isWheel) {
switch (xev.get_type()) {
case XConstants.ButtonPress:
setUserTime(xbe.get_time());
setUserTime(xbe.get_time(), true);
if (buttonState == 0) {
XWindowPeer parent = getToplevelXWindow();
// See 6385277, 6981400.
@@ -1265,15 +1264,12 @@ public class XBaseWindow {
return x >= getAbsoluteX() && y >= getAbsoluteY() && x < (getAbsoluteX()+getWidth()) && y < (getAbsoluteY()+getHeight());
}
void setUserTimeFromGlobal() {
setUserTime(globalUserTime);
void setUserTimeBeforeShowing() {
if (globalUserTime != 0) setUserTime(globalUserTime, false);
}
protected void setUserTime(long time) {
if (time == userTime) return;
userTime = time;
if ((int)time - (int)globalUserTime > 0 /* accounting for wrap-around */) {
protected void setUserTime(long time, boolean updateGlobalTime) {
if (updateGlobalTime && (int)time - (int)globalUserTime > 0 /* accounting for wrap-around */) {
globalUserTime = time;
}
XNETProtocol netProtocol = XWM.getWM().getNETProtocol();

View File

@@ -1093,7 +1093,7 @@ abstract class XDecoratedPeer extends XWindowPeer {
}
// we should treat WM_TAKE_FOCUS message as user interaction, as it can originate e.g. from user clicking
// on window title bar (there will be no ButtonPress/ButtonRelease events in this case)
setUserTime(requestTimeStamp);
setUserTime(requestTimeStamp, true);
if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
// JDK-8159460

View File

@@ -110,7 +110,8 @@ final class XWM
MUTTER_WM = 15,
UNITY_COMPIZ_WM = 16,
XMONAD_WM = 17,
AWESOME_WM = 18;
AWESOME_WM = 18,
I3_WM = 19;
public String toString() {
switch (WMID) {
@@ -621,6 +622,10 @@ final class XWM
return isNetWMName("awesome");
}
static boolean isI3() {
return isNetWMName("i3");
}
static int awtWMNonReparenting = -1;
static boolean isNonReparentingWM() {
if (awtWMNonReparenting == -1) {
@@ -824,6 +829,8 @@ final class XWM
awt_wmgr = XWM.XMONAD_WM;
} else if (isAwesome()) {
awt_wmgr = XWM.AWESOME_WM;
} else if (isI3()) {
awt_wmgr = XWM.I3_WM;
}
/*
* We don't check for legacy WM when we already know that WM

View File

@@ -1105,7 +1105,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
if (!isVisible() && vis) {
isBeforeFirstMapNotify = true;
winAttr.initialFocus = isAutoRequestFocus();
if (!winAttr.initialFocus) {
if (!winAttr.initialFocus && XWM.getWMID() != XWM.I3_WM) {
/*
* It's easier and safer to temporary suppress WM_TAKE_FOCUS
* protocol itself than to ignore WM_TAKE_FOCUS client message.
@@ -1113,6 +1113,13 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
* the message come after showing and the message come after
* activation. Also, on Metacity, for some reason, we have _two_
* WM_TAKE_FOCUS client messages when showing a frame/dialog.
*
* i3 window manager doesn't track updates to WM_TAKE_FOCUS
* property, so this approach won't work for it, breaking
* focus behaviour completely. So another way is used to
* suppress focus take over - via setting _NET_WM_USER_TIME
* to 0, as specified in EWMH spec (see
* 'setUserTimeBeforeShowing' method).
*/
suppressWmTakeFocus(true);
}
@@ -1177,6 +1184,16 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
protected void suppressWmTakeFocus(boolean doSuppress) {
}
@Override
void setUserTimeBeforeShowing() {
if (winAttr.initialFocus || XWM.getWMID() != XWM.I3_WM) {
super.setUserTimeBeforeShowing();
}
else {
setUserTime(0, false);
}
}
final boolean isSimpleWindow() {
return !(target instanceof Frame || target instanceof Dialog);
}
@@ -1399,7 +1416,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
isUnhiding |= isWMStateNetHidden();
super.handleMapNotifyEvent(xev);
if (!winAttr.initialFocus) {
if (!winAttr.initialFocus && XWM.getWMID() != XWM.I3_WM) {
suppressWmTakeFocus(false); // restore the protocol.
/*
* For some reason, on Metacity, a frame/dialog being shown
@@ -2015,7 +2032,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
this.visible = visible;
if (visible) {
applyWindowType();
setUserTimeFromGlobal();
setUserTimeBeforeShowing();
XlibWrapper.XMapRaised(XToolkit.getDisplay(), getWindow());
} else {
XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow());