window: Implement animated cursors (using pointer surfaces)
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Fri, 15 Jun 2012 14:27:36 +0000 (17:27 +0300)
committerKristian Høgsberg <krh@bitplanet.net>
Fri, 15 Jun 2012 15:03:12 +0000 (11:03 -0400)
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
clients/window.c
clients/window.h

index 5a81b2c..6c73a5c 100644 (file)
@@ -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;
 }
 
index 57443d9..436f862 100644 (file)
@@ -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 *
index 8b8e816..da3815b 100644 (file)
@@ -368,9 +368,6 @@ 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);
 
 #define MOD_SHIFT_MASK         0x01