[PATCH libinput] Emit LIBINPUT_TABLET_EVENT_TOOL_UPDATE events on tool changes

Stephen Chandler Paul thatslyude at gmail.com
Fri Jun 13 01:23:19 PDT 2014


V2 of this patch. There was a big change I was supposed to apply to this before
I sent it out that completely slipped my mind until just now. This causes a
merge conflict with the patch for handling tablet buttons so I'll be sending out
a modified version of that in just a second

Signed-off-by: Stephen Chandler Paul <thatslyude at gmail.com>
---
 src/evdev-tablet.c     | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/evdev-tablet.h     |  6 +++-
 src/libinput-private.h |  7 ++++
 src/libinput.c         | 41 ++++++++++++++++++++++
 src/libinput.h         | 35 +++++++++++++++++--
 5 files changed, 181 insertions(+), 3 deletions(-)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 5c73bcb..c5160b1 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -63,6 +63,19 @@ tablet_process_absolute(struct tablet_dispatch *tablet,
 }
 
 static void
+tablet_update_tool(struct tablet_dispatch *tablet,
+		   int32_t tool,
+		   bool enabled)
+{
+	assert(tool != LIBINPUT_TOOL_NONE);
+
+	if (enabled && tool != tablet->current_tool_type) {
+		tablet->current_tool_type = tool;
+		tablet_set_status(tablet, TABLET_TOOL_UPDATED);
+	}
+}
+
+static void
 tablet_notify_axes(struct tablet_dispatch *tablet,
 		   struct evdev_device *device,
 		   uint32_t time)
@@ -95,10 +108,85 @@ tablet_notify_axes(struct tablet_dispatch *tablet,
 }
 
 static void
+tablet_process_key(struct tablet_dispatch *tablet,
+		   struct evdev_device *device,
+		   struct input_event *e,
+		   uint32_t time)
+{
+	switch (e->code) {
+	case BTN_TOOL_PEN:
+	case BTN_TOOL_RUBBER:
+	case BTN_TOOL_BRUSH:
+	case BTN_TOOL_PENCIL:
+	case BTN_TOOL_AIRBRUSH:
+	case BTN_TOOL_FINGER:
+	case BTN_TOOL_MOUSE:
+	case BTN_TOOL_LENS:
+		/* These codes have an equivalent libinput_tool value */
+		tablet_update_tool(tablet, e->code, e->value);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+tablet_process_misc(struct tablet_dispatch *tablet,
+		    struct evdev_device *device,
+		    struct input_event *e,
+		    uint32_t time)
+{
+	switch (e->code) {
+	case MSC_SERIAL:
+		tablet->current_tool_serial = e->value;
+		break;
+	default:
+		log_info("Unhandled MSC event code %#x\n", e->code);
+		break;
+	}
+}
+
+static void
+tablet_notify_tool(struct tablet_dispatch *tablet,
+		   struct evdev_device *device,
+		   uint32_t time)
+{
+	struct libinput_device *base = &device->base;
+	struct libinput_tool *tool;
+	struct libinput_tool *new_tool = NULL;
+
+	/* Check if we already have the tool in our list of tools */
+	list_for_each(tool, &base->seat->libinput->tool_list, link) {
+		if (tablet->current_tool_type == tool->type &&
+		    tablet->current_tool_serial == tool->serial) {
+			new_tool = tool;
+			break;
+		}
+	}
+
+	/* If we didn't already have the tool in our list of tools, add it */
+	if (new_tool == NULL) {
+		new_tool = zalloc(sizeof *new_tool);
+		*new_tool = (struct libinput_tool) {
+			.type = tablet->current_tool_type,
+			.serial = tablet->current_tool_serial,
+			.refcount = 1,
+		};
+
+		list_insert(&base->seat->libinput->tool_list, &new_tool->link);
+	}
+
+	tablet_notify_tool_update(base, time, new_tool);
+}
+
+static void
 tablet_flush(struct tablet_dispatch *tablet,
 	     struct evdev_device *device,
 	     uint32_t time)
 {
+	if (tablet_has_status(tablet, TABLET_TOOL_UPDATED))
+		tablet_notify_tool(tablet, device, time);
+
 	if (tablet_has_status(tablet, TABLET_AXES_UPDATED)) {
 		tablet_notify_axes(tablet, device, time);
 		tablet_unset_status(tablet, TABLET_AXES_UPDATED);
@@ -118,6 +206,12 @@ tablet_process(struct evdev_dispatch *dispatch,
 	case EV_ABS:
 		tablet_process_absolute(tablet, device, e, time);
 		break;
+	case EV_KEY:
+		tablet_process_key(tablet, device, e, time);
+		break;
+	case EV_MSC:
+		tablet_process_misc(tablet, device, e, time);
+		break;
 	case EV_SYN:
 		tablet_flush(tablet, device, time);
 		break;
@@ -148,6 +242,7 @@ tablet_init(struct tablet_dispatch *tablet,
 	tablet->base.interface = &tablet_interface;
 	tablet->device = device;
 	tablet->status = TABLET_NONE;
+	tablet->current_tool_type = LIBINPUT_TOOL_NONE;
 
 	return 0;
 }
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index d832c17..dd5988c 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -29,7 +29,8 @@
 
 enum tablet_status {
 	TABLET_NONE = 0,
-	TABLET_AXES_UPDATED = 1 << 0
+	TABLET_AXES_UPDATED = 1 << 0,
+	TABLET_TOOL_UPDATED = 1 << 1
 };
 
 struct tablet_dispatch {
@@ -39,6 +40,9 @@ struct tablet_dispatch {
 	unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
 	const struct input_absinfo *absinfo[LIBINPUT_TABLET_AXIS_CNT];
 	double axes[LIBINPUT_TABLET_AXIS_CNT];
+
+	enum libinput_tool_type current_tool_type;
+	uint32_t current_tool_serial;
 };
 
 static inline enum libinput_tablet_axis
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 83906f5..532ce29 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -54,6 +54,8 @@ struct libinput {
 	size_t events_in;
 	size_t events_out;
 
+	struct list tool_list;
+
 	const struct libinput_interface *interface;
 	const struct libinput_interface_backend *interface_backend;
 	void *user_data;
@@ -208,6 +210,11 @@ tablet_notify_axis(struct libinput_device *device,
 		   double *axes);
 
 void
+tablet_notify_tool_update(struct libinput_device *device,
+			  uint32_t time,
+			  struct libinput_tool *tool);
+
+void
 touch_notify_frame(struct libinput_device *device,
 		   uint32_t time);
 #endif /* LIBINPUT_PRIVATE_H */
diff --git a/src/libinput.c b/src/libinput.c
index def3e91..f484a5d 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -85,6 +85,7 @@ struct libinput_event_tablet {
 	uint32_t time;
 	double *axes;
 	unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
+	struct libinput_tool *tool;
 };
 
 static void
@@ -199,6 +200,7 @@ libinput_event_get_pointer_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TOUCH_CANCEL:
 	case LIBINPUT_EVENT_TOUCH_FRAME:
 	case LIBINPUT_EVENT_TABLET_AXIS:
+	case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
 		break;
 	}
 
@@ -226,6 +228,7 @@ libinput_event_get_keyboard_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TOUCH_CANCEL:
 	case LIBINPUT_EVENT_TOUCH_FRAME:
 	case LIBINPUT_EVENT_TABLET_AXIS:
+	case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
 		break;
 	}
 
@@ -253,6 +256,7 @@ libinput_event_get_touch_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TOUCH_FRAME:
 		return (struct libinput_event_touch *) event;
 	case LIBINPUT_EVENT_TABLET_AXIS:
+	case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
 		break;
 	}
 
@@ -279,6 +283,7 @@ libinput_event_get_tablet_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TOUCH_FRAME:
 		break;
 	case LIBINPUT_EVENT_TABLET_AXIS:
+	case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
 		return (struct libinput_event_tablet *) event;
 	}
 
@@ -305,6 +310,7 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TOUCH_CANCEL:
 	case LIBINPUT_EVENT_TOUCH_FRAME:
 	case LIBINPUT_EVENT_TABLET_AXIS:
+	case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
 		break;
 	}
 
@@ -508,6 +514,12 @@ libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event,
 					height);
 }
 
+LIBINPUT_EXPORT struct libinput_tool *
+libinput_event_tablet_get_tool(struct libinput_event_tablet *event)
+{
+	return event->tool;
+}
+
 LIBINPUT_EXPORT uint32_t
 libinput_event_tablet_get_time(struct libinput_event_tablet *event)
 {
@@ -604,6 +616,7 @@ libinput_init(struct libinput *libinput,
 	libinput->user_data = user_data;
 	list_init(&libinput->source_destroy_list);
 	list_init(&libinput->seat_list);
+	list_init(&libinput->tool_list);
 
 	if (libinput_timer_subsys_init(libinput) != 0) {
 		free(libinput->events);
@@ -673,6 +686,13 @@ libinput_event_destroy(struct libinput_event *event)
 	if (event->device)
 		libinput_device_unref(event->device);
 
+	else if (event->type == LIBINPUT_EVENT_TABLET_TOOL_UPDATE) {
+		struct libinput_event_tablet *tevent =
+			(struct libinput_event_tablet*)event;
+
+		libinput_tool_unref(tevent->tool);
+	}
+
 	free(event);
 }
 
@@ -1159,6 +1179,27 @@ tablet_notify_axis(struct libinput_device *device,
 			  &axis_event->base);
 }
 
+void
+tablet_notify_tool_update(struct libinput_device *device,
+			  uint32_t time,
+			  struct libinput_tool *tool)
+{
+	struct libinput_event_tablet *tool_update_event;
+
+	tool_update_event = zalloc(sizeof *tool_update_event);
+	if (!tool_update_event)
+		return;
+
+	*tool_update_event = (struct libinput_event_tablet) {
+		.time = time,
+		.tool = tool,
+	};
+
+	post_device_event(device,
+			  LIBINPUT_EVENT_TABLET_TOOL_UPDATE,
+			  &tool_update_event->base);
+}
+
 static void
 libinput_post_event(struct libinput *libinput,
 		    struct libinput_event *event)
diff --git a/src/libinput.h b/src/libinput.h
index c0c9fae..9615f1d 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -254,7 +254,12 @@ enum libinput_event_type {
 	 */
 	LIBINPUT_EVENT_TOUCH_FRAME,
 
-	LIBINPUT_EVENT_TABLET_AXIS = 600
+	LIBINPUT_EVENT_TABLET_AXIS = 600,
+	/**
+	 * Signals that a device with the @ref LIBINPUT_DEVICE_CAP_TABLET
+	 * capability has changed its tool.
+	 */
+	LIBINPUT_EVENT_TABLET_TOOL_UPDATE
 };
 
 struct libinput;
@@ -283,7 +288,8 @@ struct libinput_event_touch;
  * @struct libinput_event_tablet
  *
  * Tablet event representing an axis update, button press, or tool update. Valid
- * event types for this event are @ref LIBINPUT_EVENT_TABLET_AXIS.
+ * event types for this event are @ref LIBINPUT_EVENT_TABLET_AXIS, and
+ * @ref LIBINPUT_EVENT_TABLET_TOOL_UPDATE.
  */
 struct libinput_event_tablet;
 
@@ -891,6 +897,31 @@ libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event,
 double
 libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event,
 					uint32_t height);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Return the new tool in use for this event.
+ * For tablet events that are not of type @ref
+ * LIBINPUT_EVENT_TABLET_TOOL_UPDATE, this function returns NULL. By default,
+ * the lifetime of each tool is binded to the lifetime of the event, so the tool
+ * will be destroyed when the event is destroyed. However, the lifetime of the
+ * tool may be extended by using libinput_tool_ref() to increment the reference
+ * count of the tool. Whenever libinput detects that the tool is in proximity of
+ * any tablet that's connected, it will return the same libinput_tool object.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_TOOL_UPDATE.
+ *
+ * @note On tablets where the serial number of tools is not reported, each tool
+ * cannot be guaranteed to be unique.
+ *
+ * @param event The libinput tablet event
+ * @return The new tool triggering this event
+ */
+struct libinput_tool *
+libinput_event_tablet_get_tool(struct libinput_event_tablet *event);
+
 /**
  * @ingroup event_tablet
  *
-- 
1.8.5.5



More information about the wayland-devel mailing list