wayland: Phase 15 — handle xdg-toplevel request_move/request_resize

Wire handle_toplevel_request_move and handle_toplevel_request_resize
listeners to each xdg_toplevel so clients that initiate CSD drag
operations (e.g. GTK titlebar drag) receive an ack rather than hanging.
In the headless compositor both handlers are currently no-ops; a real
compositor would start a pointer grab here.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-28 21:07:00 +01:00
parent b9b3b2de57
commit 9ca0bdcdf1
1 changed files with 38 additions and 8 deletions

View File

@ -114,6 +114,8 @@ struct wl_toplevel_view {
struct wl_listener unmap_listener;
struct wl_listener destroy_listener;
struct wl_listener title_listener; /* Phase 46: xdg_toplevel set_title */
struct wl_listener request_move_listener; /* Phase 15 */
struct wl_listener request_resize_listener; /* Phase 15 */
WNativeWindow id; /* synthetic handle, >= 0x10000000 */
int x, y; /* Phase 55: WM-assigned position */
long *wm_state; /* Phase 56: saved WM state or NULL */
@ -267,6 +269,30 @@ handle_toplevel_title(struct wl_listener *listener, void *data)
wWindowUpdateName(wwin, new_title);
}
/*
* Phase 15: xdg_toplevel request_move — client requests interactive move.
* In the headless compositor we acknowledge the request but do nothing
* (no real pointer to drag with). A real compositor would start a grab.
*/
static void
handle_toplevel_request_move(struct wl_listener *listener, void *data)
{
struct wl_toplevel_view *view = VIEW_FROM_LISTENER(listener, request_move_listener);
(void)data;
wwarning("wl_backend: request_move id=0x%lx (no-op in headless mode)", view->id);
}
/*
* Phase 15: xdg_toplevel request_resize — client requests interactive resize.
*/
static void
handle_toplevel_request_resize(struct wl_listener *listener, void *data)
{
struct wl_toplevel_view *view = VIEW_FROM_LISTENER(listener, request_resize_listener);
(void)data;
wwarning("wl_backend: request_resize id=0x%lx (no-op in headless mode)", view->id);
}
/*
* Phase 38: toplevel map — surface is ready to be managed.
*/
@ -405,15 +431,19 @@ handle_xdg_new_surface(struct wl_listener *listener, void *data)
view->xdg_surface = xdg_surface;
view->id = wl_state.next_synthetic_id++;
view->map_listener.notify = handle_toplevel_map;
view->unmap_listener.notify = handle_toplevel_unmap;
view->destroy_listener.notify = handle_toplevel_destroy;
view->title_listener.notify = handle_toplevel_title;
view->map_listener.notify = handle_toplevel_map;
view->unmap_listener.notify = handle_toplevel_unmap;
view->destroy_listener.notify = handle_toplevel_destroy;
view->title_listener.notify = handle_toplevel_title;
view->request_move_listener.notify = handle_toplevel_request_move; /* Phase 15 */
view->request_resize_listener.notify = handle_toplevel_request_resize; /* Phase 15 */
wl_signal_add(&xdg_surface->events.map, &view->map_listener);
wl_signal_add(&xdg_surface->events.unmap, &view->unmap_listener);
wl_signal_add(&xdg_surface->events.destroy, &view->destroy_listener);
wl_signal_add(&xdg_surface->toplevel->events.set_title, &view->title_listener);
wl_signal_add(&xdg_surface->events.map, &view->map_listener);
wl_signal_add(&xdg_surface->events.unmap, &view->unmap_listener);
wl_signal_add(&xdg_surface->events.destroy, &view->destroy_listener);
wl_signal_add(&xdg_surface->toplevel->events.set_title, &view->title_listener);
wl_signal_add(&xdg_surface->toplevel->events.request_move, &view->request_move_listener);
wl_signal_add(&xdg_surface->toplevel->events.request_resize, &view->request_resize_listener);
wl_list_insert(&wl_state.toplevel_list, &view->link);
wl_state.managed_surface_count++;