[X11] Fix Godot stealing focus on alternative Window Managers

This commit is contained in:
mequam 2023-03-04 11:52:15 -05:00 committed by David Snopek
parent 9d1cbab1c4
commit 40d69c25d5
2 changed files with 21 additions and 4 deletions

View File

@ -2010,7 +2010,7 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
// RevertToPointerRoot is used to make sure we don't lose all focus in case // RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed. // a subwindow and its parent are both destroyed.
if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) { if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) {
if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) { if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup && _window_focus_check()) {
XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime); XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
} }
} }
@ -2945,7 +2945,7 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win
XWindowAttributes xwa; XWindowAttributes xwa;
XSync(x11_display, False); XSync(x11_display, False);
XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa); XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
if (xwa.map_state == IsViewable) { if (xwa.map_state == IsViewable && _window_focus_check()) {
XSetInputFocus(x11_display, wd.x11_xim_window, RevertToParent, CurrentTime); XSetInputFocus(x11_display, wd.x11_xim_window, RevertToParent, CurrentTime);
} }
XSetICFocus(wd.xic); XSetICFocus(wd.xic);
@ -4228,6 +4228,22 @@ bool DisplayServerX11::mouse_process_popups() {
return closed; return closed;
} }
bool DisplayServerX11::_window_focus_check() {
Window focused_window;
int focus_ret_state;
XGetInputFocus(x11_display, &focused_window, &focus_ret_state);
bool has_focus = false;
for (const KeyValue<int, DisplayServerX11::WindowData> &wid : windows) {
if (wid.value.x11_window == focused_window) {
has_focus = true;
break;
}
}
return has_focus;
}
void DisplayServerX11::process_events() { void DisplayServerX11::process_events() {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
@ -4499,7 +4515,7 @@ void DisplayServerX11::process_events() {
// Set focus when menu window is started. // Set focus when menu window is started.
// RevertToPointerRoot is used to make sure we don't lose all focus in case // RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed. // a subwindow and its parent are both destroyed.
if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) { if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
} }
@ -4675,7 +4691,7 @@ void DisplayServerX11::process_events() {
// Set focus when menu window is re-used. // Set focus when menu window is re-used.
// RevertToPointerRoot is used to make sure we don't lose all focus in case // RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed. // a subwindow and its parent are both destroyed.
if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) { if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
} }

View File

@ -354,6 +354,7 @@ class DisplayServerX11 : public DisplayServer {
Context context = CONTEXT_ENGINE; Context context = CONTEXT_ENGINE;
WindowID _get_focused_window_or_popup() const; WindowID _get_focused_window_or_popup() const;
bool _window_focus_check();
void _send_window_event(const WindowData &wd, WindowEvent p_event); void _send_window_event(const WindowData &wd, WindowEvent p_event);
static void _dispatch_input_events(const Ref<InputEvent> &p_event); static void _dispatch_input_events(const Ref<InputEvent> &p_event);