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 <[email protected]>
---
 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

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to