Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Window] Expose start_drag and start_resize methods (for both native and embedded windows). #101221

Merged
merged 1 commit into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions doc/classes/Window.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
8 changes: 8 additions & 0 deletions platform/linuxbsd/x11/display_server_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
Comment on lines +5499 to +5501
Copy link
Contributor

@Sauermann Sauermann Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested the following:

Suggested change
if (wd.embed_parent) {
return; // Embedded window.
}
Window target = wd.embed_parent ? wd.embed_parent : wd.x11_window;

I also replaced wd.x11_window by target in the two locations below.

This approach works for me on linux and allows dragging/resizing the embedder window

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should work, but I'm not sure if dragging editor embedded window should be supported, it will have editor frame anyway and other window movement methods (like window_set_position/window_set_screen) are fully disabled.


XClientMessageEvent m;
memset(&m, 0, sizeof(m));

Expand Down Expand Up @@ -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));

Expand Down
8 changes: 8 additions & 0 deletions platform/windows/display_server_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
41 changes: 41 additions & 0 deletions scene/main/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2956,6 +2956,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.
Expand Down
3 changes: 3 additions & 0 deletions scene/main/viewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
51 changes: 51 additions & 0 deletions scene/main/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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);

Expand Down
3 changes: 3 additions & 0 deletions scene/main/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down