From 80620076fc7650f09d2047b9c77071f304ee6097 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 15 Jun 2012 17:27:36 +0300 Subject: [PATCH] window: Implement animated cursors (using pointer surfaces) Since the introduction of pointer.set_cursor(), it is possible for a client to set the surface containing the pointer image and get frame callbacks on it thus allowing a clear implementation of animated cursors. This also makes the busy cursor hack of using frame callbacks on the busy surface unnecessary. --- clients/desktop-shell.c | 32 ---------------------- clients/window.c | 59 +++++++++++++++++++++++++++++++++++++---- clients/window.h | 3 --- 3 files changed, 54 insertions(+), 40 deletions(-) diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index 5a81b2ca..6c73a5c5 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -767,42 +767,10 @@ background_create(struct desktop *desktop) return background; } -static const struct wl_callback_listener busy_cursor_listener; - -static void -busy_cursor_frame_callback(void *data, - struct wl_callback *callback, uint32_t time) -{ - struct input *input = data; - struct display *display = input_get_display(input); - struct desktop *desktop = display_get_user_data(display); - struct wl_surface *surface; - int index; - - if (callback) - wl_callback_destroy(callback); - if (input_get_focus_widget(input) != desktop->busy_widget) - return; - - /* FIXME: Get frame duration and number of frames from cursor. */ - index = (time / 100) % 8; - input_set_pointer_image_index(input, CURSOR_WATCH, index); - - surface = window_get_wl_surface(desktop->busy_window); - callback = wl_surface_frame(surface); - wl_callback_add_listener(callback, &busy_cursor_listener, input); -} - -static const struct wl_callback_listener busy_cursor_listener = { - busy_cursor_frame_callback -}; - static int busy_surface_enter_handler(struct widget *widget, struct input *input, float x, float y, void *data) { - busy_cursor_frame_callback(input, NULL, 0); - return CURSOR_WATCH; } diff --git a/clients/window.c b/clients/window.c index 57443d91..436f8624 100644 --- a/clients/window.c +++ b/clients/window.c @@ -189,6 +189,8 @@ struct input { struct window *pointer_focus; struct window *keyboard_focus; int current_cursor; + uint32_t cursor_anim_start; + struct wl_callback *cursor_frame_cb; struct wl_surface *pointer_surface; uint32_t modifiers; uint32_t pointer_enter_serial; @@ -2274,14 +2276,14 @@ static const struct wl_data_device_listener data_device_listener = { data_device_selection }; -void -input_set_pointer_image_index(struct input *input, int pointer, int index) +static void +input_set_pointer_image_index(struct input *input, int index) { struct wl_buffer *buffer; struct wl_cursor *cursor; struct wl_cursor_image *image; - cursor = input->display->cursors[pointer]; + cursor = input->display->cursors[input->current_cursor]; if (!cursor) return; @@ -2295,7 +2297,6 @@ input_set_pointer_image_index(struct input *input, int pointer, int index) if (!buffer) return; - input->current_cursor = pointer; wl_pointer_set_cursor(input->pointer, input->display->serial, input->pointer_surface, image->hotspot_x, image->hotspot_y); @@ -2304,13 +2305,61 @@ input_set_pointer_image_index(struct input *input, int pointer, int index) image->width, image->height); } +static const struct wl_callback_listener pointer_surface_listener; + +static void +pointer_surface_frame_callback(void *data, struct wl_callback *callback, + uint32_t time) +{ + struct input *input = data; + struct wl_cursor *cursor = + input->display->cursors[input->current_cursor]; + int i; + + if (callback) { + assert(callback == input->cursor_frame_cb); + wl_callback_destroy(callback); + input->cursor_frame_cb = NULL; + } + + if (input->current_cursor == CURSOR_UNSET) + return; + + /* FIXME We don't have the current time on the first call so we set + * the animation start to the time of the first frame callback. */ + if (time == 0) + input->cursor_anim_start = 0; + else if (input->cursor_anim_start == 0) + input->cursor_anim_start = time; + + if (time == 0 || input->cursor_anim_start == 0) + i = 0; + else + i = wl_cursor_frame(cursor, time - input->cursor_anim_start); + + input_set_pointer_image_index(input, i); + + if (cursor->image_count == 1) + return; + + input->cursor_frame_cb = wl_surface_frame(input->pointer_surface); + wl_callback_add_listener(input->cursor_frame_cb, + &pointer_surface_listener, input); +} + +static const struct wl_callback_listener pointer_surface_listener = { + pointer_surface_frame_callback +}; + void input_set_pointer_image(struct input *input, int pointer) { if (pointer == input->current_cursor) return; - input_set_pointer_image_index(input, pointer, 0); + input->current_cursor = pointer; + if (!input->cursor_frame_cb) + pointer_surface_frame_callback(input, NULL, 0); } struct wl_data_device * diff --git a/clients/window.h b/clients/window.h index 8b8e8167..da3815bb 100644 --- a/clients/window.h +++ b/clients/window.h @@ -367,9 +367,6 @@ frame_create(struct window *window, void *data); void input_set_pointer_image(struct input *input, int pointer); -void -input_set_pointer_image_index(struct input *input, int pointer, int index); - void input_get_position(struct input *input, int32_t *x, int32_t *y);