On Wed, Feb 03, 2016 at 03:28:11PM +1000, Peter Hutterer wrote:
> From: Stephen Chandler Paul <[email protected]>
> 
> Again, a lot of this is code that has been reused from the cursor code
> for pointers.
> 
> Co-authored-by: Peter Hutterer <[email protected]>
> Signed-off-by: Stephen Chandler Paul <[email protected]>
> Signed-off-by: Peter Hutterer <[email protected]>

Reviewed-by: Jonas Ådahl <[email protected]>

> ---
>  clients/window.c | 138 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  clients/window.h |  13 ++++--
>  2 files changed, 145 insertions(+), 6 deletions(-)
> 
> diff --git a/clients/window.c b/clients/window.c
> index 37c703b..26c2593 100644
> --- a/clients/window.c
> +++ b/clients/window.c
> @@ -159,6 +159,12 @@ struct tablet_tool {
>       struct tablet *current_tablet;
>       struct window *focus;
>       struct widget *focus_widget;
> +     uint32_t enter_serial;
> +     uint32_t cursor_serial;
> +     int current_cursor;
> +     struct wl_surface *cursor_surface;
> +     uint32_t cursor_anim_start;
> +     struct wl_callback *cursor_frame_cb;
>  
>       enum zwp_tablet_tool_v1_type type;
>       uint64_t serial;
> @@ -332,6 +338,7 @@ struct widget {
>       int opaque;
>       int tooltip_count;
>       int default_cursor;
> +     int default_tablet_cursor;
>       /* If this is set to false then no cairo surface will be
>        * created before redrawing the surface. This is useful if the
>        * redraw handler is going to do completely custom rendering
> @@ -1676,6 +1683,7 @@ widget_create(struct window *window, struct surface 
> *surface, void *data)
>       widget->tooltip = NULL;
>       widget->tooltip_count = 0;
>       widget->default_cursor = CURSOR_LEFT_PTR;
> +     widget->default_tablet_cursor = CURSOR_LEFT_PTR;
>       widget->use_cairo = 1;
>  
>       return widget;
> @@ -1734,6 +1742,12 @@ widget_set_default_cursor(struct widget *widget, int 
> cursor)
>  }
>  
>  void
> +widget_set_default_tablet_cursor(struct widget *widget, int cursor)
> +{
> +     widget->default_tablet_cursor = cursor;
> +}
> +
> +void
>  widget_get_allocation(struct widget *widget, struct rectangle *allocation)
>  {
>       *allocation = widget->allocation;
> @@ -5667,6 +5681,117 @@ tablet_tool_handle_removed(void *data, struct 
> zwp_tablet_tool_v1 *zwp_tablet_too
>       zwp_tablet_tool_v1_destroy(zwp_tablet_tool_v1);
>  }
>  
> +static const struct wl_callback_listener tablet_tool_cursor_surface_listener;
> +
> +static void
> +tablet_tool_set_cursor_image_index(struct tablet_tool *tool, int index)
> +{
> +     struct wl_buffer *buffer;
> +     struct wl_cursor *cursor;
> +     struct wl_cursor_image *image;
> +
> +     cursor = tool->input->display->cursors[tool->current_cursor];
> +     if (index >= (int)cursor->image_count) {
> +             fprintf(stderr, "cursor index out of range\n");
> +             return;
> +     }
> +
> +     image = cursor->images[index];
> +     buffer = wl_cursor_image_get_buffer(image);
> +     if (!buffer)
> +             return;
> +
> +     wl_surface_attach(tool->cursor_surface, buffer, 0, 0);
> +     wl_surface_damage(tool->cursor_surface, 0, 0,
> +                       image->width, image->height);
> +     wl_surface_commit(tool->cursor_surface);
> +     zwp_tablet_tool_v1_set_cursor(tool->tool, tool->enter_serial,
> +                                   tool->cursor_surface,
> +                                   image->hotspot_x, image->hotspot_y);
> +}
> +
> +static void
> +tablet_tool_surface_frame_callback(void *data, struct wl_callback *callback,
> +                                uint32_t time)
> +{
> +     struct tablet_tool *tool = data;
> +     struct wl_cursor *cursor;
> +     int i;
> +
> +     if (callback) {
> +             assert(callback == tool->cursor_frame_cb);
> +             wl_callback_destroy(callback);
> +             tool->cursor_frame_cb = NULL;
> +     }
> +
> +     if (tool->current_cursor == CURSOR_BLANK) {
> +             zwp_tablet_tool_v1_set_cursor(tool->tool, tool->enter_serial,
> +                                           NULL, 0, 0);
> +             return;
> +     }
> +
> +     if (tool->current_cursor == CURSOR_UNSET)
> +             return;
> +
> +     cursor = tool->input->display->cursors[tool->current_cursor];
> +     if (!cursor)
> +             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)
> +             tool->cursor_anim_start = 0;
> +     else if (tool->cursor_anim_start == 0)
> +             tool->cursor_anim_start = time;
> +
> +     if (time == 0 || tool->cursor_anim_start == 0)
> +             i = 0;
> +     else
> +             i = wl_cursor_frame(cursor, time - tool->cursor_anim_start);
> +
> +     if (cursor->image_count > 1) {
> +             tool->cursor_frame_cb =
> +                     wl_surface_frame(tool->cursor_surface);
> +             wl_callback_add_listener(tool->cursor_frame_cb,
> +                                      &tablet_tool_cursor_surface_listener,
> +                                      tool);
> +     }
> +
> +     tablet_tool_set_cursor_image_index(tool, i);
> +}
> +
> +static const struct wl_callback_listener tablet_tool_cursor_surface_listener 
> =  {
> +     tablet_tool_surface_frame_callback,
> +};
> +
> +void
> +tablet_tool_set_cursor_image(struct tablet_tool *tool, int cursor)
> +{
> +     bool force = false;
> +
> +     if (tool->enter_serial > tool->cursor_serial)
> +             force = true;
> +
> +     if (!force && cursor == tool->current_cursor)
> +             return;
> +
> +     tool->current_cursor = cursor;
> +     tool->cursor_serial = tool->enter_serial;
> +
> +     if (!tool->cursor_frame_cb) {
> +             tablet_tool_surface_frame_callback(tool, NULL, 0);
> +     } else if (force) {
> +             /* The current frame callback may be stuck if, for instance,
> +              * the set cursor request was processed by the server after
> +              * this client lost the focus. In this case the cursor surface
> +              * might not be mapped and the frame callback wouldn't ever
> +              * complete. Send a set_cursor and attach to try to map the
> +              * cursor surface again so that the callback will finish
> +              */
> +             tablet_tool_set_cursor_image_index(tool, 0);
> +     }
> +}
> +
>  static void
>  tablet_tool_set_focus_widget(struct tablet_tool *tool, struct window *window,
>                            wl_fixed_t sx, wl_fixed_t sy)
> @@ -5707,6 +5832,7 @@ tablet_tool_handle_proximity_in(void *data,
>  
>       tool->focus = window;
>       tool->current_tablet = tablet;
> +     tool->enter_serial = serial;
>  }
>  
>  static void
> @@ -5751,6 +5877,7 @@ tablet_tool_handle_motion(void *data, struct 
> zwp_tablet_tool_v1 *zwp_tablet_tool
>       double sy = wl_fixed_to_double(y);
>       struct window *window = tool->focus;
>       struct widget *widget;
> +     int cursor;
>  
>       if (!window)
>               return;
> @@ -5765,9 +5892,14 @@ tablet_tool_handle_motion(void *data, struct 
> zwp_tablet_tool_v1 *zwp_tablet_tool
>       tablet_tool_set_focus_widget(tool, window, sx, sy);
>       widget = tool->focus_widget;
>       if (widget && widget->tablet_tool_motion_handler) {
> -             widget->tablet_tool_motion_handler(widget, tool, sx, sy,
> -                                                widget->user_data);
> +             cursor = widget->tablet_tool_motion_handler(widget, tool,
> +                                                         sx, sy,
> +                                                         widget->user_data);
> +     } else {
> +             cursor = widget->default_tablet_cursor;
>       }
> +
> +     tablet_tool_set_cursor_image(tool, cursor);
>  }
>  
>  static void
> @@ -5908,6 +6040,8 @@ tablet_tool_added(void *data, struct zwp_tablet_seat_v1 
> *zwp_tablet_seat1,
>  
>       tool->tool = id;
>       tool->input = input;
> +     tool->cursor_surface =
> +             wl_compositor_create_surface(input->display->compositor);
>  }
>  
>  static const struct zwp_tablet_seat_v1_listener tablet_seat_listener = {
> diff --git a/clients/window.h b/clients/window.h
> index 86f0366..903abf0 100644
> --- a/clients/window.h
> +++ b/clients/window.h
> @@ -275,10 +275,10 @@ typedef void (*widget_axis_handler_t)(struct widget 
> *widget,
>                                     uint32_t axis,
>                                     wl_fixed_t value,
>                                     void *data);
> -typedef void (*widget_tablet_tool_motion_handler_t)(struct widget *widget,
> -                                                 struct tablet_tool *tool,
> -                                                 float x, float y,
> -                                                 void *data);
> +typedef int (*widget_tablet_tool_motion_handler_t)(struct widget *widget,
> +                                                struct tablet_tool *tool,
> +                                                float x, float y,
> +                                                void *data);
>  typedef void (*widget_tablet_tool_down_handler_t)(struct widget *widget,
>                                                 struct tablet_tool *tool,
>                                                 void *data);
> @@ -533,6 +533,8 @@ widget_destroy(struct widget *widget);
>  void
>  widget_set_default_cursor(struct widget *widget, int cursor);
>  void
> +widget_set_default_tablet_cursor(struct widget *widget, int cursor);
> +void
>  widget_get_allocation(struct widget *widget, struct rectangle *allocation);
>  
>  void
> @@ -750,4 +752,7 @@ tablet_tool_get_serial(struct tablet_tool *tool);
>  uint64_t
>  tablet_tool_get_hwid(struct tablet_tool *tool);
>  
> +void
> +tablet_tool_set_cursor_image(struct tablet_tool *tool, int cursor);
> +
>  #endif
> -- 
> 2.5.0
> 
> _______________________________________________
> wayland-devel mailing list
> [email protected]
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to