Merge pull request #101221 from bruvzg/win_dec_exp

[Window] Expose `start_drag` and `start_resize` methods (for both native and embedded windows).
This commit is contained in:
Rémi Verschelde 2025-01-09 11:17:24 +01:00
commit 65cf7c1d5e
7 changed files with 127 additions and 0 deletions

View file

@ -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]).
</description>
</method>
<method name="start_drag">
<return type="void" />
<description>
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.
</description>
</method>
<method name="start_resize">
<return type="void" />
<param index="0" name="edge" type="int" enum="DisplayServer.WindowResizeEdge" />
<description>
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.
</description>
</method>
</methods>
<members>
<member name="always_on_top" type="bool" setter="set_flag" getter="get_flag" default="false">

View file

@ -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));

View file

@ -3991,6 +3991,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;
@ -4007,6 +4011,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;

View file

@ -2947,6 +2947,47 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &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.

View file

@ -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);

View file

@ -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);

View file

@ -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.