[PATCH weston 01/13] tablet: Add initial tablet support to weston

Peter Hutterer peter.hutterer at who-t.net
Thu Nov 5 20:31:09 PST 2015


From: Stephen Chandler Paul <thatslyude at gmail.com>

Introduces two new structs, weston_tablet and weston_tablet_tool with the
respective information as it's used on the protocol.

Note that tools are independent of tablets, many tools can be used across
multiple tablets.

The nesting on the protocol level requires a global tablet manager, a tablet
seat nested into weston_seat. The list of tablets and tools are also part of
the weston_seat.

Most functions are stubs except for the actual tablet and tablet tool
creation and removal.

Co-authored-by: Peter Hutterer <peter.hutterer at who-t.net>
Signed-off-by: Stephen Chandler Paul <thatslyude at gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 Makefile.am           |  13 +-
 src/compositor.c      |   1 +
 src/compositor.h      |  99 +++++++++++++
 src/input.c           | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/libinput-device.c | 205 ++++++++++++++++++++++++++
 src/libinput-device.h |   4 +-
 6 files changed, 708 insertions(+), 4 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index e7feebd..4f2110d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,7 +126,9 @@ nodist_weston_SOURCES =					\
 	protocol/scaler-protocol.c			\
 	protocol/scaler-server-protocol.h		\
 	protocol/linux-dmabuf-unstable-v1-protocol.c	\
-	protocol/linux-dmabuf-unstable-v1-server-protocol.h
+	protocol/linux-dmabuf-unstable-v1-server-protocol.h		\
+	protocol/tablet-unstable-v1-protocol.c				\
+	protocol/tablet-unstable-v1-server-protocol.h
 
 BUILT_SOURCES += $(nodist_weston_SOURCES)
 
@@ -555,7 +557,9 @@ nodist_libtoytoolkit_la_SOURCES =			\
 	protocol/xdg-shell-unstable-v5-protocol.c			\
 	protocol/xdg-shell-unstable-v5-client-protocol.h		\
 	protocol/ivi-application-protocol.c		\
-	protocol/ivi-application-client-protocol.h
+	protocol/ivi-application-client-protocol.h	\
+	protocol/tablet-unstable-v1-protocol.c		\
+	protocol/tablet-unstable-v1-client-protocol.h
 
 BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES)
 
@@ -764,7 +768,10 @@ BUILT_SOURCES +=					\
 	protocol/ivi-hmi-controller-protocol.c		\
 	protocol/ivi-hmi-controller-client-protocol.h	\
 	protocol/ivi-application-protocol.c		\
-	protocol/ivi-application-client-protocol.h
+	protocol/ivi-application-client-protocol.h	\
+	protocol/tablet-unstable-v1-protocol.c		\
+	protocol/tablet-unstable-v1-client-protocol.h
+
 
 westondatadir = $(datadir)/weston
 dist_westondata_DATA =				\
diff --git a/src/compositor.c b/src/compositor.c
index 80cd983..8eadf8c 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -4518,6 +4518,7 @@ weston_compositor_create(struct wl_display *display, void *user_data)
 	wl_list_init(&ec->touch_binding_list);
 	wl_list_init(&ec->axis_binding_list);
 	wl_list_init(&ec->debug_binding_list);
+	wl_list_init(&ec->tablet_manager_resource_list);
 
 	weston_plane_init(&ec->primary_plane, ec, 0, 0);
 	weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
diff --git a/src/compositor.h b/src/compositor.h
index f3e0075..50c7034 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -38,6 +38,7 @@ extern "C" {
 
 #define WL_HIDE_DEPRECATED
 #include <wayland-server.h>
+#include <tablet-unstable-v1-server-protocol.h>
 
 #include "version.h"
 #include "matrix.h"
@@ -366,6 +367,35 @@ struct weston_touch {
 	uint32_t grab_time;
 };
 
+struct weston_tablet_tool {
+	struct weston_seat *seat;
+	enum zwp_tablet_tool1_type type;
+
+	struct wl_list resource_list;
+
+	struct wl_list link;
+
+	uint64_t serial;
+	uint64_t hwid;
+	uint32_t capabilities;
+};
+
+struct weston_tablet {
+	struct weston_seat *seat;
+	struct evdev_device *device;
+
+	struct wl_list resource_list;
+
+	struct wl_list link;
+
+	char *name;
+	enum zwp_tablet1_type type;
+	uint32_t vid;
+	uint32_t pid;
+	const char *path;
+	struct weston_output *output;
+};
+
 struct weston_pointer *
 weston_pointer_create(struct weston_seat *seat);
 void
@@ -427,6 +457,16 @@ weston_touch_start_grab(struct weston_touch *device,
 void
 weston_touch_end_grab(struct weston_touch *touch);
 
+struct weston_tablet *
+weston_tablet_create(void);
+void
+weston_tablet_destroy(struct weston_tablet *tablet);
+
+struct weston_tablet_tool *
+weston_tablet_tool_create(void);
+void
+weston_tablet_tool_destroy(struct weston_tablet_tool *tool);
+
 void
 wl_data_device_set_keyboard_focus(struct weston_seat *seat);
 
@@ -513,6 +553,8 @@ struct weston_seat {
 	struct weston_pointer *pointer_state;
 	struct weston_keyboard *keyboard_state;
 	struct weston_touch *touch_state;
+	struct wl_list tablet_list;
+	struct wl_list tablet_tool_list;
 	int pointer_device_count;
 	int keyboard_device_count;
 	int touch_device_count;
@@ -539,6 +581,8 @@ struct weston_seat {
 	uint32_t slot_map;
 	struct input_method *input_method;
 	char *seat_name;
+
+	struct wl_list tablet_seat_resource_list;
 };
 
 enum {
@@ -736,6 +780,9 @@ struct weston_compositor {
 
 	void *user_data;
 	void (*exit)(struct weston_compositor *c);
+
+	struct wl_global *tablet_manager;
+	struct wl_list tablet_manager_resource_list;
 };
 
 struct weston_buffer {
@@ -1136,6 +1183,47 @@ void
 notify_touch_frame(struct weston_seat *seat);
 
 void
+notify_tablet_added(struct weston_tablet *tablet);
+
+void
+notify_tablet_tool_added(struct weston_tablet_tool *tool);
+
+void
+notify_tablet_tool_proximity_in(struct weston_tablet_tool *tool,
+				uint32_t time,
+				struct weston_tablet *tablet);
+void
+notify_tablet_tool_proximity_out(struct weston_tablet_tool *tool,
+				 uint32_t time);
+void
+notify_tablet_tool_motion(struct weston_tablet_tool *tool,
+			  uint32_t time,
+			  wl_fixed_t x, wl_fixed_t y);
+void
+notify_tablet_tool_pressure(struct weston_tablet_tool *tool,
+			    uint32_t time, uint32_t pressure);
+void
+notify_tablet_tool_distance(struct weston_tablet_tool *tool,
+			    uint32_t time, uint32_t distance);
+void
+notify_tablet_tool_tilt(struct weston_tablet_tool *tool,
+			uint32_t time, int32_t tilt_x, int32_t tilt_y);
+void
+notify_tablet_tool_button(struct weston_tablet_tool *tool,
+			  uint32_t time,
+			  uint32_t button,
+			  enum zwp_tablet_tool1_button_state state);
+void
+notify_tablet_tool_up(struct weston_tablet_tool *tool,
+		      uint32_t time);
+void
+notify_tablet_tool_down(struct weston_tablet_tool *tool,
+			uint32_t time);
+void
+notify_tablet_tool_frame(struct weston_tablet_tool *tool,
+			 uint32_t time);
+
+void
 weston_layer_entry_insert(struct weston_layer_entry *list,
 			  struct weston_layer_entry *entry);
 void
@@ -1452,6 +1540,14 @@ void
 weston_seat_init_touch(struct weston_seat *seat);
 void
 weston_seat_release_touch(struct weston_seat *seat);
+struct weston_tablet *
+weston_seat_add_tablet(struct weston_seat *seat);
+struct weston_tablet_tool *
+weston_seat_add_tablet_tool(struct weston_seat *seat);
+void
+weston_seat_release_tablet_tool(struct weston_tablet_tool *tablet_tool);
+void
+weston_seat_release_tablet(struct weston_tablet *tablet);
 void
 weston_seat_repick(struct weston_seat *seat);
 void
@@ -1465,6 +1561,9 @@ weston_compositor_xkb_init(struct weston_compositor *ec,
 void
 weston_compositor_xkb_destroy(struct weston_compositor *ec);
 
+void
+weston_tablet_manager_init(struct weston_compositor *ec);
+
 /* String literal of spaces, the same width as the timestamp. */
 #define STAMP_SPACE "               "
 
diff --git a/src/input.c b/src/input.c
index 09d12de..8814d34 100644
--- a/src/input.c
+++ b/src/input.c
@@ -643,6 +643,60 @@ weston_touch_destroy(struct weston_touch *touch)
 	free(touch);
 }
 
+WL_EXPORT struct weston_tablet *
+weston_tablet_create(void)
+{
+	struct weston_tablet *tablet;
+
+	tablet = zalloc(sizeof *tablet);
+	if (tablet == NULL)
+		return NULL;
+
+	wl_list_init(&tablet->resource_list);
+
+	return tablet;
+}
+
+WL_EXPORT void
+weston_tablet_destroy(struct weston_tablet *tablet)
+{
+	struct wl_resource *resource;
+
+	wl_resource_for_each(resource, &tablet->resource_list)
+		zwp_tablet1_send_removed(resource);
+
+	wl_list_remove(&tablet->link);
+	free(tablet->name);
+	free(tablet);
+}
+
+WL_EXPORT struct weston_tablet_tool *
+weston_tablet_tool_create(void)
+{
+	struct weston_tablet_tool *tool;
+
+	tool = zalloc(sizeof *tool);
+	if (tool == NULL)
+		return NULL;
+
+	wl_list_init(&tool->resource_list);
+
+	return tool;
+}
+
+WL_EXPORT void
+weston_tablet_tool_destroy(struct weston_tablet_tool *tool)
+{
+	struct wl_resource *resource, *tmp;
+
+	wl_resource_for_each_safe(resource, tmp, &tool->resource_list)
+		zwp_tablet_tool1_send_removed(resource);
+
+	wl_list_remove(&tool->link);
+	free(tool);
+}
+
+
 static void
 seat_send_updated_caps(struct weston_seat *seat)
 {
@@ -1659,6 +1713,186 @@ pointer_cursor_surface_get_label(struct weston_surface *surface,
 }
 
 static void
+tablet_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct zwp_tablet1_interface tablet_interface = {
+	tablet_destroy,
+};
+
+static void
+send_tablet_added(struct weston_tablet *tablet,
+		  struct wl_resource *tablet_seat_resource,
+		  struct wl_resource *tablet_resource)
+{
+	zwp_tablet_seat1_send_tablet_added(tablet_seat_resource, tablet_resource);
+	zwp_tablet1_send_name(tablet_resource, tablet->name);
+	zwp_tablet1_send_id(tablet_resource, tablet->vid, tablet->pid);
+	zwp_tablet1_send_type(tablet_resource, tablet->type);
+	zwp_tablet1_send_path(tablet_resource, tablet->path);
+	zwp_tablet1_send_done(tablet_resource);
+}
+
+WL_EXPORT void
+notify_tablet_added(struct weston_tablet *tablet)
+{
+	struct wl_resource *resource;
+	struct weston_seat *seat = tablet->seat;
+
+	wl_resource_for_each(resource, &seat->tablet_seat_resource_list) {
+		struct wl_resource *tablet_resource =
+			wl_resource_create(wl_resource_get_client(resource),
+					   &zwp_tablet1_interface,
+					   1, 0);
+
+		wl_list_insert(&tablet->resource_list,
+			       wl_resource_get_link(tablet_resource));
+		wl_resource_set_implementation(tablet_resource,
+					       &tablet_interface,
+					       tablet,
+					       unbind_resource);
+
+		wl_resource_set_user_data(tablet_resource, tablet);
+		send_tablet_added(tablet, resource, tablet_resource);
+	}
+}
+
+static void
+tablet_tool_set_cursor(struct wl_client *client, struct wl_resource *resource,
+		       uint32_t serial, struct wl_resource *surface_resource,
+		       int32_t hotspot_x, int32_t hotspot_y)
+{
+}
+
+static void
+tablet_tool_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct zwp_tablet_tool1_interface tablet_tool_interface = {
+	tablet_tool_set_cursor,
+	tablet_tool_destroy,
+};
+
+static void
+send_tool_added(struct weston_tablet_tool *tool,
+		struct wl_resource *tool_seat_resource,
+		struct wl_resource *tool_resource)
+{
+	uint32_t caps, cap;
+	zwp_tablet_seat1_send_tool_added(tool_seat_resource, tool_resource);
+	zwp_tablet_tool1_send_type(tool_resource, tool->type);
+	zwp_tablet_tool1_send_serial_id(tool_resource,
+				      tool->serial >> 32,
+				      tool->serial & 0xFFFFFFFF);
+	zwp_tablet_tool1_send_hardware_id(tool_resource,
+					ZWP_TABLET_TOOL1_HARDWARE_ID_FORMAT_WACOM_STYLUS_ID,
+					tool->hwid >> 32,
+					tool->hwid & 0xFFFFFFFF);
+	caps = tool->capabilities;
+	while (caps != 0) {
+		cap = ffs(caps) - 1;
+		zwp_tablet_tool1_send_capability(tool_resource, cap);
+		caps &= ~(1 << cap);
+	}
+
+	zwp_tablet_tool1_send_done(tool_resource);
+	/* FIXME: hw id, not supported by libinput yet */
+}
+
+WL_EXPORT void
+notify_tablet_tool_added(struct weston_tablet_tool *tool)
+{
+	struct wl_resource *resource;
+	struct weston_seat *seat = tool->seat;
+
+	wl_resource_for_each(resource, &seat->tablet_seat_resource_list) {
+		struct wl_resource *tool_resource =
+			wl_resource_create(wl_resource_get_client(resource),
+					   &zwp_tablet_tool1_interface,
+					   1, 0);
+
+		wl_list_insert(&tool->resource_list,
+			       wl_resource_get_link(tool_resource));
+		wl_resource_set_implementation(tool_resource,
+					       &tablet_tool_interface,
+					       tool,
+					       unbind_resource);
+
+		wl_resource_set_user_data(tool_resource, tool);
+		send_tool_added(tool, resource, tool_resource);
+	}
+}
+
+WL_EXPORT void
+notify_tablet_tool_proximity_in(struct weston_tablet_tool *tool,
+				 uint32_t time,
+				 struct weston_tablet *tablet)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_proximity_out(struct weston_tablet_tool *tool,
+				 uint32_t time)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_motion(struct weston_tablet_tool *tool,
+			  uint32_t time,
+			  wl_fixed_t x, wl_fixed_t y)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_pressure(struct weston_tablet_tool *tool,
+			    uint32_t time, uint32_t pressure)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_distance(struct weston_tablet_tool *tool,
+			    uint32_t time, uint32_t distance)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_tilt(struct weston_tablet_tool *tool,
+			uint32_t time, int32_t tilt_x, int32_t tilt_y)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_button(struct weston_tablet_tool *tool,
+			  uint32_t time,
+			  uint32_t button,
+			  enum zwp_tablet_tool1_button_state state)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_down(struct weston_tablet_tool *tool,
+			uint32_t time)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_up(struct weston_tablet_tool *tool,
+		      uint32_t time)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_frame(struct weston_tablet_tool *tool,
+			 uint32_t time)
+{
+}
+
+
+static void
 pointer_cursor_surface_configure(struct weston_surface *es,
 				 int32_t dx, int32_t dy)
 {
@@ -2340,6 +2574,19 @@ weston_seat_release_pointer(struct weston_seat *seat)
 }
 
 WL_EXPORT void
+weston_seat_release_tablet_tool(struct weston_tablet_tool *tool)
+{
+	/* FIXME: nothing is calling this function yet, tools are only
+	   released on shutdown when the seat goes away */
+}
+
+WL_EXPORT void
+weston_seat_release_tablet(struct weston_tablet *tablet)
+{
+	weston_tablet_destroy(tablet);
+}
+
+WL_EXPORT void
 weston_seat_init_touch(struct weston_seat *seat)
 {
 	struct weston_touch *touch;
@@ -2362,6 +2609,39 @@ weston_seat_init_touch(struct weston_seat *seat)
 	seat_send_updated_caps(seat);
 }
 
+WL_EXPORT struct weston_tablet *
+weston_seat_add_tablet(struct weston_seat *seat)
+{
+	struct weston_tablet *tablet;
+
+	weston_tablet_manager_init(seat->compositor);
+
+	tablet = weston_tablet_create();
+	if (tablet == NULL)
+		return NULL;
+
+	tablet->seat = seat;
+
+	return tablet;
+}
+
+WL_EXPORT struct weston_tablet_tool *
+weston_seat_add_tablet_tool(struct weston_seat *seat)
+{
+	struct weston_tablet_tool *tool;
+
+	weston_tablet_manager_init(seat->compositor);
+
+	tool = weston_tablet_tool_create();
+	if (tool == NULL)
+		return NULL;
+
+	wl_list_init(&tool->resource_list);
+	tool->seat = seat;
+
+	return tool;
+}
+
 WL_EXPORT void
 weston_seat_release_touch(struct weston_seat *seat)
 {
@@ -2386,6 +2666,9 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
 	wl_list_init(&seat->drag_resource_list);
 	wl_signal_init(&seat->destroy_signal);
 	wl_signal_init(&seat->updated_caps_signal);
+	wl_list_init(&seat->tablet_seat_resource_list);
+	wl_list_init(&seat->tablet_list);
+	wl_list_init(&seat->tablet_tool_list);
 
 	seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 4,
 					seat, bind_seat);
@@ -2404,6 +2687,9 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
 WL_EXPORT void
 weston_seat_release(struct weston_seat *seat)
 {
+	struct weston_tablet *tablet, *tmp;
+	struct weston_tablet_tool *tool, *tmp_tool;
+
 	wl_list_remove(&seat->link);
 
 	if (seat->saved_kbd_focus)
@@ -2415,6 +2701,10 @@ weston_seat_release(struct weston_seat *seat)
 		weston_keyboard_destroy(seat->keyboard_state);
 	if (seat->touch_state)
 		weston_touch_destroy(seat->touch_state);
+	wl_list_for_each_safe(tablet, tmp, &seat->tablet_list, link)
+		weston_tablet_destroy(tablet);
+	wl_list_for_each_safe(tool, tmp_tool, &seat->tablet_tool_list, link)
+		weston_tablet_tool_destroy(tool);
 
 	free (seat->seat_name);
 
@@ -2488,3 +2778,103 @@ weston_seat_get_touch(struct weston_seat *seat)
 
 	return NULL;
 }
+
+static void
+tablet_seat_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+}
+
+static const struct zwp_tablet_seat1_interface tablet_seat_interface = {
+	tablet_seat_destroy,
+};
+
+static void
+tablet_manager_get_tablet_seat(struct wl_client *client, struct wl_resource *resource,
+			       uint32_t id, struct wl_resource *seat_resource)
+{
+	struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+	struct wl_resource *cr;
+	struct weston_tablet *tablet;
+	struct weston_tablet_tool *tool;
+
+	cr = wl_resource_create(client, &zwp_tablet_seat1_interface,
+				wl_resource_get_version(resource), id);
+	if (cr == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	/* store the resource in the weston_seat */
+	wl_list_insert(&seat->tablet_seat_resource_list, wl_resource_get_link(cr));
+	wl_resource_set_implementation(cr, &tablet_seat_interface, seat,
+				       unbind_resource);
+
+	/* Notify the client of all tablets currently connected to the system */
+	wl_list_for_each(tablet, &seat->tablet_list, link) {
+		struct wl_resource *tablet_resource =
+			wl_resource_create(client, &zwp_tablet1_interface, 1, 0);
+
+		wl_resource_set_implementation(tablet_resource,
+					       &tablet_interface, tablet,
+					       unbind_resource);
+		wl_resource_set_user_data(tablet_resource, tablet);
+
+		wl_list_insert(&tablet->resource_list,
+			       wl_resource_get_link(tablet_resource));
+
+		send_tablet_added(tablet, cr, tablet_resource);
+	}
+
+	/* Notify the client of all tools already known */
+	wl_list_for_each(tool, &seat->tablet_tool_list, link) {
+		struct wl_resource *tool_resource =
+			wl_resource_create(client, &zwp_tablet_tool1_interface, 1, 0);
+
+		wl_resource_set_implementation(tool_resource,
+					       &tablet_tool_interface, tool,
+					       unbind_resource);
+		wl_resource_set_user_data(tool_resource, tool);
+
+		wl_list_insert(&tool->resource_list,
+			       wl_resource_get_link(tool_resource));
+		send_tool_added(tool, cr, tool_resource);
+	}
+}
+
+static void
+tablet_manager_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+
+}
+
+static const struct zwp_tablet_manager1_interface tablet_manager_interface = {
+	tablet_manager_get_tablet_seat,
+	tablet_manager_destroy,
+};
+
+static void
+bind_tablet_manager(struct wl_client *client, void *data, uint32_t version,
+		    uint32_t id)
+{
+	struct weston_compositor *compositor = data;
+	struct wl_resource *resource;
+
+	resource = wl_resource_create(client, &zwp_tablet_manager1_interface,
+				      MIN(version, 1), id);
+	wl_resource_set_implementation(resource, &tablet_manager_interface,
+				       data, unbind_resource);
+	wl_list_insert(&compositor->tablet_manager_resource_list,
+		       wl_resource_get_link(resource));
+}
+
+WL_EXPORT void
+weston_tablet_manager_init(struct weston_compositor *compositor)
+{
+	if (compositor->tablet_manager)
+		return;
+
+	compositor->tablet_manager = wl_global_create(compositor->wl_display,
+						      &zwp_tablet_manager1_interface,
+						      1, compositor,
+						      bind_tablet_manager);
+}
diff --git a/src/libinput-device.c b/src/libinput-device.c
index 69dcbf8..262c485 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -40,6 +40,14 @@
 #include "libinput-device.h"
 #include "shared/helpers.h"
 
+struct tablet_output_listener {
+	struct wl_listener base;
+	struct wl_list tablet_list;
+};
+
+static bool
+tablet_bind_output(struct weston_tablet *tablet, struct weston_output *output);
+
 void
 evdev_led_update(struct evdev_device *device, enum weston_led weston_leds)
 {
@@ -285,6 +293,84 @@ handle_touch_frame(struct libinput_device *libinput_device,
 	notify_touch_frame(seat);
 }
 
+static void
+handle_tablet_proximity(struct libinput_device *libinput_device,
+			struct libinput_event_tablet *proximity_event)
+{
+	struct evdev_device *device;
+	struct weston_tablet *tablet;
+	struct weston_tablet_tool *tool;
+	struct libinput_tool *libinput_tool;
+	enum libinput_tool_type libinput_tool_type;
+	uint32_t serial, type;
+	uint32_t time;
+	bool create = true;
+
+	device = libinput_device_get_user_data(libinput_device);
+	time = libinput_event_tablet_get_time(proximity_event);
+	libinput_tool = libinput_event_tablet_get_tool(proximity_event);
+	serial = libinput_tool_get_serial(libinput_tool);
+	libinput_tool_type = libinput_tool_get_type(libinput_tool);
+
+	tool = libinput_tool_get_user_data(libinput_tool);
+	tablet = device->tablet;
+
+	if (libinput_event_tablet_get_proximity_state(proximity_event) ==
+	    LIBINPUT_TOOL_PROXIMITY_OUT) {
+		notify_tablet_tool_proximity_out(tool, time);
+		return;
+	}
+
+	switch (libinput_tool_type) {
+	case LIBINPUT_TOOL_PEN:
+		type = ZWP_TABLET_TOOL1_TYPE_PEN;
+		break;
+	case LIBINPUT_TOOL_ERASER:
+		type = ZWP_TABLET_TOOL1_TYPE_ERASER;
+		break;
+	default:
+		fprintf(stderr, "Unknown libinput tool type %d\n",
+			libinput_tool_type);
+		return;
+	}
+
+	wl_list_for_each(tool, &device->seat->tablet_tool_list, link) {
+		if (tool->serial == serial && tool->type == type) {
+			create = false;
+			break;
+		}
+	}
+
+	if (create) {
+		tool = weston_seat_add_tablet_tool(device->seat);
+		tool->serial = serial;
+		tool->hwid = libinput_tool_get_tool_id(libinput_tool);
+		tool->type = type;
+		tool->capabilities = 0;
+
+		if (libinput_tool_has_axis(libinput_tool,
+					   LIBINPUT_TABLET_AXIS_DISTANCE))
+		    tool->capabilities |= 1 << ZWP_TABLET_TOOL1_CAPABILITY_DISTANCE;
+		if (libinput_tool_has_axis(libinput_tool,
+					   LIBINPUT_TABLET_AXIS_PRESSURE))
+		    tool->capabilities |= 1 << ZWP_TABLET_TOOL1_CAPABILITY_PRESSURE;
+		if (libinput_tool_has_axis(libinput_tool,
+					   LIBINPUT_TABLET_AXIS_TILT_X) &&
+		    libinput_tool_has_axis(libinput_tool,
+					   LIBINPUT_TABLET_AXIS_TILT_Y))
+		    tool->capabilities |= 1 << ZWP_TABLET_TOOL1_CAPABILITY_TILT;
+
+		wl_list_insert(&device->seat->tablet_tool_list, &tool->link);
+		notify_tablet_tool_added(tool);
+
+		libinput_tool_set_user_data(libinput_tool, tool);
+	}
+
+	notify_tablet_tool_proximity_in(tool, time, tablet);
+	/* FIXME: we should send axis updates  here */
+	notify_tablet_tool_frame(tool, time);
+}
+
 int
 evdev_device_process_event(struct libinput_event *event)
 {
@@ -330,6 +416,10 @@ evdev_device_process_event(struct libinput_event *event)
 		handle_touch_frame(libinput_device,
 				   libinput_event_get_touch_event(event));
 		break;
+	case LIBINPUT_EVENT_TABLET_PROXIMITY:
+		handle_tablet_proximity(libinput_device,
+					libinput_event_get_tablet_event(event));
+		break;
 	default:
 		handled = 0;
 		weston_log("unknown libinput event %d\n",
@@ -482,6 +572,115 @@ configure_device(struct evdev_device *device)
 	evdev_device_set_calibration(device);
 }
 
+static void
+bind_unbound_tablets(struct wl_listener *listener_base, void *data)
+{
+	struct tablet_output_listener *listener =
+		wl_container_of(listener_base, listener, base);
+	struct weston_tablet *tablet, *tmp;
+
+	wl_list_for_each_safe(tablet, tmp, &listener->tablet_list, link) {
+		if (tablet_bind_output(tablet, data)) {
+			wl_list_remove(&tablet->link);
+			wl_list_insert(&tablet->seat->tablet_list,
+				       &tablet->link);
+			tablet->device->seat_caps |= EVDEV_SEAT_TABLET;
+			notify_tablet_added(tablet);
+		}
+	}
+
+	if (wl_list_empty(&listener->tablet_list)) {
+		wl_list_remove(&listener_base->link);
+		free(listener);
+	}
+}
+
+static bool
+tablet_bind_output(struct weston_tablet *tablet, struct weston_output *output)
+{
+	struct wl_list *output_list = &tablet->seat->compositor->output_list;
+	struct weston_compositor *compositor = tablet->seat->compositor;
+	struct tablet_output_listener *listener;
+	struct wl_listener *listener_base;
+
+	/* TODO: Properly bind tablets with built-in displays */
+	switch (tablet->type) {
+		case ZWP_TABLET1_TYPE_EXTERNAL:
+		case ZWP_TABLET1_TYPE_INTERNAL:
+		case ZWP_TABLET1_TYPE_DISPLAY:
+			if (output) {
+				tablet->output = output;
+			} else {
+				if (wl_list_empty(output_list))
+					break;
+
+				/* Find the first available display */
+				wl_list_for_each(output, output_list, link)
+					break;
+				tablet->output = output;
+			}
+		break;
+	}
+
+	if (tablet->output)
+		return true;
+
+	listener_base = wl_signal_get(&compositor->output_created_signal,
+				      bind_unbound_tablets);
+	if (listener_base == NULL) {
+		listener = zalloc(sizeof(*listener));
+
+		wl_list_init(&listener->tablet_list);
+
+		listener_base = &listener->base;
+		listener_base->notify = bind_unbound_tablets;
+
+		wl_signal_add(&compositor->output_created_signal,
+			      listener_base);
+	} else {
+		listener = wl_container_of(listener_base, listener, base);
+	}
+
+	wl_list_insert(&listener->tablet_list, &tablet->link);
+	return false;
+}
+
+static void
+evdev_device_init_tablet(struct evdev_device *device,
+			 struct libinput_device *libinput_device,
+			 struct weston_seat *seat)
+{
+	struct weston_tablet *tablet;
+	struct udev_device *udev_device;
+
+	tablet = weston_seat_add_tablet(seat);
+	tablet->name = strdup(libinput_device_get_name(libinput_device));
+	tablet->vid = libinput_device_get_id_vendor(libinput_device);
+	tablet->pid = libinput_device_get_id_product(libinput_device);
+
+	/* FIXME: we need libwacom to get this information */
+	tablet->type = ZWP_TABLET1_TYPE_EXTERNAL;
+
+	udev_device = libinput_device_get_udev_device(libinput_device);
+	if (udev_device) {
+		tablet->path = udev_device_get_devnode(udev_device);
+		udev_device_unref(udev_device);
+	}
+
+	/* If we can successfully bind the tablet to an output, then
+	 * it's ready to get added to the seat's tablet list, otherwise
+	 * it will get added when an appropriate output is available */
+	if (tablet_bind_output(tablet, NULL)) {
+		wl_list_insert(&seat->tablet_list, &tablet->link);
+		device->seat_caps |= EVDEV_SEAT_TABLET;
+
+		notify_tablet_added(tablet);
+	}
+
+	device->tablet = tablet;
+	tablet->device = device;
+}
+
 struct evdev_device *
 evdev_device_create(struct libinput_device *libinput_device,
 		    struct weston_seat *seat)
@@ -511,6 +710,10 @@ evdev_device_create(struct libinput_device *libinput_device,
 		weston_seat_init_touch(seat);
 		device->seat_caps |= EVDEV_SEAT_TOUCH;
 	}
+	if (libinput_device_has_capability(libinput_device,
+					   LIBINPUT_DEVICE_CAP_TABLET)) {
+		evdev_device_init_tablet(device, libinput_device, seat);
+	}
 
 	libinput_device_set_user_data(libinput_device, device);
 	libinput_device_ref(libinput_device);
@@ -529,6 +732,8 @@ evdev_device_destroy(struct evdev_device *device)
 		weston_seat_release_keyboard(device->seat);
 	if (device->seat_caps & EVDEV_SEAT_TOUCH)
 		weston_seat_release_touch(device->seat);
+	if (device->seat_caps & EVDEV_SEAT_TABLET)
+		weston_seat_release_tablet(device->tablet);
 
 	if (device->output)
 		wl_list_remove(&device->output_destroy_listener.link);
diff --git a/src/libinput-device.h b/src/libinput-device.h
index a3848ca..e082291 100644
--- a/src/libinput-device.h
+++ b/src/libinput-device.h
@@ -37,7 +37,8 @@
 enum evdev_device_seat_capability {
 	EVDEV_SEAT_POINTER = (1 << 0),
 	EVDEV_SEAT_KEYBOARD = (1 << 1),
-	EVDEV_SEAT_TOUCH = (1 << 2)
+	EVDEV_SEAT_TOUCH = (1 << 2),
+	EVDEV_SEAT_TABLET = (1 << 3)
 };
 
 struct evdev_device {
@@ -47,6 +48,7 @@ struct evdev_device {
 	struct wl_list link;
 	struct weston_output *output;
 	struct wl_listener output_destroy_listener;
+	struct weston_tablet *tablet;
 	char *devnode;
 	char *output_name;
 	int fd;
-- 
2.4.3



More information about the wayland-devel mailing list