From: Stephen Chandler Paul <thatsly...@gmail.com> Again, a lot of this is code that has been reused from the cursor code for pointers.
Co-authored-by: Peter Hutterer <peter.hutte...@who-t.net> Signed-off-by: Stephen Chandler Paul <thatsly...@gmail.com> Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- 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 25be12f..8ef831f 100644 --- a/clients/window.c +++ b/clients/window.c @@ -160,6 +160,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_tool1_type type; uint64_t serial; @@ -326,6 +332,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 @@ -1654,6 +1661,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; @@ -1712,6 +1720,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; @@ -5547,6 +5561,117 @@ tablet_tool_handle_removed(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1 zwp_tablet_tool1_destroy(zwp_tablet_tool1); } +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_tool1_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_tool1_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) @@ -5587,6 +5712,7 @@ tablet_tool_handle_proximity_in(void *data, tool->focus = window; tool->current_tablet = tablet; + tool->enter_serial = serial; } static void @@ -5631,6 +5757,7 @@ tablet_tool_handle_motion(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1, double sy = wl_fixed_to_double(y); struct window *window = tool->focus; struct widget *widget; + int cursor; if (!window) return; @@ -5645,9 +5772,14 @@ tablet_tool_handle_motion(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1, 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 @@ -5746,6 +5878,8 @@ tablet_tool_added(void *data, struct zwp_tablet_seat1 *zwp_tablet_seat1, tool->tool = id; tool->input = input; + tool->cursor_surface = + wl_compositor_create_surface(input->display->compositor); } static const struct zwp_tablet_seat1_listener tablet_seat_listener = { diff --git a/clients/window.h b/clients/window.h index a09851f..f1188b4 100644 --- a/clients/window.h +++ b/clients/window.h @@ -269,10 +269,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); @@ -497,6 +497,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 @@ -707,4 +709,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.4.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel