Merge pull request #65107 from MatthewZelriche/X11MinimizeMaximizeFix

Fix minimize/maximize not taking effect in X11.
This commit is contained in:
Rémi Verschelde 2022-09-01 08:43:43 +02:00 committed by GitHub
commit d454b944e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 92 additions and 94 deletions

View File

@ -1823,6 +1823,47 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a
return retval;
}
bool DisplayServerX11::_window_minimize_check(WindowID p_window) const {
const WindowData &wd = windows[p_window];
// Using ICCCM -- Inter-Client Communication Conventions Manual
Atom property = XInternAtom(x11_display, "WM_STATE", True);
if (property == None) {
return false;
}
Atom type;
int format;
unsigned long len;
unsigned long remaining;
unsigned char *data = nullptr;
int result = XGetWindowProperty(
x11_display,
wd.x11_window,
property,
0,
32,
False,
AnyPropertyType,
&type,
&format,
&len,
&remaining,
&data);
if (result == Success && data) {
long *state = (long *)data;
if (state[0] == WM_IconicState) {
XFree(data);
return true;
}
XFree(data);
}
return false;
}
bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
ERR_FAIL_COND_V(!windows.has(p_window), false);
const WindowData &wd = windows[p_window];
@ -1869,11 +1910,15 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
return retval;
}
void DisplayServerX11::_validate_fullscreen_on_map(WindowID p_window) {
void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
// Check if we applied any window modes that didn't take effect while unmapped
const WindowData &wd = windows[p_window];
if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
// Unmapped fullscreen attempt didn't take effect, redo...
_set_wm_fullscreen(p_window, true);
} else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) {
_set_wm_maximized(p_window, true);
} else if (wd.minimized && !_window_minimize_check(p_window)) {
_set_wm_minimized(p_window, true);
}
}
@ -1911,6 +1956,37 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
usleep(10000);
}
}
wd.maximized = p_enabled;
}
void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) {
WindowData &wd = windows[p_window];
// Using ICCCM -- Inter-Client Communication Conventions Manual
XEvent xev;
Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = wd.x11_window;
xev.xclient.message_type = wm_change;
xev.xclient.format = 32;
xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = wd.x11_window;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
xev.xclient.data.l[1] = wm_hidden;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
wd.minimized = p_enabled;
}
void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
@ -1992,32 +2068,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
//Un-Minimize
// Using ICCCM -- Inter-Client Communication Conventions Manual
XEvent xev;
Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = wd.x11_window;
xev.xclient.message_type = wm_change;
xev.xclient.format = 32;
xev.xclient.data.l[0] = WM_NormalState;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = wd.x11_window;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
xev.xclient.data.l[1] = wm_hidden;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
_set_wm_minimized(p_window, false);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@ -2046,31 +2097,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
// Using ICCCM -- Inter-Client Communication Conventions Manual
XEvent xev;
Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = wd.x11_window;
xev.xclient.message_type = wm_change;
xev.xclient.format = 32;
xev.xclient.data.l[0] = WM_IconicState;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = wd.x11_window;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
xev.xclient.data.l[1] = wm_hidden;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
_set_wm_minimized(p_window, true);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@ -2105,40 +2132,9 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c
return WINDOW_MODE_MAXIMIZED;
}
{ // Test minimized.
// Using ICCCM -- Inter-Client Communication Conventions Manual
Atom property = XInternAtom(x11_display, "WM_STATE", True);
if (property == None) {
return WINDOW_MODE_WINDOWED;
}
Atom type;
int format;
unsigned long len;
unsigned long remaining;
unsigned char *data = nullptr;
int result = XGetWindowProperty(
x11_display,
wd.x11_window,
property,
0,
32,
False,
AnyPropertyType,
&type,
&format,
&len,
&remaining,
&data);
if (result == Success && data) {
long *state = (long *)data;
if (state[0] == WM_IconicState) {
XFree(data);
return WINDOW_MODE_MINIMIZED;
}
XFree(data);
{
if (_window_minimize_check(p_window)) {
return WINDOW_MODE_MINIMIZED;
}
}
@ -3658,9 +3654,6 @@ void DisplayServerX11::process_events() {
const WindowData &wd = windows[window_id];
// Have we failed to set fullscreen while the window was unmapped?
_validate_fullscreen_on_map(window_id);
XWindowAttributes xwa;
XSync(x11_display, False);
XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
@ -3671,6 +3664,9 @@ void DisplayServerX11::process_events() {
if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
// Have we failed to set fullscreen while the window was unmapped?
_validate_mode_on_map(window_id);
} break;
case Expose: {
@ -3690,8 +3686,7 @@ void DisplayServerX11::process_events() {
case VisibilityNotify: {
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
windows[window_id].minimized = (visibility->state == VisibilityFullyObscured);
windows[window_id].minimized = _window_minimize_check(window_id);
} break;
case LeaveNotify: {
@ -5003,7 +4998,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
_window_changed(&xevent);
} else if (xevent.type == MapNotify) {
// Have we failed to set fullscreen while the window was unmapped?
_validate_fullscreen_on_map(main_window);
_validate_mode_on_map(main_window);
}
}

View File

@ -152,6 +152,7 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = true;
bool minimized = false;
bool maximized = false;
bool is_popup = false;
Rect2i parent_safe_rect;
@ -268,10 +269,12 @@ class DisplayServerX11 : public DisplayServer {
void _update_real_mouse_position(const WindowData &wd);
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
bool _window_fullscreen_check(WindowID p_window) const;
void _validate_fullscreen_on_map(WindowID p_window);
bool _window_minimize_check(WindowID p_window) const;
void _validate_mode_on_map(WindowID p_window);
void _update_size_hints(WindowID p_window);
void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
void _set_wm_maximized(WindowID p_window, bool p_enabled);
void _set_wm_minimized(WindowID p_window, bool p_enabled);
void _update_context(WindowData &wd);