mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Merge pull request #110990 from timothyqiu/x11-min-max
X11: Fix minimization of maximized windows
This commit is contained in:
commit
4ea49aecaf
2 changed files with 83 additions and 49 deletions
|
@ -1917,9 +1917,22 @@ void DisplayServerX11::show_window(WindowID p_id) {
|
||||||
|
|
||||||
DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id);
|
DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id);
|
||||||
|
|
||||||
|
// Setup initial minimize/maximize state.
|
||||||
|
// `_NET_WM_STATE` can be set directly when the window is unmapped.
|
||||||
|
LocalVector<Atom> hints;
|
||||||
|
if (wd.maximized) {
|
||||||
|
hints.push_back(XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False));
|
||||||
|
hints.push_back(XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False));
|
||||||
|
}
|
||||||
|
if (wd.minimized) {
|
||||||
|
hints.push_back(XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False));
|
||||||
|
}
|
||||||
|
XChangeProperty(x11_display, wd.x11_window, XInternAtom(x11_display, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)hints.ptr(), hints.size());
|
||||||
|
|
||||||
XMapWindow(x11_display, wd.x11_window);
|
XMapWindow(x11_display, wd.x11_window);
|
||||||
XSync(x11_display, False);
|
XSync(x11_display, False);
|
||||||
_validate_mode_on_map(p_id);
|
|
||||||
|
_validate_fullscreen_on_map(p_id);
|
||||||
|
|
||||||
if (p_id == MAIN_WINDOW_ID) {
|
if (p_id == MAIN_WINDOW_ID) {
|
||||||
// Get main window size for boot splash drawing.
|
// Get main window size for boot splash drawing.
|
||||||
|
@ -2448,6 +2461,52 @@ void DisplayServerX11::_update_actions_hints(WindowID p_window) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayServerX11::_update_wm_state_hints(WindowID p_window) {
|
||||||
|
WindowData &wd = windows[p_window];
|
||||||
|
|
||||||
|
Atom type;
|
||||||
|
int format;
|
||||||
|
unsigned long len;
|
||||||
|
unsigned long remaining;
|
||||||
|
unsigned char *data = nullptr;
|
||||||
|
|
||||||
|
int result = XGetWindowProperty(
|
||||||
|
x11_display,
|
||||||
|
wd.x11_window,
|
||||||
|
XInternAtom(x11_display, "_NET_WM_STATE", False),
|
||||||
|
0,
|
||||||
|
1024,
|
||||||
|
False,
|
||||||
|
XA_ATOM,
|
||||||
|
&type,
|
||||||
|
&format,
|
||||||
|
&len,
|
||||||
|
&remaining,
|
||||||
|
&data);
|
||||||
|
if (result != Success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalVector<Atom> hints;
|
||||||
|
if (data) {
|
||||||
|
hints.resize(len);
|
||||||
|
Atom *atoms = (Atom *)data;
|
||||||
|
for (unsigned long i = 0; i < len; i++) {
|
||||||
|
hints[i] = atoms[i];
|
||||||
|
}
|
||||||
|
XFree(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom fullscreen_atom = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
|
||||||
|
Atom maximized_horz_atom = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
|
||||||
|
Atom maximized_vert_atom = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
|
||||||
|
Atom hidden_atom = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
|
||||||
|
|
||||||
|
wd.fullscreen = hints.has(fullscreen_atom);
|
||||||
|
wd.maximized = hints.has(maximized_horz_atom) && hints.has(maximized_vert_atom);
|
||||||
|
wd.minimized = hints.has(hidden_atom);
|
||||||
|
}
|
||||||
|
|
||||||
Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
|
Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
|
@ -2855,15 +2914,11 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
|
void DisplayServerX11::_validate_fullscreen_on_map(WindowID p_window) {
|
||||||
// Check if we applied any window modes that didn't take effect while unmapped
|
// Check if we applied any window modes that didn't take effect while unmapped
|
||||||
const WindowData &wd = windows[p_window];
|
const WindowData &wd = windows[p_window];
|
||||||
if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
|
if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
|
||||||
_set_wm_fullscreen(p_window, true, wd.exclusive_fullscreen);
|
_set_wm_fullscreen(p_window, true, wd.exclusive_fullscreen);
|
||||||
} 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wd.on_top) {
|
if (wd.on_top) {
|
||||||
|
@ -3062,13 +3117,15 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case WINDOW_MODE_MAXIMIZED: {
|
case WINDOW_MODE_MAXIMIZED: {
|
||||||
_set_wm_maximized(p_window, false);
|
// Varies between target modes, so do nothing here.
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (p_mode) {
|
switch (p_mode) {
|
||||||
case WINDOW_MODE_WINDOWED: {
|
case WINDOW_MODE_WINDOWED: {
|
||||||
//do nothing
|
if (wd.maximized) {
|
||||||
|
_set_wm_maximized(p_window, false);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case WINDOW_MODE_MINIMIZED: {
|
case WINDOW_MODE_MINIMIZED: {
|
||||||
_set_wm_minimized(p_window, true);
|
_set_wm_minimized(p_window, true);
|
||||||
|
@ -3102,28 +3159,21 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c
|
||||||
ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
|
ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
|
||||||
const WindowData &wd = windows[p_window];
|
const WindowData &wd = windows[p_window];
|
||||||
|
|
||||||
if (wd.fullscreen) { //if fullscreen, it's not in another mode
|
if (_window_minimize_check(p_window)) {
|
||||||
if (wd.exclusive_fullscreen) {
|
return WINDOW_MODE_MINIMIZED;
|
||||||
return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
|
}
|
||||||
} else {
|
|
||||||
return WINDOW_MODE_FULLSCREEN;
|
if (wd.fullscreen) {
|
||||||
}
|
if (wd.exclusive_fullscreen) {
|
||||||
|
return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
|
||||||
|
}
|
||||||
|
return WINDOW_MODE_FULLSCREEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test maximized.
|
|
||||||
// Using EWMH -- Extended Window Manager Hints
|
|
||||||
if (_window_maximize_check(p_window, "_NET_WM_STATE")) {
|
if (_window_maximize_check(p_window, "_NET_WM_STATE")) {
|
||||||
return WINDOW_MODE_MAXIMIZED;
|
return WINDOW_MODE_MAXIMIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
if (_window_minimize_check(p_window)) {
|
|
||||||
return WINDOW_MODE_MINIMIZED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All other discarded, return windowed.
|
|
||||||
|
|
||||||
return WINDOW_MODE_WINDOWED;
|
return WINDOW_MODE_WINDOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4402,11 +4452,6 @@ void DisplayServerX11::_window_changed(XEvent *event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query display server about a possible new window state.
|
|
||||||
wd.fullscreen = _window_fullscreen_check(window_id);
|
|
||||||
wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE") && !wd.fullscreen;
|
|
||||||
wd.minimized = _window_minimize_check(window_id) && !wd.fullscreen && !wd.maximized;
|
|
||||||
|
|
||||||
// Readjusting the window position if the window is being reparented by the window manager for decoration
|
// Readjusting the window position if the window is being reparented by the window manager for decoration
|
||||||
Window root, parent, *children;
|
Window root, parent, *children;
|
||||||
unsigned int nchildren;
|
unsigned int nchildren;
|
||||||
|
@ -5037,7 +5082,7 @@ void DisplayServerX11::process_events() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have we failed to set fullscreen while the window was unmapped?
|
// Have we failed to set fullscreen while the window was unmapped?
|
||||||
_validate_mode_on_map(window_id);
|
_validate_fullscreen_on_map(window_id);
|
||||||
|
|
||||||
// On KDE Plasma, when the parent window of an embedded process is restored after being minimized,
|
// On KDE Plasma, when the parent window of an embedded process is restored after being minimized,
|
||||||
// only the embedded window receives the Map notification, causing it to
|
// only the embedded window receives the Map notification, causing it to
|
||||||
|
@ -5058,24 +5103,6 @@ void DisplayServerX11::process_events() {
|
||||||
Main::force_redraw();
|
Main::force_redraw();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NoExpose: {
|
|
||||||
DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id);
|
|
||||||
if (ime_window_event) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
windows[window_id].minimized = true;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case VisibilityNotify: {
|
|
||||||
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
|
|
||||||
if (ime_window_event) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
windows[window_id].minimized = _window_minimize_check(window_id);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case LeaveNotify: {
|
case LeaveNotify: {
|
||||||
DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
|
DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
|
||||||
if (ime_window_event) {
|
if (ime_window_event) {
|
||||||
|
@ -5219,6 +5246,12 @@ void DisplayServerX11::process_events() {
|
||||||
_window_changed(&event);
|
_window_changed(&event);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case PropertyNotify: {
|
||||||
|
if (event.xproperty.atom == XInternAtom(x11_display, "_NET_WM_STATE", False)) {
|
||||||
|
_update_wm_state_hints(window_id);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case ButtonPress:
|
case ButtonPress:
|
||||||
case ButtonRelease: {
|
case ButtonRelease: {
|
||||||
if (ime_window_event || ignore_events) {
|
if (ime_window_event || ignore_events) {
|
||||||
|
|
|
@ -352,9 +352,10 @@ class DisplayServerX11 : public DisplayServer {
|
||||||
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
|
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
|
||||||
bool _window_fullscreen_check(WindowID p_window) const;
|
bool _window_fullscreen_check(WindowID p_window) const;
|
||||||
bool _window_minimize_check(WindowID p_window) const;
|
bool _window_minimize_check(WindowID p_window) const;
|
||||||
void _validate_mode_on_map(WindowID p_window);
|
void _validate_fullscreen_on_map(WindowID p_window);
|
||||||
void _update_size_hints(WindowID p_window);
|
void _update_size_hints(WindowID p_window);
|
||||||
void _update_actions_hints(WindowID p_window);
|
void _update_actions_hints(WindowID p_window);
|
||||||
|
void _update_wm_state_hints(WindowID p_window);
|
||||||
void _set_wm_fullscreen(WindowID p_window, bool p_enabled, bool p_exclusive);
|
void _set_wm_fullscreen(WindowID p_window, bool p_enabled, bool p_exclusive);
|
||||||
void _set_wm_maximized(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 _set_wm_minimized(WindowID p_window, bool p_enabled);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue