diff options
-rw-r--r-- | doc/classes/DisplayServer.xml | 10 | ||||
-rw-r--r-- | platform/osx/display_server_osx.h | 2 | ||||
-rw-r--r-- | platform/osx/display_server_osx.mm | 28 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 25 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 2 | ||||
-rw-r--r-- | scene/main/window.cpp | 5 | ||||
-rw-r--r-- | servers/display_server.cpp | 5 | ||||
-rw-r--r-- | servers/display_server.h | 1 |
8 files changed, 74 insertions, 4 deletions
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index d28fd5d817..a6b854e36a 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -644,6 +644,16 @@ <description> </description> </method> + <method name="window_set_exclusive"> + <return type="void" /> + <argument index="0" name="window_id" type="int" /> + <argument index="1" name="exclusive" type="bool" /> + <description> + If set to [code]true[/code], this window will always stay on top of its parent window, parent window will ignore input while this window is opened. + [b]Note:[/b] On macOS, exclusive windows are confined to the same space (virtual desktop or screen) as the parent window. + [b]Note:[/b] This method is implemented on macOS and Windows. + </description> + </method> <method name="window_set_flag"> <return type="void" /> <argument index="0" name="flag" type="int" enum="DisplayServer.WindowFlags" /> diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index eaf03d298e..2b57983ca7 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -95,6 +95,7 @@ public: ObjectID instance_id; WindowID transient_parent = INVALID_WINDOW_ID; + bool exclusive = false; Set<WindowID> transient_children; bool layered_window = false; @@ -274,6 +275,7 @@ public: virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_set_transient(WindowID p_window, WindowID p_parent) override; + virtual void window_set_exclusive(WindowID p_window, bool p_exclusive) override; virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 137b1b45b0..b7258e6cf4 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -1471,6 +1471,24 @@ void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window } } +void DisplayServerOSX::window_set_exclusive(WindowID p_window, bool p_exclusive) { + _THREAD_SAFE_METHOD_ + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + if (wd.exclusive != p_exclusive) { + wd.exclusive = p_exclusive; + if (wd.transient_parent != INVALID_WINDOW_ID) { + WindowData &wd_parent = windows[wd.transient_parent]; + if (wd.exclusive) { + ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); + [wd_parent.window_object addChildWindow:wd.window_object ordered:NSWindowAbove]; + } else { + [wd_parent.window_object removeChildWindow:wd.window_object]; + } + } + } +} + Point2i DisplayServerOSX::window_get_position(WindowID p_window) const { _THREAD_SAFE_METHOD_ @@ -1541,8 +1559,11 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent wd_window.transient_parent = INVALID_WINDOW_ID; wd_parent.transient_children.erase(p_window); - [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + + if (wd_window.exclusive) { + [wd_parent.window_object removeChildWindow:wd_window.window_object]; + } } else { ERR_FAIL_COND(!windows.has(p_parent)); ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent"); @@ -1550,8 +1571,11 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent wd_window.transient_parent = p_parent; wd_parent.transient_children.insert(p_window); - [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + + if (wd_window.exclusive) { + [wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove]; + } } } diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 36c87f2683..c7955ebf31 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -830,6 +830,23 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window _update_real_mouse_position(p_window); } +void DisplayServerWindows::window_set_exclusive(WindowID p_window, bool p_exclusive) { + _THREAD_SAFE_METHOD_ + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + if (wd.exclusive != p_exclusive) { + wd.exclusive = p_exclusive; + if (wd.transient_parent != INVALID_WINDOW_ID) { + WindowData &wd_parent = windows[wd.transient_parent]; + if (wd.exclusive) { + SetWindowLongPtr(wd.hWnd, GWLP_HWNDPARENT, (LONG_PTR)wd_parent.hWnd); + } else { + SetWindowLongPtr(wd.hWnd, GWLP_HWNDPARENT, (LONG_PTR) nullptr); + } + } + } +} + void DisplayServerWindows::window_set_transient(WindowID p_window, WindowID p_parent) { _THREAD_SAFE_METHOD_ @@ -852,7 +869,9 @@ void DisplayServerWindows::window_set_transient(WindowID p_window, WindowID p_pa wd_window.transient_parent = INVALID_WINDOW_ID; wd_parent.transient_children.erase(p_window); - SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR) nullptr); + if (wd_window.exclusive) { + SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR) nullptr); + } } else { ERR_FAIL_COND(!windows.has(p_parent)); ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent"); @@ -861,7 +880,9 @@ void DisplayServerWindows::window_set_transient(WindowID p_window, WindowID p_pa wd_window.transient_parent = p_parent; wd_parent.transient_children.insert(p_window); - SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR)wd_parent.hWnd); + if (wd_window.exclusive) { + SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR)wd_parent.hWnd); + } } } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index d36ca97ebe..7561f9bb77 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -339,6 +339,7 @@ class DisplayServerWindows : public DisplayServer { bool always_on_top = false; bool no_focus = false; bool window_has_focus = false; + bool exclusive = false; // Used to transfer data between events using timer. WPARAM saved_wparam; @@ -499,6 +500,7 @@ public: virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_set_transient(WindowID p_window, WindowID p_parent) override; + virtual void window_set_exclusive(WindowID p_window, bool p_exclusive) override; virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index b5e0e7b110..77c0fa2a48 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -255,6 +255,7 @@ void Window::_make_window() { #endif DisplayServer::get_singleton()->window_set_title(tr_title, window_id); DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); + DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); _update_window_size(); @@ -523,6 +524,10 @@ void Window::set_exclusive(bool p_exclusive) { exclusive = p_exclusive; + if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); + } + if (transient_parent) { if (p_exclusive && is_inside_tree() && is_visible()) { ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index d880df2a9b..4d7e2b4d9f 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -204,6 +204,10 @@ void DisplayServer::delete_sub_window(WindowID p_id) { ERR_FAIL_MSG("Sub-windows not supported by this display server."); } +void DisplayServer::window_set_exclusive(WindowID p_window, bool p_exclusive) { + // Do nothing, if not supported. +} + void DisplayServer::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { ERR_FAIL_MSG("Mouse passthrough not supported by this display server."); } @@ -436,6 +440,7 @@ void DisplayServer::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("window_set_exclusive", "window_id", "exclusive"), &DisplayServer::window_set_exclusive); ClassDB::bind_method(D_METHOD("window_set_ime_active", "active", "window_id"), &DisplayServer::window_set_ime_active, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_ime_position", "position", "window_id"), &DisplayServer::window_set_ime_position, DEFVAL(MAIN_WINDOW_ID)); diff --git a/servers/display_server.h b/servers/display_server.h index bd38f28f17..81ac551f57 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -277,6 +277,7 @@ public: virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) = 0; virtual void window_set_transient(WindowID p_window, WindowID p_parent) = 0; + virtual void window_set_exclusive(WindowID p_window, bool p_exclusive); virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) = 0; virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const = 0; |