[PATCH weston 02/19] tablet: Add initial tablet support to weston

Stephen Chandler Paul thatslyude at gmail.com
Wed Aug 6 16:07:52 PDT 2014


This only adds support for reporting motion events, proximity_in events
(without the tool object information), proximity_out events and frame
events.

Signed-off-by: Stephen Chandler Paul <thatslyude at gmail.com>
---
 src/compositor.h      |  97 ++++++++++++++++
 src/input.c           | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/libinput-device.c | 160 ++++++++++++++++++++++++++
 src/libinput-device.h |   4 +-
 4 files changed, 572 insertions(+), 1 deletion(-)

diff --git a/src/compositor.h b/src/compositor.h
index 102cfa7..f0f4e90 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -33,6 +33,7 @@ extern "C" {
 
 #define WL_HIDE_DEPRECATED
 #include <wayland-server.h>
+#include <wayland-tablet-server-protocol.h>
 
 #include "version.h"
 #include "matrix.h"
@@ -288,6 +289,45 @@ struct weston_touch_grab {
 	struct weston_touch *touch;
 };
 
+struct weston_tablet_tool;
+struct weston_tablet_grab;
+struct weston_tablet_grab_interface {
+	void (*proximity_in)(struct weston_tablet_grab *grab,
+			     uint32_t time,
+			     struct weston_tablet_tool *tool);
+	void (*proximity_out)(struct weston_tablet_grab *grab,
+			      uint32_t time);
+	void (*motion)(struct weston_tablet_grab *grab,
+		       uint32_t time,
+		       wl_fixed_t x,
+		       wl_fixed_t y);
+	void (*down)(struct weston_tablet_grab *grab,
+		     uint32_t time);
+	void (*up)(struct weston_tablet_grab *grab,
+		   uint32_t time);
+	void (*pressure)(struct weston_tablet_grab *grab,
+			 uint32_t time,
+			 wl_fixed_t pressure);
+	void (*distance)(struct weston_tablet_grab *grab,
+			 uint32_t time,
+			 wl_fixed_t distance);
+	void (*tilt)(struct weston_tablet_grab *grab,
+		     uint32_t time,
+		     wl_fixed_t tilt_x,
+		     wl_fixed_t tilt_y);
+	void (*button)(struct weston_tablet_grab *grab,
+		       uint32_t time,
+		       uint32_t button,
+		       enum wl_tablet_button_state state);
+	void (*frame)(struct weston_tablet_grab *grab);
+	void (*cancel)(struct weston_tablet_grab *grab);
+};
+
+struct weston_tablet_grab {
+	const struct weston_tablet_grab_interface *interface;
+	struct weston_tablet *tablet;
+};
+
 struct weston_data_offer {
 	struct wl_resource *resource;
 	struct weston_data_source *source;
@@ -358,6 +398,31 @@ struct weston_touch {
 	uint32_t grab_time;
 };
 
+struct weston_tablet {
+	struct weston_seat *seat;
+	struct evdev_device *device;
+
+	struct wl_list resource_list;
+	struct wl_list focus_resource_list;
+	struct weston_view *focus;
+	struct wl_listener focus_view_listener;
+	struct wl_listener focus_resource_listener;
+	uint32_t focus_serial;
+
+	wl_fixed_t x, y;
+
+	struct weston_tablet_grab *grab;
+	struct weston_tablet_grab default_grab;
+
+	struct wl_list link;
+
+	char *name;
+	enum wl_tablet_manager_tablet_type type;
+	uint32_t vid;
+	uint32_t pid;
+	struct weston_output *output;
+};
+
 struct weston_pointer *
 weston_pointer_create(struct weston_seat *seat);
 void
@@ -407,6 +472,19 @@ 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);
+void
+weston_tablet_set_focus(struct weston_tablet *tablet, struct weston_view *view,
+			uint32_t time);
+void
+weston_tablet_start_grab(struct weston_tablet *device,
+			 struct weston_tablet_grab *grab);
+void
+weston_tablet_end_grab(struct weston_tablet *tablet);
+
 void
 wl_data_device_set_keyboard_focus(struct weston_seat *seat);
 
@@ -490,9 +568,11 @@ struct weston_seat {
 	struct weston_pointer *pointer;
 	struct weston_keyboard *keyboard;
 	struct weston_touch *touch;
+	struct wl_list tablet_list;
 	int pointer_device_count;
 	int keyboard_device_count;
 	int touch_device_count;
+	int tablet_device_count;
 
 	struct weston_output *output; /* constraint */
 
@@ -511,6 +591,9 @@ struct weston_seat {
 	struct wl_listener selection_data_source_listener;
 	struct wl_signal selection_signal;
 
+	struct wl_global *tablet_manager;
+	struct wl_list tablet_manager_resource_list;
+
 	void (*led_update)(struct weston_seat *ws, enum weston_led leds);
 
 	uint32_t slot_map;
@@ -1006,6 +1089,16 @@ void
 notify_touch_frame(struct weston_seat *seat);
 
 void
+notify_tablet_added(struct weston_tablet *tablet);
+void
+notify_tablet_proximity_out(struct weston_tablet *tablet, uint32_t time);
+void
+notify_tablet_motion(struct weston_tablet *tablet, uint32_t time,
+		     wl_fixed_t x, wl_fixed_t y);
+void
+notify_tablet_frame(struct weston_tablet *tablet);
+
+void
 weston_layer_entry_insert(struct weston_layer_entry *list,
 			  struct weston_layer_entry *entry);
 void
@@ -1257,6 +1350,10 @@ 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);
+void
+weston_seat_release_tablet(struct weston_tablet *tablet);
 void
 weston_seat_repick(struct weston_seat *seat);
 void
diff --git a/src/input.c b/src/input.c
index aaa2223..8a97632 100644
--- a/src/input.c
+++ b/src/input.c
@@ -122,6 +122,26 @@ touch_focus_resource_destroyed(struct wl_listener *listener, void *data)
 }
 
 static void
+tablet_focus_view_destroyed(struct wl_listener *listener, void *data)
+{
+	struct weston_tablet *tablet =
+		container_of(listener, struct weston_tablet,
+			     focus_view_listener);
+
+	weston_tablet_set_focus(tablet, NULL, 0);
+}
+
+static void
+tablet_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+	struct weston_tablet *tablet =
+		container_of(listener, struct weston_tablet,
+			     focus_resource_listener);
+
+	weston_tablet_set_focus(tablet, NULL, 0);
+}
+
+static void
 move_resources(struct wl_list *destination, struct wl_list *source)
 {
 	wl_list_insert_list(destination, source);
@@ -421,6 +441,66 @@ static const struct weston_keyboard_grab_interface
 };
 
 static void
+default_grab_tablet_proximity_out(struct weston_tablet_grab *grab,
+				  uint32_t time)
+{
+	weston_tablet_set_focus(grab->tablet, NULL, time);
+}
+
+static void
+default_grab_tablet_motion(struct weston_tablet_grab *grab,
+			   uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+	struct weston_tablet *tablet = grab->tablet;
+	struct weston_view *current_view;
+	wl_fixed_t sx, sy;
+	struct wl_resource *resource;
+	struct wl_list *resource_list = &tablet->focus_resource_list;
+
+	current_view = weston_compositor_pick_view(tablet->seat->compositor,
+						   x, y, &sx, &sy);
+	if (current_view != tablet->focus)
+		weston_tablet_set_focus(tablet, current_view, time);
+
+	if (!wl_list_empty(resource_list)) {
+		wl_resource_for_each(resource, resource_list)
+			wl_tablet_send_motion(resource, time, sx, sy);
+	}
+}
+
+static void
+default_grab_tablet_frame(struct weston_tablet_grab *grab)
+{
+	struct wl_resource *resource;
+	struct wl_list *resource_list = &grab->tablet->focus_resource_list;
+
+	if (!wl_list_empty(resource_list)) {
+		wl_resource_for_each(resource, resource_list)
+			wl_tablet_send_frame(resource);
+	}
+}
+
+static void
+default_grab_tablet_cancel(struct weston_tablet_grab *grab)
+{
+
+}
+
+static struct weston_tablet_grab_interface default_tablet_grab_interface = {
+	NULL,
+	default_grab_tablet_proximity_out,
+	default_grab_tablet_motion,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	default_grab_tablet_frame,
+	default_grab_tablet_cancel,
+};
+
+static void
 pointer_unmap_sprite(struct weston_pointer *pointer)
 {
 	if (weston_surface_is_mapped(pointer->sprite->surface))
@@ -597,6 +677,90 @@ 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);
+	wl_list_init(&tablet->focus_resource_list);
+	wl_list_init(&tablet->focus_view_listener.link);
+	tablet->focus_view_listener.notify = tablet_focus_view_destroyed;
+	wl_list_init(&tablet->focus_resource_listener.link);
+	tablet->focus_resource_listener.notify = tablet_focus_resource_destroyed;
+	tablet->default_grab.interface = &default_tablet_grab_interface;
+	tablet->default_grab.tablet = tablet;
+	tablet->grab = &tablet->default_grab;
+
+	return tablet;
+}
+
+WL_EXPORT void
+weston_tablet_destroy(struct weston_tablet *tablet)
+{
+	free(tablet->name);
+
+	wl_list_remove(&tablet->focus_view_listener.link);
+	wl_list_remove(&tablet->focus_resource_listener.link);
+
+	free(tablet);
+}
+
+WL_EXPORT void
+weston_tablet_set_focus(struct weston_tablet *tablet, struct weston_view *view,
+			uint32_t time)
+{
+	struct wl_list *focus_resource_list;
+	struct wl_resource *resource;
+	struct weston_seat *seat = tablet->seat;
+
+	focus_resource_list = &tablet->focus_resource_list;
+
+	if (tablet->focus && !wl_list_empty(focus_resource_list)) {
+		wl_resource_for_each(resource, focus_resource_list) {
+			wl_tablet_send_proximity_out(resource, time);
+			wl_tablet_send_frame(resource);
+		}
+
+		move_resources(&tablet->resource_list, focus_resource_list);
+	}
+
+	if (find_resource_for_view(&tablet->resource_list, view)) {
+		struct wl_client *surface_client =
+			wl_resource_get_client(view->surface->resource);
+
+		move_resources_for_client(focus_resource_list,
+					  &tablet->resource_list,
+					  surface_client);
+		tablet->focus_serial =
+			wl_display_next_serial(seat->compositor->wl_display);
+
+		wl_resource_for_each(resource, focus_resource_list)
+			wl_tablet_send_proximity_in(resource,
+						    tablet->focus_serial,
+						    time, NULL,
+						    view->surface->resource);
+	}
+
+	wl_list_remove(&tablet->focus_view_listener.link);
+	wl_list_init(&tablet->focus_view_listener.link);
+	wl_list_remove(&tablet->focus_resource_listener.link);
+	wl_list_init(&tablet->focus_resource_listener.link);
+	if (view)
+		wl_signal_add(&view->destroy_signal,
+			      &tablet->focus_view_listener);
+	if (view && view->surface->resource)
+		wl_resource_add_destroy_listener(view->surface->resource,
+						 &tablet->focus_resource_listener);
+
+	tablet->focus = view;
+	tablet->focus_view_listener.notify = tablet_focus_view_destroyed;
+}
+
 static void
 seat_send_updated_caps(struct weston_seat *seat)
 {
@@ -1531,6 +1695,60 @@ notify_touch_frame(struct weston_seat *seat)
 	grab->interface->frame(grab);
 }
 
+static const struct wl_tablet_interface tablet_interface;
+
+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_manager_resource_list) {
+		struct wl_resource *tablet_resource =
+			wl_resource_create(wl_resource_get_client(resource),
+					   &wl_tablet_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);
+		wl_tablet_manager_send_device_added(resource, tablet_resource,
+						    tablet->name, tablet->vid,
+						    tablet->pid, 0, 0);
+	}
+}
+
+WL_EXPORT void
+notify_tablet_proximity_out(struct weston_tablet *tablet, uint32_t time)
+{
+	struct weston_tablet_grab *grab = tablet->grab;
+
+	grab->interface->proximity_out(grab, time);
+}
+
+WL_EXPORT void
+notify_tablet_motion(struct weston_tablet *tablet, uint32_t time,
+		     wl_fixed_t x, wl_fixed_t y)
+{
+	struct weston_tablet_grab *grab = tablet->grab;
+
+	weston_compositor_wake(tablet->seat->compositor);
+	grab->interface->motion(grab, time, x, y);
+}
+
+WL_EXPORT void
+notify_tablet_frame(struct weston_tablet *tablet)
+{
+	struct weston_tablet_grab *grab = tablet->grab;
+
+	grab->interface->frame(grab);
+}
+
 static void
 pointer_cursor_surface_configure(struct weston_surface *es,
 				 int32_t dx, int32_t dy)
@@ -1809,6 +2027,16 @@ static const struct wl_seat_interface seat_interface = {
 };
 
 static void
+tablet_release(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct wl_tablet_interface tablet_interface = {
+	tablet_release,
+};
+
+static void
 bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 {
 	struct weston_seat *seat = data;
@@ -1833,6 +2061,44 @@ bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 		wl_seat_send_name(resource, seat->seat_name);
 }
 
+static void
+bind_tablet_manager(struct wl_client *client, void *data, uint32_t version,
+		    uint32_t id)
+{
+	struct weston_seat *seat = data;
+	struct wl_resource *seat_resource =
+		wl_resource_find_for_client(&seat->base_resource_list, client);
+	struct wl_resource *resource;
+	struct weston_tablet *tablet;
+
+	resource = wl_resource_create(client, &wl_tablet_manager_interface,
+				      MIN(version, 1), id);
+	wl_resource_set_implementation(resource, NULL, data, unbind_resource);
+	wl_list_insert(&seat->tablet_manager_resource_list,
+		       wl_resource_get_link(resource));
+
+	/* Notify the client of the wl_seat object we're associated with */
+	wl_tablet_manager_send_seat(resource, seat_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, &wl_tablet_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));
+
+		wl_tablet_manager_send_device_added(resource, tablet_resource,
+						    tablet->name, tablet->vid,
+						    tablet->pid, 0, 0);
+	}
+}
+
 #ifdef ENABLE_XKBCOMMON
 int
 weston_compositor_xkb_init(struct weston_compositor *ec,
@@ -2185,6 +2451,42 @@ 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;
+
+	seat->tablet_device_count++;
+	if (seat->tablet_device_count == 1)
+		seat_send_updated_caps(seat);
+
+	tablet = weston_tablet_create();
+	if (tablet == NULL)
+		return NULL;
+
+	tablet->seat = seat;
+
+	return tablet;
+}
+
+WL_EXPORT void
+weston_seat_release_tablet(struct weston_tablet *tablet)
+{
+	struct wl_resource *resource;
+
+	weston_tablet_set_focus(tablet, NULL, 0);
+	wl_resource_for_each(resource, &tablet->resource_list)
+		wl_tablet_send_removed(resource);
+
+	tablet->seat->tablet_device_count--;
+	wl_list_remove(&tablet->link);
+
+	if (tablet->seat->tablet_device_count == 0)
+		seat_send_updated_caps(tablet->seat);
+
+	weston_tablet_destroy(tablet);
+}
+
 WL_EXPORT void
 weston_seat_release_touch(struct weston_seat *seat)
 {
@@ -2209,9 +2511,14 @@ 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_list);
+	wl_list_init(&seat->tablet_manager_resource_list);
 
 	seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 4,
 					seat, bind_seat);
+	seat->tablet_manager = wl_global_create(ec->wl_display,
+						&wl_tablet_manager_interface,
+						1, seat, bind_tablet_manager);
 
 	seat->compositor = ec;
 	seat->modifier_state = 0;
@@ -2227,6 +2534,8 @@ 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;
+
 	wl_list_remove(&seat->link);
 
 	if (seat->saved_kbd_focus)
@@ -2238,10 +2547,13 @@ weston_seat_release(struct weston_seat *seat)
 		weston_keyboard_destroy(seat->keyboard);
 	if (seat->touch)
 		weston_touch_destroy(seat->touch);
+	wl_list_for_each(tablet, &seat->tablet_list, link)
+		weston_tablet_destroy(tablet);
 
 	free (seat->seat_name);
 
 	wl_global_destroy(seat->global);
+	wl_global_destroy(seat->tablet_manager);
 
 	wl_signal_emit(&seat->destroy_signal, seat);
 }
diff --git a/src/libinput-device.c b/src/libinput-device.c
index 2ba4ec3..f5ed2a0 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -38,6 +38,14 @@
 
 #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
 
+struct tablet_output_listener {
+	struct wl_listener base;
+	struct wl_list tablet_list;
+};
+
+static int
+tablet_bind_output(struct weston_tablet *tablet, struct weston_output *output);
+
 void
 evdev_led_update(struct evdev_device *device, enum weston_led weston_leds)
 {
@@ -210,6 +218,51 @@ handle_touch_frame(struct libinput_device *libinput_device,
 	notify_touch_frame(seat);
 }
 
+static void
+handle_tablet_axis(struct libinput_device *libinput_device,
+		   struct libinput_event_tablet *axis_event)
+{
+	struct evdev_device *device =
+		libinput_device_get_user_data(libinput_device);
+	struct weston_tablet *tablet = device->tablet;
+
+	if (libinput_event_tablet_axis_has_changed(axis_event,
+						   LIBINPUT_TABLET_AXIS_X) ||
+	    libinput_event_tablet_axis_has_changed(axis_event,
+						   LIBINPUT_TABLET_AXIS_Y)) {
+		double x, y;
+		uint32_t width, height,
+			 time;
+
+		time = libinput_event_tablet_get_time(axis_event);
+
+		width = tablet->output->current_mode->width;
+		height = tablet->output->current_mode->height;
+		x = libinput_event_tablet_get_x_transformed(axis_event, width);
+		y = libinput_event_tablet_get_y_transformed(axis_event, height);
+
+		notify_tablet_motion(tablet, time,
+				     wl_fixed_from_double(x),
+				     wl_fixed_from_double(y));
+	}
+
+	notify_tablet_frame(tablet);
+}
+
+static void
+handle_tablet_proximity_out(struct libinput_device *libinput_device,
+			    struct libinput_event_tablet *proximity_out_event)
+{
+	struct evdev_device *device =
+		libinput_device_get_user_data(libinput_device);
+	struct weston_tablet *tablet = device->tablet;
+	uint32_t time;
+
+	time = libinput_event_tablet_get_time(proximity_out_event);
+
+	notify_tablet_proximity_out(tablet, time);
+}
+
 int
 evdev_device_process_event(struct libinput_event *event)
 {
@@ -255,6 +308,15 @@ evdev_device_process_event(struct libinput_event *event)
 		handle_touch_frame(libinput_device,
 				   libinput_event_get_touch_event(event));
 		break;
+	case LIBINPUT_EVENT_TABLET_AXIS:
+		handle_tablet_axis(libinput_device,
+				   libinput_event_get_tablet_event(event));
+		break;
+	case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
+		handle_tablet_proximity_out(
+		    libinput_device,
+		    libinput_event_get_tablet_event(event));
+		break;
 	default:
 		handled = 0;
 		weston_log("unknown libinput event %d\n",
@@ -297,6 +359,81 @@ evdev_device_set_output(struct evdev_device *device,
 		      &device->output_destroy_listener);
 }
 
+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 int
+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;
+
+	/* TODO: Properly bind tablets with built-in displays */
+	switch (tablet->type) {
+		case WL_TABLET_MANAGER_TABLET_TYPE_EXTERNAL:
+		case WL_TABLET_MANAGER_TABLET_TYPE_INTERNAL:
+		case WL_TABLET_MANAGER_TABLET_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;
+			}
+	}
+
+	if (!tablet->output) {
+		struct tablet_output_listener *listener;
+		struct wl_listener *listener_base;
+
+		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 0;
+	}
+
+	return 1;
+}
+
 struct evdev_device *
 evdev_device_create(struct libinput_device *libinput_device,
 		    struct weston_seat *seat)
@@ -326,6 +463,27 @@ 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)) {
+		struct weston_tablet *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);
+
+		/* 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;
+	}
 
 	libinput_device_set_user_data(libinput_device, device);
 	libinput_device_ref(libinput_device);
@@ -342,6 +500,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 0775743..02a2095 100644
--- a/src/libinput-device.h
+++ b/src/libinput-device.h
@@ -34,7 +34,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 {
@@ -44,6 +45,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;
-- 
1.8.5.5



More information about the wayland-devel mailing list