Merge branch 'xwayland-cursor-scale' into 'master'

Draft: xwayland: Track and apply output scales for tablet cursors

Closes #1824

See merge request xorg/xserver!2033
This commit is contained in:
Olivier Fourdan 2025-12-15 15:48:14 +01:00
commit 1247821301
6 changed files with 185 additions and 43 deletions

View file

@ -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,18 +234,31 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
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;
wl_pointer_set_cursor(xwl_seat->wl_pointer,
xwl_seat->pointer_enter_serial,
xwl_cursor->surface,
xhot,
yhot);
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;
int xhot, yhot;
if (!xwl_seat->x_cursor)
return;
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,
xwl_cursor->surface,
xhot,
yhot);
}
void
xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
{
@ -235,7 +267,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,25 +291,11 @@ 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);
}
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)
{
@ -295,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)
{
@ -438,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);
}
}

View file

@ -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 */

View file

@ -1938,14 +1938,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

View file

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

View file

@ -1087,22 +1087,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);
}
}
}
@ -1110,23 +1110,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;
}

View file

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