[gtk+] wayland: Implement animatable cursors



commit b8ed3e9ef52bb45ff9a3836e50fd7b90936c2c97
Author: Chris Cummins <christopher e cummins intel com>
Date:   Thu Mar 28 12:08:43 2013 +0000

    wayland: Implement animatable cursors
    
    Cursor animations are handled on a per-device basis, with
    GdkWaylandDevice updating the pointer surface for each frame.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=696429

 gdk/wayland/gdkcursor-wayland.c  |   54 ++++++++++++++++++++++++-----
 gdk/wayland/gdkdevice-wayland.c  |   68 ++++++++++++++++++++++++++++++++-----
 gdk/wayland/gdkprivate-wayland.h |    8 +++-
 3 files changed, 108 insertions(+), 22 deletions(-)
---
diff --git a/gdk/wayland/gdkcursor-wayland.c b/gdk/wayland/gdkcursor-wayland.c
index 8873813..fc51473 100644
--- a/gdk/wayland/gdkcursor-wayland.c
+++ b/gdk/wayland/gdkcursor-wayland.c
@@ -182,6 +182,7 @@ gdk_wayland_cursor_get_image (GdkCursor *cursor)
 
 struct wl_buffer *
 _gdk_wayland_cursor_get_buffer (GdkCursor *cursor,
+                                guint      image_index,
                                 int       *x,
                                 int       *y,
                                 int       *w,
@@ -191,13 +192,25 @@ _gdk_wayland_cursor_get_buffer (GdkCursor *cursor,
 
   if (wayland_cursor->wl_cursor)
     {
-      *x = wayland_cursor->wl_cursor->images[0]->hotspot_x;
-      *y = wayland_cursor->wl_cursor->images[0]->hotspot_y;
+      struct wl_cursor_image *image;
 
-      *w = wayland_cursor->wl_cursor->images[0]->width;
-      *h = wayland_cursor->wl_cursor->images[0]->height;
+      if (image_index >= wayland_cursor->wl_cursor->image_count)
+        {
+          g_warning (G_STRLOC " out of bounds cursor image [%d / %d]",
+                     image_index,
+                     wayland_cursor->wl_cursor->image_count - 1);
+          image_index = 0;
+        }
 
-      return wl_cursor_image_get_buffer(wayland_cursor->wl_cursor->images[0]);
+      image = wayland_cursor->wl_cursor->images[image_index];
+
+      *x = image->hotspot_x;
+      *y = image->hotspot_y;
+
+      *w = image->width;
+      *h = image->height;
+
+      return wl_cursor_image_get_buffer (image);
     }
   else /* From pixbuf */
     {
@@ -211,6 +224,32 @@ _gdk_wayland_cursor_get_buffer (GdkCursor *cursor,
     }
 }
 
+guint
+_gdk_wayland_cursor_get_next_image_index (GdkCursor *cursor,
+                                          guint      current_image_index,
+                                          guint     *next_image_delay)
+{
+  struct wl_cursor *wl_cursor = GDK_WAYLAND_CURSOR (cursor)->wl_cursor;
+
+  if (wl_cursor && wl_cursor->image_count > 1)
+    {
+      if (current_image_index >= wl_cursor->image_count)
+        {
+          g_warning (G_STRLOC " out of bounds cursor image [%d / %d]",
+                     current_image_index, wl_cursor->image_count - 1);
+          current_image_index = 0;
+        }
+
+      /* Return the time to next image */
+      if (next_image_delay)
+        *next_image_delay = wl_cursor->images[current_image_index]->delay;
+
+      return (current_image_index + 1) % wl_cursor->image_count;
+    }
+  else
+    return current_image_index;
+}
+
 static void
 _gdk_wayland_cursor_class_init (GdkWaylandCursorClass *wayland_cursor_class)
 {
@@ -335,11 +374,6 @@ _gdk_wayland_display_get_cursor_for_name (GdkDisplay  *display,
   if (!set_cursor_from_theme (private, wayland_display->cursor_theme))
     return GDK_CURSOR (private);
 
-  /* TODO: Do something clever so we can do animated cursors - move the
-   * wl_pointer_set_cursor to a function here so that we can do the magic to
-   * iterate through
-   */
-
   add_to_cache (wayland_display, private);
 
   return GDK_CURSOR (private);
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 4c8caec..74dd5d5 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -71,6 +71,9 @@ struct _GdkWaylandDeviceData
   guint32 repeat_count;
   GSettings *keyboard_settings;
 
+  guint cursor_timeout_id;
+  guint cursor_image_index;
+
   DataOffer *drag_offer;
   DataOffer *selection_offer;
 
@@ -145,13 +148,62 @@ gdk_wayland_device_get_state (GdkDevice       *device,
 }
 
 static void
+gdk_wayland_device_stop_window_cursor_animation (GdkWaylandDeviceData *wd)
+{
+  if (wd->cursor_timeout_id > 0)
+    {
+      g_source_remove (wd->cursor_timeout_id);
+      wd->cursor_timeout_id = 0;
+    }
+  wd->cursor_image_index = 0;
+}
+
+static gboolean
+gdk_wayland_device_update_window_cursor (GdkWaylandDeviceData *wd)
+{
+  struct wl_buffer *buffer;
+  int x, y, w, h;
+  guint next_image_index, next_image_delay;
+
+  buffer = _gdk_wayland_cursor_get_buffer (wd->cursor, wd->cursor_image_index,
+                                           &x, &y, &w, &h);
+  wl_pointer_set_cursor (wd->wl_pointer,
+                         wd->enter_serial,
+                         wd->pointer_surface,
+                         x, y);
+  wl_surface_attach (wd->pointer_surface, buffer, 0, 0);
+  wl_surface_damage (wd->pointer_surface,  0, 0, w, h);
+  wl_surface_commit (wd->pointer_surface);
+
+  next_image_index =
+    _gdk_wayland_cursor_get_next_image_index (wd->cursor,
+                                              wd->cursor_image_index,
+                                              &next_image_delay);
+
+  if (next_image_index != wd->cursor_image_index)
+    {
+      guint id;
+
+      /* Queue timeout for next frame */
+      id = g_timeout_add (next_image_delay,
+                          (GSourceFunc)gdk_wayland_device_update_window_cursor,
+                          wd);
+
+      wd->cursor_timeout_id = id;
+      wd->cursor_image_index = next_image_index;
+    }
+  else
+    wd->cursor_timeout_id = 0;
+
+  return FALSE;
+}
+
+static void
 gdk_wayland_device_set_window_cursor (GdkDevice *device,
                                       GdkWindow *window,
                                       GdkCursor *cursor)
 {
   GdkWaylandDeviceData *wd = GDK_WAYLAND_DEVICE(device)->device;
-  struct wl_buffer *buffer;
-  int x, y, w, h;
 
   /* Setting the cursor to NULL means that we should use the default cursor */
   if (!cursor)
@@ -164,19 +216,14 @@ gdk_wayland_device_set_window_cursor (GdkDevice *device,
   if (cursor == wd->cursor)
     return;
 
+  gdk_wayland_device_stop_window_cursor_animation (wd);
+
   if (wd->cursor)
     g_object_unref (wd->cursor);
 
   wd->cursor = g_object_ref (cursor);
 
-  buffer = _gdk_wayland_cursor_get_buffer (wd->cursor, &x, &y, &w, &h);
-  wl_pointer_set_cursor (wd->wl_pointer,
-                         wd->enter_serial,
-                         wd->pointer_surface,
-                         x, y);
-  wl_surface_attach (wd->pointer_surface, buffer, 0, 0);
-  wl_surface_damage (wd->pointer_surface,  0, 0, w, h);
-  wl_surface_commit (wd->pointer_surface);
+  gdk_wayland_device_update_window_cursor (wd);
 }
 
 static void
@@ -622,6 +669,7 @@ pointer_handle_leave (void              *data,
   g_object_unref(device->pointer_focus);
   if (device->cursor)
     {
+      gdk_wayland_device_stop_window_cursor_animation (device);
       g_object_unref (device->cursor);
       device->cursor = NULL;
     }
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index 4dcc80c..8421043 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -78,10 +78,14 @@ gboolean   _gdk_wayland_display_supports_cursor_alpha (GdkDisplay *display);
 gboolean   _gdk_wayland_display_supports_cursor_color (GdkDisplay *display);
 
 struct wl_buffer *_gdk_wayland_cursor_get_buffer (GdkCursor *cursor,
-                                                 int       *x,
-                                                 int       *y,
+                                                  guint      image_index,
+                                                  int       *x,
+                                                  int       *y,
                                                   int       *w,
                                                   int       *h);
+guint      _gdk_wayland_cursor_get_next_image_index (GdkCursor *cursor,
+                                                     guint      current_image_index,
+                                                     guint     *next_image_delay);
 
 GdkDragProtocol _gdk_wayland_window_get_drag_protocol (GdkWindow *window,
                                                       GdkWindow **target);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]