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
