diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index cd39543c453..194fc8a5030 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1258,6 +1258,13 @@ Returns the V-Sync mode of the given window. + + + + + Returns [code]true[/code] if the window specified by [param window_id] is focused. + + diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 4d9a49c35cd..f02b292868d 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -453,6 +453,10 @@ void DisplayServerAndroid::window_move_to_foreground(DisplayServer::WindowID p_w // Not supported on Android. } +bool DisplayServerAndroid::window_is_focused(WindowID p_window) const { + return true; +} + bool DisplayServerAndroid::window_can_draw(DisplayServer::WindowID p_window) const { return true; } diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index ad1cbddb08b..e0ad2cb9161 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -178,6 +178,7 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h index b29bdeec621..da16449c613 100644 --- a/platform/ios/display_server_ios.h +++ b/platform/ios/display_server_ios.h @@ -193,6 +193,7 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; virtual float screen_get_max_scale() const override; diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index bfb09b68615..7d91274a0c5 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -562,6 +562,10 @@ void DisplayServerIOS::window_move_to_foreground(WindowID p_window) { // Probably not supported for iOS } +bool DisplayServerIOS::window_is_focused(WindowID p_window) const { + return true; +} + float DisplayServerIOS::screen_get_max_scale() const { return screen_get_scale(SCREEN_OF_MAIN_WINDOW); } diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 83b6fb76284..a607e26ac54 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -2626,6 +2626,15 @@ void DisplayServerX11::window_move_to_foreground(WindowID p_window) { XFlush(x11_display); } +bool DisplayServerX11::window_is_focused(WindowID p_window) const { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; + + return wd.focused; +} + bool DisplayServerX11::window_can_draw(WindowID p_window) const { //this seems to be all that is provided by X11 return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED; diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 176a1ffb9ab..180362923ba 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -477,6 +477,7 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 5944cc8abd8..93fa93b2592 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -117,6 +117,7 @@ public: bool no_focus = false; bool is_popup = false; bool mpass = false; + bool focused = false; Rect2i parent_safe_rect; }; @@ -390,6 +391,7 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index b77715d6486..a0a851b7dce 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -3075,6 +3075,15 @@ void DisplayServerMacOS::window_move_to_foreground(WindowID p_window) { } } +bool DisplayServerMacOS::window_is_focused(WindowID p_window) const { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; + + return wd.focused; +} + bool DisplayServerMacOS::window_can_draw(WindowID p_window) const { return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED; } diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm index df971c51392..1c6dbb1981a 100644 --- a/platform/macos/godot_window_delegate.mm +++ b/platform/macos/godot_window_delegate.mm @@ -314,6 +314,7 @@ [self windowDidResize:notification]; // Emit resize event, to ensure content is resized if the window was resized while it was hidden. + wd.focused = true; ds->set_last_focused_window(window_id); ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); } @@ -330,6 +331,7 @@ [(GodotButtonView *)wd.window_button_view displayButtons]; } + wd.focused = false; ds->release_pressed_events(); ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } @@ -342,6 +344,7 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + wd.focused = false; ds->release_pressed_events(); ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } @@ -353,9 +356,11 @@ } DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); - - ds->set_last_focused_window(window_id); - ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); + if ([wd.window_object isKeyWindow]) { + wd.focused = true; + ds->set_last_focused_window(window_id); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); + } } @end diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index 6cb56b404fd..951ce110e02 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -1073,6 +1073,10 @@ void DisplayServerWeb::window_move_to_foreground(WindowID p_window) { // Not supported. } +bool DisplayServerWeb::window_is_focused(WindowID p_window) const { + return true; +} + bool DisplayServerWeb::window_can_draw(WindowID p_window) const { return true; } diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h index 3b03b102cdb..a4fd75f33b3 100644 --- a/platform/web/display_server_web.h +++ b/platform/web/display_server_web.h @@ -211,6 +211,7 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index fc208eb4bb0..ea93c47ec5e 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1615,6 +1615,15 @@ void DisplayServerWindows::window_move_to_foreground(WindowID p_window) { } } +bool DisplayServerWindows::window_is_focused(WindowID p_window) const { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; + + return wd.window_focused; +} + bool DisplayServerWindows::window_can_draw(WindowID p_window) const { _THREAD_SAFE_METHOD_ diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index ae2cd4e8b59..7228de7d317 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -594,6 +594,7 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index b82b215e546..e8395f59c96 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -616,6 +616,8 @@ void Window::_update_from_window() { void Window::_clear_window() { ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); + bool had_focus = has_focus(); + DisplayServer::get_singleton()->window_set_rect_changed_callback(Callable(), window_id); DisplayServer::get_singleton()->window_set_window_event_callback(Callable(), window_id); DisplayServer::get_singleton()->window_set_input_event_callback(Callable(), window_id); @@ -638,7 +640,7 @@ void Window::_clear_window() { window_id = DisplayServer::INVALID_WINDOW_ID; // If closing window was focused and has a parent, return focus. - if (focused && transient_parent) { + if (had_focus && transient_parent) { transient_parent->grab_focus(); } @@ -1185,6 +1187,7 @@ void Window::_notification(int p_what) { { position = DisplayServer::get_singleton()->window_get_position(window_id); size = DisplayServer::get_singleton()->window_get_size(window_id); + focused = DisplayServer::get_singleton()->window_is_focused(window_id); } _update_window_size(); // Inform DisplayServer of minimum and maximum size. _update_viewport_size(); // Then feed back to the viewport. @@ -1762,6 +1765,9 @@ void Window::grab_focus() { bool Window::has_focus() const { ERR_READ_THREAD_GUARD_V(false); + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + return DisplayServer::get_singleton()->window_is_focused(window_id); + } return focused; } diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 516f2f1be6b..41fa0d2d477 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -716,6 +716,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_move_to_foreground", "window_id"), &DisplayServer::window_move_to_foreground, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_is_focused", "window_id"), &DisplayServer::window_is_focused, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_can_draw", "window_id"), &DisplayServer::window_can_draw, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_transient", "window_id", "parent_window_id"), &DisplayServer::window_set_transient); diff --git a/servers/display_server.h b/servers/display_server.h index d8e67b4f927..fc8207f2d36 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -424,6 +424,7 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const = 0; virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) {} virtual Vector3i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector3i(); } diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 0c43b84f2ee..af13f8db21c 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -119,6 +119,7 @@ public: void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override {} void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override {} + bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override { return true; }; bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override { return false; }