<div dir="ltr">Does toytoolkit really need to support animated cursors?<div><br></div><div>If so it would be nice to animate the normal cursor, too, and perhaps demonstrate code reuse for this.</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Feb 2, 2016 at 9:28 PM, Peter Hutterer <span dir="ltr"><<a href="mailto:peter.hutterer@who-t.net" target="_blank">peter.hutterer@who-t.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Stephen Chandler Paul <<a href="mailto:thatslyude@gmail.com">thatslyude@gmail.com</a>><br>
<br>
Again, a lot of this is code that has been reused from the cursor code<br>
for pointers.<br>
<br>
Co-authored-by: Peter Hutterer <<a href="mailto:peter.hutterer@who-t.net">peter.hutterer@who-t.net</a>><br>
Signed-off-by: Stephen Chandler Paul <<a href="mailto:thatslyude@gmail.com">thatslyude@gmail.com</a>><br>
Signed-off-by: Peter Hutterer <<a href="mailto:peter.hutterer@who-t.net">peter.hutterer@who-t.net</a>><br>
---<br>
 clients/window.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-<br>
 clients/window.h |  13 ++++--<br>
 2 files changed, 145 insertions(+), 6 deletions(-)<br>
<br>
diff --git a/clients/window.c b/clients/window.c<br>
index 37c703b..26c2593 100644<br>
--- a/clients/window.c<br>
+++ b/clients/window.c<br>
@@ -159,6 +159,12 @@ struct tablet_tool {<br>
        struct tablet *current_tablet;<br>
        struct window *focus;<br>
        struct widget *focus_widget;<br>
+       uint32_t enter_serial;<br>
+       uint32_t cursor_serial;<br>
+       int current_cursor;<br>
+       struct wl_surface *cursor_surface;<br>
+       uint32_t cursor_anim_start;<br>
+       struct wl_callback *cursor_frame_cb;<br>
<br>
        enum zwp_tablet_tool_v1_type type;<br>
        uint64_t serial;<br>
@@ -332,6 +338,7 @@ struct widget {<br>
        int opaque;<br>
        int tooltip_count;<br>
        int default_cursor;<br>
+       int default_tablet_cursor;<br>
        /* If this is set to false then no cairo surface will be<br>
         * created before redrawing the surface. This is useful if the<br>
         * redraw handler is going to do completely custom rendering<br>
@@ -1676,6 +1683,7 @@ widget_create(struct window *window, struct surface *surface, void *data)<br>
        widget->tooltip = NULL;<br>
        widget->tooltip_count = 0;<br>
        widget->default_cursor = CURSOR_LEFT_PTR;<br>
+       widget->default_tablet_cursor = CURSOR_LEFT_PTR;<br>
        widget->use_cairo = 1;<br>
<br>
        return widget;<br>
@@ -1734,6 +1742,12 @@ widget_set_default_cursor(struct widget *widget, int cursor)<br>
 }<br>
<br>
 void<br>
+widget_set_default_tablet_cursor(struct widget *widget, int cursor)<br>
+{<br>
+       widget->default_tablet_cursor = cursor;<br>
+}<br>
+<br>
+void<br>
 widget_get_allocation(struct widget *widget, struct rectangle *allocation)<br>
 {<br>
        *allocation = widget->allocation;<br>
@@ -5667,6 +5681,117 @@ tablet_tool_handle_removed(void *data, struct zwp_tablet_tool_v1 *zwp_tablet_too<br>
        zwp_tablet_tool_v1_destroy(zwp_tablet_tool_v1);<br>
 }<br>
<br>
+static const struct wl_callback_listener tablet_tool_cursor_surface_listener;<br>
+<br>
+static void<br>
+tablet_tool_set_cursor_image_index(struct tablet_tool *tool, int index)<br>
+{<br>
+       struct wl_buffer *buffer;<br>
+       struct wl_cursor *cursor;<br>
+       struct wl_cursor_image *image;<br>
+<br>
+       cursor = tool->input->display->cursors[tool->current_cursor];<br>
+       if (index >= (int)cursor->image_count) {<br>
+               fprintf(stderr, "cursor index out of range\n");<br>
+               return;<br>
+       }<br>
+<br>
+       image = cursor->images[index];<br>
+       buffer = wl_cursor_image_get_buffer(image);<br>
+       if (!buffer)<br>
+               return;<br>
+<br>
+       wl_surface_attach(tool->cursor_surface, buffer, 0, 0);<br>
+       wl_surface_damage(tool->cursor_surface, 0, 0,<br>
+                         image->width, image->height);<br>
+       wl_surface_commit(tool->cursor_surface);<br>
+       zwp_tablet_tool_v1_set_cursor(tool->tool, tool->enter_serial,<br>
+                                     tool->cursor_surface,<br>
+                                     image->hotspot_x, image->hotspot_y);<br>
+}<br>
+<br>
+static void<br>
+tablet_tool_surface_frame_callback(void *data, struct wl_callback *callback,<br>
+                                  uint32_t time)<br>
+{<br>
+       struct tablet_tool *tool = data;<br>
+       struct wl_cursor *cursor;<br>
+       int i;<br>
+<br>
+       if (callback) {<br>
+               assert(callback == tool->cursor_frame_cb);<br>
+               wl_callback_destroy(callback);<br>
+               tool->cursor_frame_cb = NULL;<br>
+       }<br>
+<br>
+       if (tool->current_cursor == CURSOR_BLANK) {<br>
+               zwp_tablet_tool_v1_set_cursor(tool->tool, tool->enter_serial,<br>
+                                             NULL, 0, 0);<br>
+               return;<br>
+       }<br>
+<br>
+       if (tool->current_cursor == CURSOR_UNSET)<br>
+               return;<br>
+<br>
+       cursor = tool->input->display->cursors[tool->current_cursor];<br>
+       if (!cursor)<br>
+               return;<br>
+<br>
+       /* FIXME We don't have the current time on the first call so we set<br>
+        * the animation start to the time of the first frame callback. */<br>
+       if (time == 0)<br>
+               tool->cursor_anim_start = 0;<br>
+       else if (tool->cursor_anim_start == 0)<br>
+               tool->cursor_anim_start = time;<br>
+<br>
+       if (time == 0 || tool->cursor_anim_start == 0)<br>
+               i = 0;<br>
+       else<br>
+               i = wl_cursor_frame(cursor, time - tool->cursor_anim_start);<br>
+<br>
+       if (cursor->image_count > 1) {<br>
+               tool->cursor_frame_cb =<br>
+                       wl_surface_frame(tool->cursor_surface);<br>
+               wl_callback_add_listener(tool->cursor_frame_cb,<br>
+                                        &tablet_tool_cursor_surface_listener,<br>
+                                        tool);<br>
+       }<br>
+<br>
+       tablet_tool_set_cursor_image_index(tool, i);<br>
+}<br>
+<br>
+static const struct wl_callback_listener tablet_tool_cursor_surface_listener =  {<br>
+       tablet_tool_surface_frame_callback,<br>
+};<br>
+<br>
+void<br>
+tablet_tool_set_cursor_image(struct tablet_tool *tool, int cursor)<br>
+{<br>
+       bool force = false;<br>
+<br>
+       if (tool->enter_serial > tool->cursor_serial)<br>
+               force = true;<br>
+<br>
+       if (!force && cursor == tool->current_cursor)<br>
+               return;<br>
+<br>
+       tool->current_cursor = cursor;<br>
+       tool->cursor_serial = tool->enter_serial;<br>
+<br>
+       if (!tool->cursor_frame_cb) {<br>
+               tablet_tool_surface_frame_callback(tool, NULL, 0);<br>
+       } else if (force) {<br>
+               /* The current frame callback may be stuck if, for instance,<br>
+                * the set cursor request was processed by the server after<br>
+                * this client lost the focus. In this case the cursor surface<br>
+                * might not be mapped and the frame callback wouldn't ever<br>
+                * complete. Send a set_cursor and attach to try to map the<br>
+                * cursor surface again so that the callback will finish<br>
+                */<br>
+               tablet_tool_set_cursor_image_index(tool, 0);<br>
+       }<br>
+}<br>
+<br>
 static void<br>
 tablet_tool_set_focus_widget(struct tablet_tool *tool, struct window *window,<br>
                             wl_fixed_t sx, wl_fixed_t sy)<br>
@@ -5707,6 +5832,7 @@ tablet_tool_handle_proximity_in(void *data,<br>
<br>
        tool->focus = window;<br>
        tool->current_tablet = tablet;<br>
+       tool->enter_serial = serial;<br>
 }<br>
<br>
 static void<br>
@@ -5751,6 +5877,7 @@ tablet_tool_handle_motion(void *data, struct zwp_tablet_tool_v1 *zwp_tablet_tool<br>
        double sy = wl_fixed_to_double(y);<br>
        struct window *window = tool->focus;<br>
        struct widget *widget;<br>
+       int cursor;<br>
<br>
        if (!window)<br>
                return;<br>
@@ -5765,9 +5892,14 @@ tablet_tool_handle_motion(void *data, struct zwp_tablet_tool_v1 *zwp_tablet_tool<br>
        tablet_tool_set_focus_widget(tool, window, sx, sy);<br>
        widget = tool->focus_widget;<br>
        if (widget && widget->tablet_tool_motion_handler) {<br>
-               widget->tablet_tool_motion_handler(widget, tool, sx, sy,<br>
-                                                  widget->user_data);<br>
+               cursor = widget->tablet_tool_motion_handler(widget, tool,<br>
+                                                           sx, sy,<br>
+                                                           widget->user_data);<br>
+       } else {<br>
+               cursor = widget->default_tablet_cursor;<br>
        }<br>
+<br>
+       tablet_tool_set_cursor_image(tool, cursor);<br>
 }<br>
<br>
 static void<br>
@@ -5908,6 +6040,8 @@ tablet_tool_added(void *data, struct zwp_tablet_seat_v1 *zwp_tablet_seat1,<br>
<br>
        tool->tool = id;<br>
        tool->input = input;<br>
+       tool->cursor_surface =<br>
+               wl_compositor_create_surface(input->display->compositor);<br>
 }<br>
<br>
 static const struct zwp_tablet_seat_v1_listener tablet_seat_listener = {<br>
diff --git a/clients/window.h b/clients/window.h<br>
index 86f0366..903abf0 100644<br>
--- a/clients/window.h<br>
+++ b/clients/window.h<br>
@@ -275,10 +275,10 @@ typedef void (*widget_axis_handler_t)(struct widget *widget,<br>
                                      uint32_t axis,<br>
                                      wl_fixed_t value,<br>
                                      void *data);<br>
-typedef void (*widget_tablet_tool_motion_handler_t)(struct widget *widget,<br>
-                                                   struct tablet_tool *tool,<br>
-                                                   float x, float y,<br>
-                                                   void *data);<br>
+typedef int (*widget_tablet_tool_motion_handler_t)(struct widget *widget,<br>
+                                                  struct tablet_tool *tool,<br>
+                                                  float x, float y,<br>
+                                                  void *data);<br>
 typedef void (*widget_tablet_tool_down_handler_t)(struct widget *widget,<br>
                                                  struct tablet_tool *tool,<br>
                                                  void *data);<br>
@@ -533,6 +533,8 @@ widget_destroy(struct widget *widget);<br>
 void<br>
 widget_set_default_cursor(struct widget *widget, int cursor);<br>
 void<br>
+widget_set_default_tablet_cursor(struct widget *widget, int cursor);<br>
+void<br>
 widget_get_allocation(struct widget *widget, struct rectangle *allocation);<br>
<br>
 void<br>
@@ -750,4 +752,7 @@ tablet_tool_get_serial(struct tablet_tool *tool);<br>
 uint64_t<br>
 tablet_tool_get_hwid(struct tablet_tool *tool);<br>
<br>
+void<br>
+tablet_tool_set_cursor_image(struct tablet_tool *tool, int cursor);<br>
+<br>
 #endif<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.5.0<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" rel="noreferrer" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br></div>