diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 6d8eaeda19c..7cd1e3b9171 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1836,7 +1836,7 @@ Starts a drag operation on the window with the given [param window_id], 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. - [b]Note:[/b] This method is implemented only on macOS. + [b]Note:[/b] This method is implemented on Linux(X11/Wayland), macOS, and Windows. diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index e321e4d4b94..bae1cfd444e 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -986,6 +986,12 @@ DisplayServer::VSyncMode DisplayServerWayland::window_get_vsync_mode(DisplayServ return DisplayServer::VSYNC_ENABLED; } +void DisplayServerWayland::window_start_drag(WindowID p_window) { + MutexLock mutex_lock(wayland_thread.mutex); + + wayland_thread.window_start_drag(p_window); +} + void DisplayServerWayland::cursor_set_shape(CursorShape p_shape) { ERR_FAIL_INDEX(p_shape, CURSOR_MAX); diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index d6f51b4a7e9..5046097d7ce 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -272,6 +272,8 @@ public: virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window_id = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_window_id) const override; + virtual void window_start_drag(WindowID p_window = MAIN_WINDOW_ID) override; + virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; virtual void cursor_set_custom_image(const Ref &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) override; diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index 1130472e947..11a8c6adad8 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -3338,6 +3338,22 @@ void WaylandThread::beep() const { } } +void WaylandThread::window_start_drag(DisplayServer::WindowID p_window_id) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss && ws.xdg_toplevel) { + xdg_toplevel_move(ws.xdg_toplevel, ss->wl_seat, ss->pointer_data.button_serial); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_move(ws.libdecor_frame, ss->wl_seat, ss->pointer_data.button_serial); + } +#endif +} + void WaylandThread::window_set_max_size(DisplayServer::WindowID p_window_id, const Size2i &p_size) { // TODO: Use window IDs for multiwindow support. WindowState &ws = main_window; diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h index 8f1605b8202..1996e0e359d 100644 --- a/platform/linuxbsd/wayland/wayland_thread.h +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -971,6 +971,8 @@ public: // Optional - requires xdg_activation_v1 void window_request_attention(DisplayServer::WindowID p_window_id); + void window_start_drag(DisplayServer::WindowID p_window_id); + // Optional - require idle_inhibit_unstable_v1 void window_set_idle_inhibition(DisplayServer::WindowID p_window_id, bool p_enable); bool window_get_idle_inhibition(DisplayServer::WindowID p_window_id) const; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index be66ea30ae3..f8716c6f34c 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -69,6 +69,8 @@ #define _NET_WM_STATE_REMOVE 0L // remove/unset property #define _NET_WM_STATE_ADD 1L // add/set property +#define _NET_WM_MOVERESIZE_MOVE 8L + // 2.2 is the first release with multitouch #define XINPUT_CLIENT_VERSION_MAJOR 2 #define XINPUT_CLIENT_VERSION_MINOR 2 @@ -5422,6 +5424,40 @@ DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_wind return DisplayServer::VSYNC_ENABLED; } +void DisplayServerX11::window_start_drag(WindowID p_window) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + + XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + + XUngrabPointer(x11_display, CurrentTime); + + Window root_return, child_return; + int root_x, root_y, win_x, win_y; + unsigned int mask_return; + + Bool xquerypointer_result = XQueryPointer(x11_display, wd.x11_window, &root_return, &child_return, &root_x, &root_y, &win_x, &win_y, &mask_return); + + m.type = ClientMessage; + m.window = wd.x11_window; + m.message_type = XInternAtom(x11_display, "_NET_WM_MOVERESIZE", True); + m.format = 32; + if (xquerypointer_result) { + m.data.l[0] = root_x; + m.data.l[1] = root_y; + m.data.l[3] = Button1; + } + m.data.l[2] = _NET_WM_MOVERESIZE_MOVE; + m.data.l[4] = 1; // Source - normal application. + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&m); + + XSync(x11_display, 0); +} + Vector DisplayServerX11::get_rendering_drivers_func() { Vector drivers; diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 31e4d548b9a..cbb29182d66 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -512,6 +512,8 @@ public: virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual void window_start_drag(WindowID p_window = MAIN_WINDOW_ID) override; + virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; virtual void cursor_set_custom_image(const Ref &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) override; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 2fa0ad8effd..60b72cdbce0 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3803,6 +3803,21 @@ DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_ return DisplayServer::VSYNC_ENABLED; } +void DisplayServerWindows::window_start_drag(WindowID p_window) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + + ReleaseCapture(); + + POINT coords; + GetCursorPos(&coords); + ScreenToClient(wd.hWnd, &coords); + + SendMessage(wd.hWnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(coords.x, coords.y)); +} + void DisplayServerWindows::set_context(Context p_context) { } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 2ee6bd2e730..579a23eb0e1 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -805,6 +805,8 @@ public: virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual void window_start_drag(WindowID p_window = MAIN_WINDOW_ID) override; + virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; virtual void cursor_set_custom_image(const Ref &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;