From 98bfd77e3bf3de27f821c6c2426ae5cfc1c383ef Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Fri, 20 Jun 2025 16:29:48 +0200 Subject: [PATCH 1/3] xwayland: Rename window_output to surface_output No functional change, simply use a more generic name to make it clear that this does not apply solely to xwl_window. Signed-off-by: Olivier Fourdan --- hw/xwayland/xwayland-window.c | 32 ++++++++++++++++---------------- hw/xwayland/xwayland-window.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index b717fcf3c..70230db41 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -1064,22 +1064,22 @@ xwl_window_update_surface_scale(struct xwl_window *xwl_window) static void xwl_window_enter_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output) { - struct xwl_window_output *window_output; + struct xwl_surface_output *surface_output; - window_output = XNFcallocarray(1, sizeof(struct xwl_window_output)); - window_output->xwl_output = xwl_output; - xorg_list_add(&window_output->link, &xwl_window->xwl_output_list); + surface_output = XNFcallocarray(1, sizeof(struct xwl_surface_output)); + surface_output->xwl_output = xwl_output; + xorg_list_add(&surface_output->link, &xwl_window->xwl_output_list); } void xwl_window_leave_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output) { - struct xwl_window_output *window_output, *tmp; + struct xwl_surface_output *surface_output, *tmp; - xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) { - if (window_output->xwl_output == xwl_output) { - xorg_list_del(&window_output->link); - free(window_output); + xorg_list_for_each_entry_safe(surface_output, tmp, &xwl_window->xwl_output_list, link) { + if (surface_output->xwl_output == xwl_output) { + xorg_list_del(&surface_output->link); + free(surface_output); } } } @@ -1087,23 +1087,23 @@ xwl_window_leave_output(struct xwl_window *xwl_window, struct xwl_output *xwl_ou static void xwl_window_free_outputs(struct xwl_window *xwl_window) { - struct xwl_window_output *window_output, *tmp; + struct xwl_surface_output *surface_output, *tmp; - xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) { - xorg_list_del(&window_output->link); - free(window_output); + xorg_list_for_each_entry_safe(surface_output, tmp, &xwl_window->xwl_output_list, link) { + xorg_list_del(&surface_output->link); + free(surface_output); } } int xwl_window_get_max_output_scale(struct xwl_window *xwl_window) { - struct xwl_window_output *window_output; + struct xwl_surface_output *surface_output; struct xwl_output *xwl_output; int scale = 1; - xorg_list_for_each_entry(window_output, &xwl_window->xwl_output_list, link) { - xwl_output = window_output->xwl_output; + xorg_list_for_each_entry(surface_output, &xwl_window->xwl_output_list, link) { + xwl_output = surface_output->xwl_output; if (xwl_output->scale > scale) scale = xwl_output->scale; } diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index ba5c3a078..d20eb4bcc 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -52,7 +52,7 @@ struct xwl_wl_surface { struct xorg_list link; }; -struct xwl_window_output { +struct xwl_surface_output { struct xorg_list link; struct xwl_output *xwl_output; }; From 3d692112669bee39a35fcd7fc0267240640f66ba Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Mon, 23 Jun 2025 16:59:28 +0200 Subject: [PATCH 2/3] xwayland: Move the cursor update to its own function No functional change, this is preparation work for the next commit. Signed-off-by: Olivier Fourdan --- hw/xwayland/xwayland-cursor.c | 59 +++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c index be78f97e3..6f6d6111b 100644 --- a/hw/xwayland/xwayland-cursor.c +++ b/hw/xwayland/xwayland-cursor.c @@ -181,6 +181,26 @@ xwl_cursor_clear_frame_cb(struct xwl_cursor *xwl_cursor) return FALSE; } +static void +xwl_seat_set_pointer_surface(struct xwl_seat *xwl_seat) +{ + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; + struct xwl_cursor *xwl_cursor = &xwl_seat->cursor; + int xhot, yhot; + + if (!xwl_seat->x_cursor) + return; + + xhot = xwl_seat->x_cursor->bits->xhot / xwl_screen->global_surface_scale; + yhot = xwl_seat->x_cursor->bits->yhot / xwl_screen->global_surface_scale; + + wl_pointer_set_cursor(xwl_seat->wl_pointer, + xwl_seat->pointer_enter_serial, + xwl_cursor->surface, + xhot, + yhot); +} + void xwl_seat_set_cursor(struct xwl_seat *xwl_seat) { @@ -188,7 +208,6 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat) struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; PixmapPtr pixmap; CursorPtr cursor; - int xhot, yhot; if (!xwl_seat->wl_pointer) return; @@ -215,16 +234,30 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat) xwl_cursor_copy_bits_to_pixmap(cursor, pixmap); + xwl_seat_set_pointer_surface(xwl_seat); + + xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap); +} + +static void +xwl_tablet_tool_set_pointer_surface(struct xwl_tablet_tool *xwl_tablet_tool) +{ + struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; + int xhot, yhot; + + if (!xwl_seat->x_cursor) + return; + xhot = xwl_seat->x_cursor->bits->xhot / xwl_screen->global_surface_scale; yhot = xwl_seat->x_cursor->bits->yhot / xwl_screen->global_surface_scale; - wl_pointer_set_cursor(xwl_seat->wl_pointer, - xwl_seat->pointer_enter_serial, - xwl_cursor->surface, - xhot, - yhot); - - xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap); + zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, + xwl_tablet_tool->proximity_in_serial, + xwl_cursor->surface, + xhot, + yhot); } void @@ -235,7 +268,6 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor; PixmapPtr pixmap; CursorPtr cursor; - int xhot, yhot; if (!xwl_seat->x_cursor) { zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, @@ -260,14 +292,7 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) xwl_cursor_copy_bits_to_pixmap(cursor, pixmap); - xhot = xwl_seat->x_cursor->bits->xhot / xwl_screen->global_surface_scale; - yhot = xwl_seat->x_cursor->bits->yhot / xwl_screen->global_surface_scale; - - zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, - xwl_tablet_tool->proximity_in_serial, - xwl_cursor->surface, - xhot, - yhot); + xwl_tablet_tool_set_pointer_surface(xwl_tablet_tool); xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap); } From cac7647eabb2ad970aa41951548de8c988278d96 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Fri, 20 Jun 2025 16:34:57 +0200 Subject: [PATCH 3/3] xwayland: Track cursor surface scale separately Track and apply the cursor scale separately, and apply the output scale to the tablet cursors instead of using the global scale. Signed-off-by: Olivier Fourdan Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1824 --- hw/xwayland/xwayland-cursor.c | 122 +++++++++++++++++++++++++++++++--- hw/xwayland/xwayland-cursor.h | 5 +- hw/xwayland/xwayland-input.c | 9 +++ hw/xwayland/xwayland-input.h | 3 + 4 files changed, 128 insertions(+), 11 deletions(-) diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c index 6f6d6111b..10a28591b 100644 --- a/hw/xwayland/xwayland-cursor.c +++ b/hw/xwayland/xwayland-cursor.c @@ -244,14 +244,13 @@ xwl_tablet_tool_set_pointer_surface(struct xwl_tablet_tool *xwl_tablet_tool) { struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor; struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; - struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; int xhot, yhot; if (!xwl_seat->x_cursor) return; - xhot = xwl_seat->x_cursor->bits->xhot / xwl_screen->global_surface_scale; - yhot = xwl_seat->x_cursor->bits->yhot / xwl_screen->global_surface_scale; + xhot = xwl_seat->x_cursor->bits->xhot / xwl_cursor->surface_scale; + yhot = xwl_seat->x_cursor->bits->yhot / xwl_cursor->surface_scale; zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, xwl_tablet_tool->proximity_in_serial, @@ -297,13 +296,6 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap); } -void -xwl_cursor_release(struct xwl_cursor *xwl_cursor) -{ - wl_surface_destroy(xwl_cursor->surface); - xwl_cursor_clear_frame_cb(xwl_cursor); -} - static void xwl_seat_update_all_cursors(struct xwl_seat *xwl_seat) { @@ -320,6 +312,25 @@ xwl_seat_update_all_cursors(struct xwl_seat *xwl_seat) xwl_seat->pending_x_cursor = NULL; } +static void +xwl_cursor_free_outputs(struct xwl_cursor *xwl_cursor) +{ + struct xwl_surface_output *surface_output, *tmp; + + xorg_list_for_each_entry_safe(surface_output, tmp, &xwl_cursor->xwl_output_list, link) { + xorg_list_del(&surface_output->link); + free(surface_output); + } +} + +void +xwl_cursor_release(struct xwl_cursor *xwl_cursor) +{ + wl_surface_destroy(xwl_cursor->surface); + xwl_cursor_clear_frame_cb(xwl_cursor); + xwl_cursor_free_outputs(xwl_cursor); +} + static void xwl_seat_update_cursor_visibility(struct xwl_seat *xwl_seat) { @@ -463,3 +474,94 @@ xwl_screen_init_cursor(struct xwl_screen *xwl_screen) &xwl_pointer_sprite_funcs, &xwl_pointer_screen_funcs, TRUE); } + +static void +xwl_cursor_enter_output(struct xwl_cursor *xwl_cursor, struct xwl_output *xwl_output) +{ + struct xwl_surface_output *surface_output; + + surface_output = XNFcallocarray(1, sizeof(struct xwl_surface_output)); + surface_output->xwl_output = xwl_output; + xorg_list_add(&surface_output->link, &xwl_cursor->xwl_output_list); +} + +static void +xwl_cursor_leave_output(struct xwl_cursor *xwl_cursor, struct xwl_output *xwl_output) +{ + struct xwl_surface_output *surface_output, *tmp; + + xorg_list_for_each_entry_safe(surface_output, tmp, &xwl_cursor->xwl_output_list, link) { + if (surface_output->xwl_output == xwl_output) { + xorg_list_del(&surface_output->link); + free(surface_output); + } + } +} + +static int +xwl_cursor_get_max_output_scale(struct xwl_cursor *xwl_cursor) +{ + struct xwl_surface_output *surface_output; + struct xwl_output *xwl_output; + int scale = 1; + + xorg_list_for_each_entry(surface_output, &xwl_cursor->xwl_output_list, link) { + xwl_output = surface_output->xwl_output; + if (xwl_output->scale > scale) + scale = xwl_output->scale; + } + + return scale; +} + +static void +xwl_cursor_update_surface_scale(struct xwl_cursor *xwl_cursor) +{ + struct xwl_screen *xwl_screen = xwl_cursor->xwl_screen; + struct xwl_tablet_tool *xwl_tablet_tool; + struct xwl_seat *xwl_seat; + + xwl_cursor->surface_scale = xwl_cursor_get_max_output_scale(xwl_cursor); + + xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) { + if (&xwl_seat->cursor == xwl_cursor) + xwl_seat_set_pointer_surface(xwl_seat); + + xorg_list_for_each_entry(xwl_tablet_tool, &xwl_seat->tablet_tools, link) { + if (xwl_tablet_tool->proximity_in_serial == 0) + continue; + if (&xwl_tablet_tool->cursor == xwl_cursor) + xwl_tablet_tool_set_pointer_surface(xwl_tablet_tool); + } + } +} + +void +xwl_cursor_surface_enter(void *data, + struct wl_surface *wl_surface, + struct wl_output *wl_output) +{ + struct xwl_cursor *xwl_cursor = data; + struct xwl_screen *xwl_screen = xwl_cursor->xwl_screen; + struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output); + + if (xwl_output) { + xwl_cursor_enter_output(xwl_cursor, xwl_output); + xwl_cursor_update_surface_scale(xwl_cursor); + } +} + +void +xwl_cursor_surface_leave(void *data, + struct wl_surface *wl_surface, + struct wl_output *wl_output) +{ + struct xwl_cursor *xwl_cursor = data; + struct xwl_screen *xwl_screen = xwl_cursor->xwl_screen; + struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output); + + if (xwl_output) { + xwl_cursor_leave_output(xwl_cursor, xwl_output); + xwl_cursor_update_surface_scale(xwl_cursor); + } +} diff --git a/hw/xwayland/xwayland-cursor.h b/hw/xwayland/xwayland-cursor.h index 76b5b49b6..63790f5bc 100644 --- a/hw/xwayland/xwayland-cursor.h +++ b/hw/xwayland/xwayland-cursor.h @@ -36,5 +36,8 @@ void xwl_cursor_release(struct xwl_cursor *xwl_cursor); void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool); void xwl_seat_set_cursor(struct xwl_seat *xwl_seat); Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen); - +void xwl_cursor_surface_enter(void *data, + struct wl_surface *wl_surface, struct wl_output *wl_output); +void xwl_cursor_surface_leave(void *data, + struct wl_surface *wl_surface, struct wl_output *wl_output); #endif /* XWAYLAND_CURSOR_H */ diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 620778719..fe0f12d02 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -1934,14 +1934,23 @@ static const struct wl_seat_listener seat_listener = { seat_handle_name }; +static const struct wl_surface_listener surface_listener = { + xwl_cursor_surface_enter, + xwl_cursor_surface_leave +}; + static void xwl_cursor_init(struct xwl_cursor *xwl_cursor, struct xwl_screen *xwl_screen, void (* update_proc)(struct xwl_cursor *)) { + xwl_cursor->xwl_screen = xwl_screen; xwl_cursor->surface = wl_compositor_create_surface(xwl_screen->compositor); xwl_cursor->update_proc = update_proc; xwl_cursor->frame_cb = NULL; xwl_cursor->needs_update = FALSE; + xwl_cursor->surface_scale = 1; + xorg_list_init(&xwl_cursor->xwl_output_list); + wl_surface_add_listener(xwl_cursor->surface, &surface_listener, xwl_cursor); } static void diff --git a/hw/xwayland/xwayland-input.h b/hw/xwayland/xwayland-input.h index d40bca08a..c33fc399b 100644 --- a/hw/xwayland/xwayland-input.h +++ b/hw/xwayland/xwayland-input.h @@ -47,10 +47,13 @@ struct xwl_pointer_warp_emulator { }; struct xwl_cursor { + struct xwl_screen *xwl_screen; void (* update_proc) (struct xwl_cursor *); struct wl_surface *surface; struct wl_callback *frame_cb; + struct xorg_list xwl_output_list; Bool needs_update; + int surface_scale; }; struct xwl_seat {