|
|
@@ -1917,9 +1917,22 @@ void DisplayServerX11::show_window(WindowID 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);
|
|
|
XSync(x11_display, False);
|
|
|
- _validate_mode_on_map(p_id);
|
|
|
+
|
|
|
+ _validate_fullscreen_on_map(p_id);
|
|
|
|
|
|
if (p_id == MAIN_WINDOW_ID) {
|
|
|
// 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 {
|
|
|
_THREAD_SAFE_METHOD_
|
|
|
|
|
|
@@ -2855,15 +2914,11 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
|
|
|
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
|
|
|
const WindowData &wd = windows[p_window];
|
|
|
if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
|
|
|
_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) {
|
|
|
@@ -3062,13 +3117,15 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
|
|
|
|
|
|
} break;
|
|
|
case WINDOW_MODE_MAXIMIZED: {
|
|
|
- _set_wm_maximized(p_window, false);
|
|
|
+ // Varies between target modes, so do nothing here.
|
|
|
} break;
|
|
|
}
|
|
|
|
|
|
switch (p_mode) {
|
|
|
case WINDOW_MODE_WINDOWED: {
|
|
|
- //do nothing
|
|
|
+ if (wd.maximized) {
|
|
|
+ _set_wm_maximized(p_window, false);
|
|
|
+ }
|
|
|
} break;
|
|
|
case WINDOW_MODE_MINIMIZED: {
|
|
|
_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);
|
|
|
const WindowData &wd = windows[p_window];
|
|
|
|
|
|
- if (wd.fullscreen) { //if fullscreen, it's not in another mode
|
|
|
+ if (_window_minimize_check(p_window)) {
|
|
|
+ return WINDOW_MODE_MINIMIZED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wd.fullscreen) {
|
|
|
if (wd.exclusive_fullscreen) {
|
|
|
return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
|
|
|
- } else {
|
|
|
- return WINDOW_MODE_FULLSCREEN;
|
|
|
}
|
|
|
+ return WINDOW_MODE_FULLSCREEN;
|
|
|
}
|
|
|
|
|
|
- // Test maximized.
|
|
|
- // Using EWMH -- Extended Window Manager Hints
|
|
|
if (_window_maximize_check(p_window, "_NET_WM_STATE")) {
|
|
|
return WINDOW_MODE_MAXIMIZED;
|
|
|
}
|
|
|
|
|
|
- {
|
|
|
- if (_window_minimize_check(p_window)) {
|
|
|
- return WINDOW_MODE_MINIMIZED;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // All other discarded, return windowed.
|
|
|
-
|
|
|
return WINDOW_MODE_WINDOWED;
|
|
|
}
|
|
|
|
|
|
@@ -4402,11 +4452,6 @@ void DisplayServerX11::_window_changed(XEvent *event) {
|
|
|
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
|
|
|
Window root, parent, *children;
|
|
|
unsigned int nchildren;
|
|
|
@@ -5037,7 +5082,7 @@ void DisplayServerX11::process_events() {
|
|
|
}
|
|
|
|
|
|
// 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,
|
|
|
// only the embedded window receives the Map notification, causing it to
|
|
|
@@ -5058,24 +5103,6 @@ void DisplayServerX11::process_events() {
|
|
|
Main::force_redraw();
|
|
|
} 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: {
|
|
|
DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
|
|
|
if (ime_window_event) {
|
|
|
@@ -5219,6 +5246,12 @@ void DisplayServerX11::process_events() {
|
|
|
_window_changed(&event);
|
|
|
} break;
|
|
|
|
|
|
+ case PropertyNotify: {
|
|
|
+ if (event.xproperty.atom == XInternAtom(x11_display, "_NET_WM_STATE", False)) {
|
|
|
+ _update_wm_state_hints(window_id);
|
|
|
+ }
|
|
|
+ } break;
|
|
|
+
|
|
|
case ButtonPress:
|
|
|
case ButtonRelease: {
|
|
|
if (ime_window_event || ignore_events) {
|