From 992ee045f1b59c037165ecdd752c2f2d78f16ee4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 7 Feb 2021 11:32:46 +0100 Subject: [PATCH] clients/window: atomically update pointer cursor Currently, Weston clients update the pointer cursor by first issuing a wl_surface.commit request to update the buffer, then a wl_pointer.set_cursor request to update the hotspot. This causes an issue because buffer and hotspot aren't updated atomically: in-between the two requests, the buffer is new but the hotspot is old. To fix this issue, create a new surface each time the cursor is updated. Signed-off-by: Simon Ser --- clients/window.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/clients/window.c b/clients/window.c index ca7e62d0..49574b57 100644 --- a/clients/window.c +++ b/clients/window.c @@ -3785,6 +3785,8 @@ input_set_pointer_image_index(struct input *input, int index) struct wl_buffer *buffer; struct wl_cursor *cursor; struct wl_cursor_image *image; + struct wl_surface *prev_surface; + struct display *d = input->display; if (!input->pointer) return; @@ -3803,6 +3805,11 @@ input_set_pointer_image_index(struct input *input, int index) if (!buffer) return; + /* Don't re-use the previous surface, otherwise the new buffer and the + * new hotspot aren't applied atomically. */ + prev_surface = input->pointer_surface; + input->pointer_surface = wl_compositor_create_surface(d->compositor); + wl_surface_attach(input->pointer_surface, buffer, 0, 0); wl_surface_damage(input->pointer_surface, 0, 0, image->width, image->height); @@ -3810,6 +3817,9 @@ input_set_pointer_image_index(struct input *input, int index) wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial, input->pointer_surface, image->hotspot_x, image->hotspot_y); + + if (prev_surface) + wl_surface_destroy(prev_surface); } static const struct wl_callback_listener pointer_surface_listener; @@ -3914,11 +3924,11 @@ pointer_surface_frame_callback(void *data, struct wl_callback *callback, time - input->cursor_anim_start, &duration); + input_set_pointer_image_index(input, i); + if (cursor->image_count > 1) schedule_pointer_image_update(input, cursor, duration, force_frame); - - input_set_pointer_image_index(input, i); } static void @@ -5899,8 +5909,6 @@ display_add_input(struct display *d, uint32_t id, int display_seat_version) input); } - input->pointer_surface = wl_compositor_create_surface(d->compositor); - toytimer_init(&input->cursor_timer, CLOCK_MONOTONIC, d, cursor_timer_func); @@ -5968,7 +5976,8 @@ input_destroy(struct input *input) fini_xkb(input); - wl_surface_destroy(input->pointer_surface); + if (input->pointer_surface) + wl_surface_destroy(input->pointer_surface); wl_list_remove(&input->link); wl_seat_destroy(input->seat);