From c8de3a54c6bda5dfe5479e5c7c16db3cb9c5a803 Mon Sep 17 00:00:00 2001
From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com>
Date: Sun, 9 Jul 2023 23:36:55 +0200
Subject: [PATCH] Expose getters for the currently focused Window
Replace the last focused Window by the currently focused Window
on Linux, Windows and macOS.
---
doc/classes/DisplayServer.xml | 6 ++++++
doc/classes/Viewport.xml | 6 ++++++
platform/linuxbsd/x11/display_server_x11.cpp | 5 +++--
platform/linuxbsd/x11/display_server_x11.h | 4 ++--
platform/macos/display_server_macos.h | 6 +++---
platform/macos/display_server_macos.mm | 6 +++---
platform/macos/godot_window_delegate.mm | 6 ++++--
platform/windows/display_server_windows.cpp | 14 +++++++-------
platform/windows/display_server_windows.h | 4 ++--
scene/main/viewport.cpp | 5 +++++
scene/main/viewport.h | 1 +
servers/display_server.cpp | 9 +++++++++
servers/display_server.h | 5 +++++
13 files changed, 56 insertions(+), 21 deletions(-)
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index c2f81ba1094b..72d2537c55e7 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -194,6 +194,12 @@
[b]Note:[/b] This doesn't affect native dialogs such as the ones spawned by [method DisplayServer.dialog_show].
+
+
+
+ Returns the [method Object.get_instance_id] of the top [Popup] if available or of the currently focused [Window].
+
+
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 43640916f442..041d76f94344 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -104,6 +104,12 @@
[/codeblock]
+
+
+
+ Returns the top [Popup] if available or the currently focused [Window].
+
+
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index f38a9dd27833..6d3f9b6aeebb 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -3741,7 +3741,7 @@ DisplayServer::WindowID DisplayServerX11::_get_focused_window_or_popup() const {
return E->get();
}
- return last_focused_window;
+ return currently_focused_window;
}
void DisplayServerX11::_dispatch_input_events(const Ref &p_event) {
@@ -4346,7 +4346,7 @@ void DisplayServerX11::process_events() {
}
WindowData &wd = windows[window_id];
- last_focused_window = window_id;
+ currently_focused_window = window_id;
wd.focused = true;
// Keep track of focus order for overlapping windows.
@@ -4401,6 +4401,7 @@ void DisplayServerX11::process_events() {
im_selection = Vector2i();
OS_Unix::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
}
+ currently_focused_window = INVALID_WINDOW_ID;
wd.focused = false;
Input::get_singleton()->release_pressed_events();
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 71beddce7623..70811fd15f71 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -226,7 +226,7 @@ class DisplayServerX11 : public DisplayServer {
List popup_list;
WindowID window_mouseover_id = INVALID_WINDOW_ID;
- WindowID last_focused_window = INVALID_WINDOW_ID;
+ WindowID currently_focused_window = INVALID_WINDOW_ID;
WindowID window_id_counter = MAIN_WINDOW_ID;
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
@@ -348,7 +348,7 @@ class DisplayServerX11 : public DisplayServer {
Context context = CONTEXT_ENGINE;
- WindowID _get_focused_window_or_popup() const;
+ virtual WindowID _get_focused_window_or_popup() const override;
void _send_window_event(const WindowData &wd, WindowEvent p_event);
static void _dispatch_input_events(const Ref &p_event);
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 69f600804353..d8ba57947bd7 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -172,7 +172,7 @@ class DisplayServerMacOS : public DisplayServer {
bool keyboard_layout_dirty = true;
WindowID window_mouseover_id = INVALID_WINDOW_ID;
- WindowID last_focused_window = INVALID_WINDOW_ID;
+ WindowID currently_focused_window = INVALID_WINDOW_ID;
WindowID window_id_counter = MAIN_WINDOW_ID;
float display_max_scale = 1.f;
Point2i origin;
@@ -233,14 +233,14 @@ class DisplayServerMacOS : public DisplayServer {
void push_to_key_event_buffer(const KeyEvent &p_event);
void pop_last_key_event();
void update_im_text(const Point2i &p_selection, const String &p_text);
- void set_last_focused_window(WindowID p_window);
+ void set_currently_focused_window(WindowID p_window);
bool mouse_process_popups(bool p_close = false);
void popup_open(WindowID p_window);
void popup_close(WindowID p_window);
void set_is_resizing(bool p_is_resizing);
bool get_is_resizing() const;
void reparent_check(WindowID p_window);
- WindowID _get_focused_window_or_popup() const;
+ virtual WindowID _get_focused_window_or_popup() const override;
void mouse_enter_window(WindowID p_window);
void mouse_exit_window(WindowID p_window);
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index e79d6acc3f89..d91521be63ca 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -363,7 +363,7 @@
return E->get();
}
- return last_focused_window;
+ return currently_focused_window;
}
void DisplayServerMacOS::mouse_enter_window(WindowID p_window) {
@@ -718,8 +718,8 @@
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
}
-void DisplayServerMacOS::set_last_focused_window(WindowID p_window) {
- last_focused_window = p_window;
+void DisplayServerMacOS::set_currently_focused_window(WindowID p_window) {
+ currently_focused_window = p_window;
}
void DisplayServerMacOS::set_is_resizing(bool p_is_resizing) {
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 46355b4ae8fa..8c3e06f54625 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -316,7 +316,7 @@ - (void)windowDidBecomeKey:(NSNotification *)notification {
[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->set_currently_focused_window(window_id);
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN);
}
@@ -333,6 +333,7 @@ - (void)windowDidResignKey:(NSNotification *)notification {
}
wd.focused = false;
+ ds->set_currently_focused_window(DisplayServerMacOS::INVALID_WINDOW_ID);
ds->release_pressed_events();
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT);
}
@@ -346,6 +347,7 @@ - (void)windowDidMiniaturize:(NSNotification *)notification {
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
wd.focused = false;
+ ds->set_currently_focused_window(DisplayServerMacOS::INVALID_WINDOW_ID);
ds->release_pressed_events();
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT);
}
@@ -359,7 +361,7 @@ - (void)windowDidDeminiaturize:(NSNotification *)notification {
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
if ([wd.window_object isKeyWindow]) {
wd.focused = true;
- ds->set_last_focused_window(window_id);
+ ds->set_currently_focused_window(window_id);
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN);
}
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 5863a75324ff..94016e23481e 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -158,7 +158,7 @@ DisplayServer::WindowID DisplayServerWindows::_get_focused_window_or_popup() con
return E->get();
}
- return last_focused_window;
+ return currently_focused_window;
}
void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) {
@@ -476,10 +476,10 @@ String DisplayServerWindows::clipboard_get() const {
Ref DisplayServerWindows::clipboard_get_image() const {
Ref image;
- if (!windows.has(last_focused_window)) {
+ if (!windows.has(currently_focused_window)) {
return image; // No focused window?
}
- if (!OpenClipboard(windows[last_focused_window].hWnd)) {
+ if (!OpenClipboard(windows[currently_focused_window].hWnd)) {
ERR_FAIL_V_MSG(image, "Unable to open clipboard.");
}
UINT png_format = RegisterClipboardFormatA("PNG");
@@ -1082,8 +1082,8 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
DestroyWindow(windows[p_window].hWnd);
windows.erase(p_window);
- if (last_focused_window == p_window) {
- last_focused_window = INVALID_WINDOW_ID;
+ if (currently_focused_window == p_window) {
+ currently_focused_window = INVALID_WINDOW_ID;
}
}
@@ -2843,7 +2843,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_SETFOCUS: {
windows[window_id].window_has_focus = true;
- last_focused_window = window_id;
+ currently_focused_window = window_id;
// Restore mouse mode.
_set_mouse_mode_impl(mouse_mode);
@@ -2857,7 +2857,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_KILLFOCUS: {
windows[window_id].window_has_focus = false;
- last_focused_window = window_id;
+ currently_focused_window = INVALID_WINDOW_ID;
// Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
ReleaseCapture();
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 59c444260410..89a1c8a38a6f 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -438,7 +438,7 @@ class DisplayServerWindows : public DisplayServer {
WindowID window_id_counter = MAIN_WINDOW_ID;
RBMap windows;
- WindowID last_focused_window = INVALID_WINDOW_ID;
+ WindowID currently_focused_window = INVALID_WINDOW_ID;
HCURSOR hCursor;
@@ -476,7 +476,7 @@ class DisplayServerWindows : public DisplayServer {
void _update_real_mouse_position(WindowID p_window);
void _set_mouse_mode_impl(MouseMode p_mode);
- WindowID _get_focused_window_or_popup() const;
+ virtual WindowID _get_focused_window_or_popup() const override;
void _register_raw_input_devices(WindowID p_target_window);
void _process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index dac600d5d9a9..a78c520d584f 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2450,6 +2450,10 @@ Window *Viewport::get_base_window() const {
return w;
}
+Window *Viewport::get_top_popup_or_focused_window() const {
+ return gui.subwindow_focused;
+}
+
void Viewport::_gui_remove_focus_for_window(Node *p_window) {
if (get_base_window() == p_window) {
gui_release_focus();
@@ -4427,6 +4431,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_embedding_subwindows", "enable"), &Viewport::set_embedding_subwindows);
ClassDB::bind_method(D_METHOD("is_embedding_subwindows"), &Viewport::is_embedding_subwindows);
ClassDB::bind_method(D_METHOD("get_embedded_subwindows"), &Viewport::get_embedded_subwindows);
+ ClassDB::bind_method(D_METHOD("get_top_popup_or_focused_window"), &Viewport::get_top_popup_or_focused_window);
ClassDB::bind_method(D_METHOD("set_canvas_cull_mask", "mask"), &Viewport::set_canvas_cull_mask);
ClassDB::bind_method(D_METHOD("get_canvas_cull_mask"), &Viewport::get_canvas_cull_mask);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 6fb9a6c510cd..665e73ee1d73 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -662,6 +662,7 @@ class Viewport : public Node {
Viewport *get_parent_viewport() const;
Window *get_base_window() const;
+ Window *get_top_popup_or_focused_window() const;
void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index f41238b07547..26f157b75ad0 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -435,6 +435,14 @@ void DisplayServer::delete_sub_window(WindowID p_id) {
ERR_FAIL_MSG("Sub-windows not supported by this display server.");
}
+ObjectID DisplayServer::get_top_popup_or_focused_window() const {
+ WindowID wid = _get_focused_window_or_popup();
+ if (wid == INVALID_WINDOW_ID) {
+ return ObjectID();
+ }
+ return window_get_attached_instance_id(wid);
+}
+
void DisplayServer::window_set_exclusive(WindowID p_window, bool p_exclusive) {
// Do nothing, if not supported.
}
@@ -689,6 +697,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_window_list"), &DisplayServer::get_window_list);
ClassDB::bind_method(D_METHOD("get_window_at_screen_position", "position"), &DisplayServer::get_window_at_screen_position);
+ ClassDB::bind_method(D_METHOD("get_top_popup_or_focused_window"), &DisplayServer::get_top_popup_or_focused_window);
ClassDB::bind_method(D_METHOD("window_get_native_handle", "handle_type", "window_id"), &DisplayServer::window_get_native_handle, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_active_popup"), &DisplayServer::window_get_active_popup);
diff --git a/servers/display_server.h b/servers/display_server.h
index 85f92706965e..1ac500ea386b 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -330,6 +330,10 @@ class DisplayServer : public Object {
typedef int WindowID;
+private:
+ virtual WindowID _get_focused_window_or_popup() const { return MAIN_WINDOW_ID; };
+
+public:
virtual Vector get_window_list() const = 0;
enum WindowFlags {
@@ -367,6 +371,7 @@ class DisplayServer : public Object {
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const;
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0;
+ ObjectID get_top_popup_or_focused_window() const;
virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const = 0;