diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 193dbe6a10..90eba0bdea 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -557,6 +557,19 @@ Makes the [Window] appear. This enables interactions with the [Window] and doesn't change any of its property other than visibility (unlike e.g. [method popup]). + + + + Starts an interactive drag operation on the window, using the current mouse position. Call this method when handling a mouse button being pressed to simulate a pressed event on the window's title bar. Using this method allows the window to participate in space switching, tiling, and other system features. + + + + + + + Starts an interactive resize operation on the window, using the current mouse position. Call this method when handling a mouse button being pressed to simulate a pressed event on the window's edge. + + diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 8a33e10cbe..77f08095b1 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -5496,6 +5496,10 @@ void DisplayServerX11::window_start_drag(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (wd.embed_parent) { + return; // Embedded window. + } + XClientMessageEvent m; memset(&m, 0, sizeof(m)); @@ -5532,6 +5536,10 @@ void DisplayServerX11::window_start_resize(WindowResizeEdge p_edge, WindowID p_w ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (wd.embed_parent) { + return; // Embedded window. + } + XClientMessageEvent m; memset(&m, 0, sizeof(m)); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index c053408ed4..0c331725bd 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3990,6 +3990,10 @@ void DisplayServerWindows::window_start_drag(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (wd.parent_hwnd) { + return; // Embedded window. + } + ReleaseCapture(); POINT coords; @@ -4006,6 +4010,10 @@ void DisplayServerWindows::window_start_resize(WindowResizeEdge p_edge, WindowID ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (wd.parent_hwnd) { + return; // Embedded window. + } + ReleaseCapture(); POINT coords; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 6a898bd5ca..6043006786 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2956,6 +2956,47 @@ bool Viewport::_sub_windows_forward_input(const Ref &p_event) { return true; } +void Viewport::_window_start_drag(Window *p_window) { + int index = _sub_window_find(p_window); + ERR_FAIL_COND(index == -1); + + SubWindow sw = gui.sub_windows.write[index]; + + if (gui.subwindow_focused != sw.window) { + // Refocus. + _sub_window_grab_focus(sw.window); + } + + gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE; + gui.subwindow_drag_from = get_mouse_position(); + gui.subwindow_drag_pos = sw.window->get_position(); + gui.currently_dragged_subwindow = sw.window; + + _sub_window_update(sw.window); +} + +void Viewport::_window_start_resize(SubWindowResize p_edge, Window *p_window) { + int index = _sub_window_find(p_window); + ERR_FAIL_COND(index == -1); + + SubWindow sw = gui.sub_windows.write[index]; + Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size()); + + if (gui.subwindow_focused != sw.window) { + // Refocus. + _sub_window_grab_focus(sw.window); + } + + gui.subwindow_drag = SUB_WINDOW_DRAG_RESIZE; + gui.subwindow_resize_mode = p_edge; + gui.subwindow_resize_from_rect = r; + gui.subwindow_drag_from = get_mouse_position(); + gui.subwindow_drag_pos = sw.window->get_position(); + gui.currently_dragged_subwindow = sw.window; + + _sub_window_update(sw.window); +} + void Viewport::_update_mouse_over() { // Update gui.mouse_over and gui.subwindow_over in all Viewports. // Send necessary mouse_enter/mouse_exit signals and the MOUSE_ENTER/MOUSE_EXIT notifications for every Viewport in the SceneTree. diff --git a/scene/main/viewport.h b/scene/main/viewport.h index a6a6e8ed44..63bec5b01c 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -488,6 +488,9 @@ private: void _process_dirty_canvas_parent_orders(); void _propagate_world_2d_changed(Node *p_node); + void _window_start_drag(Window *p_window); + void _window_start_resize(SubWindowResize p_edge, Window *p_window); + protected: bool _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 0d37447892..3476cb4cdc 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1998,6 +1998,54 @@ bool Window::has_focus() const { return focused; } +void Window::start_drag() { + ERR_MAIN_THREAD_GUARD; + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_start_drag(window_id); + } else if (embedder) { + embedder->_window_start_drag(this); + } +} + +void Window::start_resize(DisplayServer::WindowResizeEdge p_edge) { + ERR_MAIN_THREAD_GUARD; + if (get_flag(FLAG_RESIZE_DISABLED)) { + return; + } + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_start_resize(p_edge, window_id); + } else if (embedder) { + switch (p_edge) { + case DisplayServer::WINDOW_EDGE_TOP_LEFT: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_TOP_LEFT, this); + } break; + case DisplayServer::WINDOW_EDGE_TOP: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_TOP, this); + } break; + case DisplayServer::WINDOW_EDGE_TOP_RIGHT: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_TOP_RIGHT, this); + } break; + case DisplayServer::WINDOW_EDGE_LEFT: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_LEFT, this); + } break; + case DisplayServer::WINDOW_EDGE_RIGHT: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_RIGHT, this); + } break; + case DisplayServer::WINDOW_EDGE_BOTTOM_LEFT: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_BOTTOM_LEFT, this); + } break; + case DisplayServer::WINDOW_EDGE_BOTTOM: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_BOTTOM, this); + } break; + case DisplayServer::WINDOW_EDGE_BOTTOM_RIGHT: { + embedder->_window_start_resize(Viewport::SUB_WINDOW_RESIZE_BOTTOM_RIGHT, this); + } break; + default: + break; + } + } +} + Rect2i Window::get_usable_parent_rect() const { ERR_READ_THREAD_GUARD_V(Rect2i()); ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); @@ -2888,6 +2936,9 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("has_focus"), &Window::has_focus); ClassDB::bind_method(D_METHOD("grab_focus"), &Window::grab_focus); + ClassDB::bind_method(D_METHOD("start_drag"), &Window::start_drag); + ClassDB::bind_method(D_METHOD("start_resize", "edge"), &Window::start_resize); + ClassDB::bind_method(D_METHOD("set_ime_active", "active"), &Window::set_ime_active); ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &Window::set_ime_position); diff --git a/scene/main/window.h b/scene/main/window.h index 86b1d7c71a..ce5489e96b 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -401,6 +401,9 @@ public: void grab_focus(); bool has_focus() const; + void start_drag(); + void start_resize(DisplayServer::WindowResizeEdge p_edge); + Rect2i get_usable_parent_rect() const; // Internationalization.