summaryrefslogtreecommitdiff
path: root/platform/linuxbsd/display_server_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd/display_server_x11.cpp')
-rw-r--r--platform/linuxbsd/display_server_x11.cpp199
1 files changed, 108 insertions, 91 deletions
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 8efbd2e3c5..0d619904bc 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -322,8 +322,8 @@ bool DisplayServerX11::tts_is_paused() const {
return tts->is_paused();
}
-Array DisplayServerX11::tts_get_voices() const {
- ERR_FAIL_COND_V(!tts, Array());
+TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const {
+ ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>());
return tts->get_voices();
}
@@ -1522,11 +1522,15 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
XSetTransientForHint(x11_display, wd_window.x11_window, None);
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd_parent.x11_window, &xwa);
+
// Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) {
- if (!wd_parent.no_focus && !wd_window.is_popup) {
+ if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) {
XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
}
}
@@ -1819,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];
@@ -1865,6 +1910,18 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
return retval;
}
+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)) {
+ _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);
+ }
+}
+
bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const {
_THREAD_SAFE_METHOD_
return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS");
@@ -1899,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) {
@@ -1980,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: {
@@ -2034,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: {
@@ -2093,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;
}
}
@@ -3646,12 +3654,19 @@ void DisplayServerX11::process_events() {
const WindowData &wd = windows[window_id];
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+
// Set focus when menu window is started.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if (!wd.no_focus && !wd.is_popup) {
+ 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: {
@@ -3671,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: {
@@ -4982,6 +4996,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
XNextEvent(x11_display, &xevent);
if (xevent.type == ConfigureNotify) {
_window_changed(&xevent);
+ } else if (xevent.type == MapNotify) {
+ // Have we failed to set fullscreen while the window was unmapped?
+ _validate_mode_on_map(main_window);
}
}