From 8d911b25542a76da1b81dfe8f0d464e39df2aed6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?=
<7645683+bruvzg@users.noreply.github.com>
Date: Tue, 7 Jan 2025 14:11:45 +0200
Subject: [PATCH] [Window] Expose `start_drag` and `start_resize` methods (for
both native and embedded windows).
---
doc/classes/Window.xml | 13 +++++
platform/linuxbsd/x11/display_server_x11.cpp | 8 +++
platform/windows/display_server_windows.cpp | 8 +++
scene/main/viewport.cpp | 41 ++++++++++++++++
scene/main/viewport.h | 3 ++
scene/main/window.cpp | 51 ++++++++++++++++++++
scene/main/window.h | 3 ++
7 files changed, 127 insertions(+)
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 193dbe6a107c..90eba0bdea85 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 8a33e10cbe22..77f08095b1ca 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 c053408ed4c0..0c331725bdcd 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 6a898bd5ca2b..6043006786b8 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 a6a6e8ed4464..63bec5b01c37 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -488,6 +488,9 @@ class Viewport : public Node {
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 0d3744789271..3476cb4cdc54 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 86b1d7c71ac2..ce5489e96b16 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -401,6 +401,9 @@ class Window : public Viewport {
void grab_focus();
bool has_focus() const;
+ void start_drag();
+ void start_resize(DisplayServer::WindowResizeEdge p_edge);
+
Rect2i get_usable_parent_rect() const;
// Internationalization.