diff options
-rw-r--r-- | platform/linuxbsd/display_server_x11.cpp | 43 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.h | 5 | ||||
-rw-r--r-- | scene/main/window.cpp | 174 | ||||
-rw-r--r-- | scene/main/window.h | 13 | ||||
-rw-r--r-- | servers/display_server.cpp | 2 | ||||
-rw-r--r-- | servers/display_server.h | 3 |
6 files changed, 236 insertions, 4 deletions
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index b68b766ddd..3e6d244dc6 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -640,6 +640,14 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { WindowData &wd = windows[p_id]; + while (wd.transient_children.size()) { + window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID); + } + + if (wd.transient_parent != INVALID_WINDOW_ID) { + window_set_transient(p_id, INVALID_WINDOW_ID); + } + #ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { context_vulkan->window_destroy(p_id); @@ -733,6 +741,40 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window } } +void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent) { + + ERR_FAIL_COND(p_window == p_parent); + + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd_window = windows[p_window]; + + ERR_FAIL_COND(wd_window.transient_parent == p_parent); + + ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient."); + if (p_parent == INVALID_WINDOW_ID) { + //remove transient + + ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID); + ERR_FAIL_COND(!windows.has(wd_window.transient_parent)); + + WindowData &wd_parent = windows[wd_window.transient_parent]; + + wd_window.transient_parent = INVALID_WINDOW_ID; + wd_parent.transient_children.erase(p_window); + + XSetTransientForHint(x11_display, wd_window.x11_window, None); + } 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"); + WindowData &wd_parent = windows[p_parent]; + + wd_window.transient_parent = p_parent; + wd_parent.transient_children.insert(p_window); + + XSetTransientForHint(x11_display, wd_window.x11_window, wd_parent.x11_window); + } +} + Point2i DisplayServerX11::window_get_position(WindowID p_window) const { ERR_FAIL_COND_V(!windows.has(p_window), Point2i()); const WindowData &wd = windows[p_window]; @@ -1353,6 +1395,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } break; case WINDOW_FLAG_ALWAYS_ON_TOP: { + ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID, "Can't make a window transient if the 'on top' flag is active."); if (p_enabled && wd.fullscreen) { _set_wm_maximized(p_window, true); } diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index e17078c5ca..85d6dbf972 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -125,6 +125,9 @@ class DisplayServerX11 : public DisplayServer { Callable input_text_callback; Callable drop_files_callback; + WindowID transient_parent = INVALID_WINDOW_ID; + Set<WindowID> transient_children; + //better to guess on the fly, given WM can change it //WindowMode mode; bool fullscreen = false; //OS can't exit from this mode @@ -278,6 +281,8 @@ public: virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID); virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const; + virtual void window_set_transient(WindowID p_window, WindowID p_parent); + virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID); virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index cfc3fa87c4..b1f2f0cc97 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -217,6 +217,16 @@ void Window::_make_window() { DisplayServer::get_singleton()->window_set_title(title, window_id); _update_size(); + + if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); + } + + for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) { + if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, transient_parent->window_id); + } + } } void Window::_update_from_window() { @@ -233,6 +243,17 @@ void Window::_update_from_window() { void Window::_clear_window() { ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); + + if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID); + } + + for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) { + if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, DisplayServer::INVALID_WINDOW_ID); + } + } + _update_from_window(); DisplayServer::get_singleton()->delete_sub_window(window_id); window_id = DisplayServer::INVALID_WINDOW_ID; @@ -310,6 +331,69 @@ void Window::set_visible(bool p_visible) { _update_size(); } } + +void Window::_clear_transient() { + if (transient_parent) { + if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID); + } + transient_parent->transient_children.erase(this); + transient_parent = nullptr; + } +} + +void Window::_make_transient() { + if (!get_parent()) { + //main window, can't be transient + return; + } + //find transient parent + Viewport *vp = get_parent()->get_viewport(); + Window *window = nullptr; + while (vp) { + window = Object::cast_to<Window>(vp); + if (window) { + break; + } + if (!vp->get_parent()) { + break; + } + + vp = vp->get_parent()->get_viewport(); + } + + if (window) { + transient_parent = window; + window->transient_children.insert(this); + } + + //see if we can make transient + if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); + } +} + +void Window::set_transient(bool p_transient) { + if (transient == p_transient) { + return; + } + + transient = p_transient; + + if (!is_inside_tree()) { + return; + } + + if (transient) { + _make_transient(); + } else { + _clear_transient(); + } +} +bool Window::is_transient() const { + return transient; +} + bool Window::is_visible() const { return visible; } @@ -467,9 +551,18 @@ void Window::_notification(int p_what) { _update_window_callbacks(); } } + + if (transient) { + _make_transient(); + } } if (p_what == NOTIFICATION_EXIT_TREE) { + + if (transient) { + _clear_transient(); + } + if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) { if (window_id == DisplayServer::MAIN_WINDOW_ID) { @@ -495,7 +588,7 @@ Size2i Window::get_content_scale_size() const { return content_scale_size; } -void Window::set_content_scale_mode(const ContentScaleMode &p_mode) { +void Window::set_content_scale_mode(ContentScaleMode p_mode) { content_scale_mode = p_mode; _update_size(); } @@ -503,7 +596,7 @@ Window::ContentScaleMode Window::get_content_scale_mode() const { return content_scale_mode; } -void Window::set_content_scale_aspect(const ContentScaleAspect &p_aspect) { +void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) { content_scale_aspect = p_aspect; _update_size(); } @@ -553,6 +646,83 @@ void Window::_window_drop_files(const Vector<String> &p_files) { void Window::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title); + ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title); + + ClassDB::bind_method(D_METHOD("set_current_screen", "index"), &Window::set_current_screen); + ClassDB::bind_method(D_METHOD("get_current_screen"), &Window::get_current_screen); + + ClassDB::bind_method(D_METHOD("set_position", "position"), &Window::set_position); + ClassDB::bind_method(D_METHOD("get_position"), &Window::get_position); + + ClassDB::bind_method(D_METHOD("set_size", "size"), &Window::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size); + + ClassDB::bind_method(D_METHOD("get_real_size"), &Window::get_real_size); + + ClassDB::bind_method(D_METHOD("set_max_size", "max_size"), &Window::set_max_size); + ClassDB::bind_method(D_METHOD("get_max_size"), &Window::get_max_size); + + ClassDB::bind_method(D_METHOD("set_min_size", "min_size"), &Window::set_min_size); + ClassDB::bind_method(D_METHOD("get_min_size"), &Window::get_min_size); + + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Window::set_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &Window::get_mode); + + ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &Window::set_flag); + ClassDB::bind_method(D_METHOD("get_flag", "flag"), &Window::get_flag); + + ClassDB::bind_method(D_METHOD("is_maximize_allowed"), &Window::is_maximize_allowed); + + ClassDB::bind_method(D_METHOD("request_attention"), &Window::request_attention); + + ClassDB::bind_method(D_METHOD("move_to_foreground"), &Window::move_to_foreground); + + ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Window::set_visible); + ClassDB::bind_method(D_METHOD("is_visible"), &Window::is_visible); + + ClassDB::bind_method(D_METHOD("set_transient", "transient"), &Window::set_transient); + ClassDB::bind_method(D_METHOD("is_transient"), &Window::is_transient); + + ClassDB::bind_method(D_METHOD("can_draw"), &Window::is_transient); + + ClassDB::bind_method(D_METHOD("set_ime_active"), &Window::set_ime_active); + ClassDB::bind_method(D_METHOD("set_ime_position"), &Window::set_ime_position); + + ClassDB::bind_method(D_METHOD("is_embedded"), &Window::is_embedded); + + ClassDB::bind_method(D_METHOD("set_content_scale_size", "size"), &Window::set_content_scale_size); + ClassDB::bind_method(D_METHOD("get_content_scale_size"), &Window::get_content_scale_size); + + ClassDB::bind_method(D_METHOD("set_content_scale_mode", "mode"), &Window::set_content_scale_mode); + ClassDB::bind_method(D_METHOD("get_content_scale_mode"), &Window::get_content_scale_mode); + + ClassDB::bind_method(D_METHOD("set_content_scale_aspect", "aspect"), &Window::set_content_scale_aspect); + ClassDB::bind_method(D_METHOD("get_content_scale_aspect"), &Window::get_content_scale_aspect); + + ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &Window::set_use_font_oversampling); + ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &Window::is_using_font_oversampling); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,FullScreen"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_screen"), "set_current_screen", "get_current_screen"); + ADD_GROUP("Flags", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient"), "set_transient", "is_transient"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unresizable"), "set_flag", "get_flag", FLAG_RESIZE_DISABLED); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "borderless"), "set_flag", "get_flag", FLAG_BORDERLESS); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT); + ADD_GROUP("Limits", ""); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size"), "set_max_size", "get_max_size"); + ADD_GROUP("Content Scale", "content_scale_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Object,Pixels"), "set_content_scale_mode", "get_content_scale_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,KeepWidth,KeepHeight,Expand"), "set_content_scale_aspect", "get_content_scale_aspect"); + ADD_SIGNAL(MethodInfo("files_dropped")); ADD_SIGNAL(MethodInfo("mouse_entered")); ADD_SIGNAL(MethodInfo("mouse_exited")); diff --git a/scene/main/window.h b/scene/main/window.h index 0c689a001f..795e415396 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -85,6 +85,7 @@ private: bool visible = true; bool use_font_oversampling = false; + bool transient = false; Size2i content_scale_size; ContentScaleMode content_scale_mode; @@ -110,6 +111,11 @@ private: void _window_unhandled_input(const Ref<InputEvent> &p_ev); void _update_window_callbacks(); + void _clear_transient(); + void _make_transient(); + Window *transient_parent = nullptr; + Set<Window *> transient_children; + protected: static void _bind_methods(); void _notification(int p_what); @@ -149,6 +155,9 @@ public: void set_visible(bool p_visible); bool is_visible() const; + void set_transient(bool p_transient); + bool is_transient() const; + bool can_draw() const; void set_ime_active(bool p_active); @@ -159,10 +168,10 @@ public: void set_content_scale_size(const Size2i &p_size); Size2i get_content_scale_size() const; - void set_content_scale_mode(const ContentScaleMode &p_mode); + void set_content_scale_mode(ContentScaleMode p_mode); ContentScaleMode get_content_scale_mode() const; - void set_content_scale_aspect(const ContentScaleAspect &p_aspect); + void set_content_scale_aspect(ContentScaleAspect p_aspect); ContentScaleAspect get_content_scale_aspect() const; void set_use_font_oversampling(bool p_oversampling); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index f764e3b528..102012f6d4 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -299,6 +299,8 @@ void DisplayServer::_bind_methods() { 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_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_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 28f9485f6e..5da9c76216 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -194,6 +194,7 @@ public: virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0; virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0; virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0; + virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0; virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) = 0; @@ -204,6 +205,8 @@ public: virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const = 0; 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_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; |