[PATCH weston v2 07/16] client: Add tablet cursor support into libtoytoolkit
Maniraj Devadoss
Maniraj.Devadoss at in.bosch.com
Thu Nov 23 10:17:19 UTC 2017
From: Lyude Paul <thatslyude at 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.hutterer at who-t.net>
Signed-off-by: Lyude Paul <thatslyude at gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
Reviewed-by: Jonas Ã…dahl <jadahl at gmail.com>
Signed-off-by: Bastian Farkas <bfarkas at de.adit-jv.com>
---
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 3e9af47..bb370d4 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -172,6 +172,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;
@@ -362,6 +368,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
@@ -1712,6 +1719,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;
@@ -1770,6 +1778,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;
@@ -6189,6 +6203,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)
@@ -6229,6 +6354,7 @@ tablet_tool_handle_proximity_in(void *data,
tool->focus = window;
tool->current_tablet = tablet;
+ tool->enter_serial = serial;
}
static void
@@ -6273,6 +6399,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;
@@ -6287,9 +6414,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
@@ -6430,6 +6562,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 57220a2..977acf1 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -288,10 +288,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);
@@ -584,6 +584,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
@@ -801,4 +803,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.7.4
More information about the wayland-devel
mailing list