diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 94c2e989f1c..cb4b0d745b6 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -2339,6 +2339,24 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev void DisplayServerX11::process_events() { _THREAD_SAFE_METHOD_ + if (app_focused) { + //verify that one of the windows has focus, else send focus out notification + bool focus_found = false; + for (Map::Element *E = windows.front(); E; E = E->next()) { + if (E->get().focused) { + focus_found = true; + } + } + + if (!focus_found) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); + } + + app_focused = false; + } + } + do_mouse_warp = false; // Is the current mouse mode one where it needs to be grabbed. @@ -2533,12 +2551,12 @@ void DisplayServerX11::process_events() { break; case NoExpose: - minimized = true; + windows[window_id].minimized = true; break; case VisibilityNotify: { XVisibilityEvent *visibility = (XVisibilityEvent *)&event; - minimized = (visibility->state == VisibilityFullyObscured); + windows[window_id].minimized = (visibility->state == VisibilityFullyObscured); } break; case LeaveNotify: { if (!mouse_mode_grab) { @@ -2552,10 +2570,8 @@ void DisplayServerX11::process_events() { } } break; case FocusIn: - minimized = false; - window_has_focus = true; + windows[window_id].focused = true; _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN); - window_focused = true; if (mouse_mode_grab) { // Show and update the cursor if confined and the window regained focus. @@ -2582,13 +2598,19 @@ void DisplayServerX11::process_events() { if (windows[window_id].xic) { XSetICFocus(windows[window_id].xic); } + + if (!app_focused) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); + } + app_focused = true; + } break; case FocusOut: - window_has_focus = false; + windows[window_id].focused = false; Input::get_singleton()->release_pressed_events(); _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT); - window_focused = false; if (mouse_mode_grab) { for (Map::Element *E = windows.front(); E; E = E->next()) { @@ -2727,7 +2749,7 @@ void DisplayServerX11::process_events() { Point2i new_center = pos; pos = last_mouse_pos + xi.relative_motion; center = new_center; - do_mouse_warp = window_has_focus; // warp the cursor if we're focused in + do_mouse_warp = windows[window_id].focused; // warp the cursor if we're focused in } if (!last_mouse_pos_valid) { @@ -2787,7 +2809,7 @@ void DisplayServerX11::process_events() { // Don't propagate the motion event unless we have focus // this is so that the relative motion doesn't get messed up // after we regain focus. - if (window_has_focus || !mouse_mode_grab) { + if (windows[window_id].focused || !mouse_mode_grab) { Input::get_singleton()->accumulate_input_event(mm); } @@ -3764,8 +3786,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode requested = None; - window_has_focus = true; // Set focus to true at init - /*if (p_desired.layered) { set_window_per_pixel_transparency_enabled(true); }*/ diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 3b2ff0e08d4..3d0b2c7e8a3 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -139,6 +139,8 @@ class DisplayServerX11 : public DisplayServer { bool borderless = false; bool resize_disabled = false; Vector2i last_position_before_fs; + bool focused = false; + bool minimized = false; }; Map windows; @@ -164,6 +166,7 @@ class DisplayServerX11 : public DisplayServer { uint64_t last_click_ms; int last_click_button_index; uint32_t last_button_state; + bool app_focused = false; struct { int opcode; @@ -195,8 +198,8 @@ class DisplayServerX11 : public DisplayServer { void _handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo = false); - bool minimized; - bool window_has_focus; + //bool minimized; + //bool window_has_focus; bool do_mouse_warp; const char *cursor_theme; @@ -210,7 +213,7 @@ class DisplayServerX11 : public DisplayServer { bool layered_window; String rendering_driver; - bool window_focused; + //bool window_focused; //void set_wm_border(bool p_enabled); void set_wm_fullscreen(bool p_enabled); void set_wm_above(bool p_enabled); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 8042f02fa67..0d5d222f5ef 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2913,6 +2913,10 @@ void Viewport::input(const Ref &p_event, bool p_local_coords) { return; } + if (!_can_consume_input_events()) { + return; + } + if (!is_input_handled()) { get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input } @@ -2926,7 +2930,7 @@ void Viewport::input(const Ref &p_event, bool p_local_coords) { void Viewport::unhandled_input(const Ref &p_event, bool p_local_coords) { ERR_FAIL_COND(!is_inside_tree()); - if (disable_input) { + if (disable_input || !_can_consume_input_events()) { return; } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 11fe4f00d24..d45b321f73f 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -441,6 +441,8 @@ private: bool _sub_windows_forward_input(const Ref &p_event); SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point); + virtual bool _can_consume_input_events() const { return true; } + protected: void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 7f2160c6a5a..8604bb78aca 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -874,6 +874,10 @@ void Window::child_controls_changed() { call_deferred("_update_child_controls"); } +bool Window::_can_consume_input_events() const { + return exclusive_child == nullptr; +} + void Window::_window_input(const Ref &p_ev) { if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to(p_ev.ptr()) || Object::cast_to(*p_ev))) { return; //avoid joy input on editor @@ -890,10 +894,13 @@ void Window::_window_input(const Ref &p_ev) { if (exclusive_child != nullptr) { exclusive_child->grab_focus(); - return; //has an exclusive child, can't get events until child is closed + if (!is_embedding_subwindows()) { //not embedding, no need for event + return; + } } emit_signal(SceneStringNames::get_singleton()->window_input, p_ev); + input(p_ev); if (!is_input_handled()) { unhandled_input(p_ev); diff --git a/scene/main/window.h b/scene/main/window.h index adaa5ca3be2..89c94753daf 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -130,6 +130,7 @@ private: void _window_drop_files(const Vector &p_files); void _rect_changed_callback(const Rect2i &p_callback); void _event_callback(DisplayServer::WindowEvent p_event); + virtual bool _can_consume_input_events() const; protected: Viewport *_get_embedder() const;