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 <contact@emersion.fr>
dev
Simon Ser 4 years ago committed by Daniel Stone
parent 7514bf7e45
commit 992ee045f1
  1. 19
      clients/window.c

@ -3785,6 +3785,8 @@ input_set_pointer_image_index(struct input *input, int index)
struct wl_buffer *buffer; struct wl_buffer *buffer;
struct wl_cursor *cursor; struct wl_cursor *cursor;
struct wl_cursor_image *image; struct wl_cursor_image *image;
struct wl_surface *prev_surface;
struct display *d = input->display;
if (!input->pointer) if (!input->pointer)
return; return;
@ -3803,6 +3805,11 @@ input_set_pointer_image_index(struct input *input, int index)
if (!buffer) if (!buffer)
return; 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_attach(input->pointer_surface, buffer, 0, 0);
wl_surface_damage(input->pointer_surface, 0, 0, wl_surface_damage(input->pointer_surface, 0, 0,
image->width, image->height); 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, wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
input->pointer_surface, input->pointer_surface,
image->hotspot_x, image->hotspot_y); image->hotspot_x, image->hotspot_y);
if (prev_surface)
wl_surface_destroy(prev_surface);
} }
static const struct wl_callback_listener pointer_surface_listener; 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, time - input->cursor_anim_start,
&duration); &duration);
input_set_pointer_image_index(input, i);
if (cursor->image_count > 1) if (cursor->image_count > 1)
schedule_pointer_image_update(input, cursor, duration, schedule_pointer_image_update(input, cursor, duration,
force_frame); force_frame);
input_set_pointer_image_index(input, i);
} }
static void static void
@ -5899,8 +5909,6 @@ display_add_input(struct display *d, uint32_t id, int display_seat_version)
input); input);
} }
input->pointer_surface = wl_compositor_create_surface(d->compositor);
toytimer_init(&input->cursor_timer, CLOCK_MONOTONIC, d, toytimer_init(&input->cursor_timer, CLOCK_MONOTONIC, d,
cursor_timer_func); cursor_timer_func);
@ -5968,7 +5976,8 @@ input_destroy(struct input *input)
fini_xkb(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_list_remove(&input->link);
wl_seat_destroy(input->seat); wl_seat_destroy(input->seat);

Loading…
Cancel
Save