xserver: Branch 'master' - 9 commits

Peter Hutterer whot at kemper.freedesktop.org
Fri Apr 28 02:55:58 UTC 2017


 configure.ac                  |    2 
 hw/xwayland/Makefile.am       |    9 
 hw/xwayland/meson.build       |    3 
 hw/xwayland/xwayland-cursor.c |   95 ++-
 hw/xwayland/xwayland-input.c  | 1111 +++++++++++++++++++++++++++++++++++++++++-
 hw/xwayland/xwayland.c        |    2 
 hw/xwayland/xwayland.h        |   85 +++
 meson.build                   |    2 
 8 files changed, 1277 insertions(+), 32 deletions(-)

New commits:
commit 8475e6360ce31551d50fd63a26f7a44d1e8928f2
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Feb 7 15:04:46 2017 +1000

    xwayland: add tablet pad support
    
    Hooked up a bit differently to the other tools. Those tools can be static for
    all and be re-used. The wacom driver initializes the pad with the correct
    number of buttons though and we can't do this until we have the pad done event.
    
    If the tablet is removed and we plug a different one in, we should initialize
    that correctly, so unlike the other tools the pad is properly removed and
    re-initialized on plug.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index e80b94e08..bb667c441 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1335,6 +1335,7 @@ tablet_handle_removed(void *data, struct zwp_tablet_v2 *tablet)
             DisableDevice(xwl_seat->eraser, TRUE);
         if (xwl_seat->puck)
             DisableDevice(xwl_seat->puck, TRUE);
+        /* pads are removed separately */
     }
 
     zwp_tablet_v2_destroy(tablet);
@@ -1695,6 +1696,418 @@ static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
 };
 
 static void
+tablet_pad_ring_destroy(struct xwl_tablet_pad_ring *ring)
+{
+    zwp_tablet_pad_ring_v2_destroy(ring->ring);
+    xorg_list_del(&ring->link);
+    free(ring);
+}
+
+static void
+tablet_pad_ring_source(void *data,
+                       struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
+                       uint32_t source)
+{
+}
+
+static void
+tablet_pad_ring_angle(void *data,
+                      struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
+                      wl_fixed_t degrees)
+{
+    struct xwl_tablet_pad_ring *ring = data;
+    struct xwl_tablet_pad *pad = ring->group->pad;
+    double deg = wl_fixed_to_double(degrees);
+    ValuatorMask mask;
+
+    valuator_mask_zero(&mask);
+    valuator_mask_set(&mask, 5 + ring->index, deg/360.0  * 71);
+    QueuePointerEvents(pad->xdevice, MotionNotify, 0, 0, &mask);
+}
+
+static void
+tablet_pad_ring_stop(void *data,
+                     struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2)
+{
+}
+
+static void
+tablet_pad_ring_frame(void *data,
+                      struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
+                      uint32_t time)
+{
+}
+
+static const struct zwp_tablet_pad_ring_v2_listener tablet_pad_ring_listener = {
+    tablet_pad_ring_source,
+    tablet_pad_ring_angle,
+    tablet_pad_ring_stop,
+    tablet_pad_ring_frame,
+};
+
+
+static void
+tablet_pad_strip_destroy(struct xwl_tablet_pad_strip *strip)
+{
+    zwp_tablet_pad_strip_v2_destroy(strip->strip);
+    xorg_list_del(&strip->link);
+    free(strip);
+}
+
+static void
+tablet_pad_strip_source(void *data,
+                        struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
+                        uint32_t source)
+{
+}
+
+static void
+tablet_pad_strip_position(void *data,
+                          struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
+                          uint32_t position)
+{
+    struct xwl_tablet_pad_strip *strip = data;
+    struct xwl_tablet_pad *pad = strip->group->pad;
+    ValuatorMask mask;
+
+    valuator_mask_zero(&mask);
+    valuator_mask_set(&mask, 3 + strip->index, position/65535.0 * 2048);
+    QueuePointerEvents(pad->xdevice, MotionNotify, 0, 0, &mask);
+}
+
+static void
+tablet_pad_strip_stop(void *data,
+                      struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2)
+{
+}
+
+static void
+tablet_pad_strip_frame(void *data,
+                       struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
+                       uint32_t time)
+{
+}
+
+static const struct zwp_tablet_pad_strip_v2_listener tablet_pad_strip_listener = {
+    tablet_pad_strip_source,
+    tablet_pad_strip_position,
+    tablet_pad_strip_stop,
+    tablet_pad_strip_frame,
+};
+
+static void
+tablet_pad_group_destroy(struct xwl_tablet_pad_group *group)
+{
+    struct xwl_tablet_pad_ring *r, *tr;
+    struct xwl_tablet_pad_strip *s, *ts;
+
+    xorg_list_for_each_entry_safe(r, tr,
+                                  &group->pad_group_ring_list,
+                                  link)
+        tablet_pad_ring_destroy(r);
+
+    xorg_list_for_each_entry_safe(s, ts,
+                                  &group->pad_group_strip_list,
+                                  link)
+        tablet_pad_strip_destroy(s);
+
+    zwp_tablet_pad_group_v2_destroy(group->group);
+    xorg_list_del(&group->link);
+    free(group);
+}
+
+static void
+tablet_pad_group_buttons(void *data,
+                         struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,
+                         struct wl_array *buttons)
+{
+
+}
+
+static void
+tablet_pad_group_ring(void *data,
+                      struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,
+                      struct zwp_tablet_pad_ring_v2 *wp_ring)
+{
+    static unsigned int ring_index = 0;
+    struct xwl_tablet_pad_group *group = data;
+    struct xwl_tablet_pad_ring *ring;
+
+    ring = calloc(1, sizeof *ring);
+    if (ring == NULL) {
+        ErrorF("%s ENOMEM\n", __func__);
+        return;
+    }
+
+    ring->index = ring_index++;
+    ring->group = group;
+    ring->ring = wp_ring;
+
+    xorg_list_add(&ring->link, &group->pad_group_ring_list);
+
+    zwp_tablet_pad_ring_v2_add_listener(wp_ring, &tablet_pad_ring_listener,
+                                        ring);
+}
+
+static void
+tablet_pad_group_strip(void *data,
+                       struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,
+                       struct zwp_tablet_pad_strip_v2 *wp_strip)
+{
+    static unsigned int strip_index = 0;
+    struct xwl_tablet_pad_group *group = data;
+    struct xwl_tablet_pad_strip *strip;
+
+    strip = calloc(1, sizeof *strip);
+    if (strip == NULL) {
+        ErrorF("%s ENOMEM\n", __func__);
+        return;
+    }
+
+    strip->index = strip_index++;
+    strip->group = group;
+    strip->strip = wp_strip;
+
+    xorg_list_add(&strip->link, &group->pad_group_strip_list);
+
+    zwp_tablet_pad_strip_v2_add_listener(wp_strip, &tablet_pad_strip_listener,
+                                         strip);
+}
+
+static void
+tablet_pad_group_modes(void *data,
+                       struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,
+                       uint32_t modes)
+{
+
+}
+
+static void
+tablet_pad_group_done(void *data,
+                      struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2)
+{
+
+}
+
+static void
+tablet_pad_group_mode_switch(void *data,
+                             struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,
+                             uint32_t time,
+                             uint32_t serial,
+                             uint32_t mode)
+{
+
+}
+
+static struct zwp_tablet_pad_group_v2_listener tablet_pad_group_listener = {
+    tablet_pad_group_buttons,
+    tablet_pad_group_ring,
+    tablet_pad_group_strip,
+    tablet_pad_group_modes,
+    tablet_pad_group_done,
+    tablet_pad_group_mode_switch,
+};
+
+static int
+xwl_tablet_pad_proc(DeviceIntPtr device, int what)
+{
+    struct xwl_tablet_pad *pad = device->public.devicePrivate;
+    /* Axis layout mirrors that of xf86-input-wacom to have better
+       compatibility with existing clients */
+#define NAXES 7
+    Atom axes_labels[NAXES] = { 0 };
+    BYTE map[MAX_BUTTONS + 1];
+    int i = 0;
+    Atom btn_labels[MAX_BUTTONS] = { 0 }; /* btn labels are meaningless */
+    int nbuttons;
+
+    switch (what) {
+    case DEVICE_INIT:
+        device->public.on = FALSE;
+
+        axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
+        axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
+        /* The others have no good mapping */
+
+        if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels,
+                                           GetMotionHistorySize(), Absolute))
+            return BadValue;
+
+        for (i = 1; i <= MAX_BUTTONS; i++)
+            map[i] = i;
+
+        /* We need at least 7 buttons to allow scrolling */
+        nbuttons = min(max(pad->nbuttons + 4, 7), MAX_BUTTONS);
+
+        if (!InitButtonClassDeviceStruct(device, nbuttons,
+                                         btn_labels, map))
+            return BadValue;
+
+        /* Valuators */
+        InitValuatorAxisStruct(device, 0, axes_labels[0],
+                               0, 100, 1, 0, 1, Absolute);
+        InitValuatorAxisStruct(device, 1, axes_labels[1],
+                               0, 100, 1, 0, 1, Absolute);
+        /* Pressure - unused, for backwards compat only */
+        InitValuatorAxisStruct(device, 2, axes_labels[2],
+                               0, 2048, 1, 0, 1, Absolute);
+        /* strip x */
+        InitValuatorAxisStruct(device, 3, axes_labels[3],
+                               0, 2048, 1, 0, 1, Absolute);
+        /* strip y */
+        InitValuatorAxisStruct(device, 4, axes_labels[4],
+                               0, 2048, 1, 0, 1, Absolute);
+        /* ring */
+        InitValuatorAxisStruct(device, 5, axes_labels[5],
+                               0, 71, 1, 0, 1, Absolute);
+        /* ring2 */
+        InitValuatorAxisStruct(device, 6, axes_labels[6],
+                               0, 71, 1, 0, 1, Absolute);
+
+        if (!InitPtrFeedbackClassDeviceStruct(device, xwl_pointer_control))
+            return BadValue;
+
+        return Success;
+
+    case DEVICE_ON:
+        device->public.on = TRUE;
+        return Success;
+
+    case DEVICE_OFF:
+    case DEVICE_CLOSE:
+        device->public.on = FALSE;
+        return Success;
+    }
+
+    return BadMatch;
+#undef NAXES
+}
+
+static void
+tablet_pad_group(void *data,
+                 struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
+                 struct zwp_tablet_pad_group_v2 *pad_group)
+{
+    struct xwl_tablet_pad *pad = data;
+    struct xwl_tablet_pad_group *group;
+
+    group = calloc(1, sizeof *group);
+    if (pad == NULL) {
+        ErrorF("%s ENOMEM\n", __func__);
+        return;
+    }
+
+    group->pad = pad;
+    group->group = pad_group;
+    xorg_list_init(&group->pad_group_ring_list);
+    xorg_list_init(&group->pad_group_strip_list);
+
+    xorg_list_add(&group->link, &pad->pad_group_list);
+
+    zwp_tablet_pad_group_v2_add_listener(pad_group,
+                                         &tablet_pad_group_listener,
+                                         group);
+}
+
+static void
+tablet_pad_path(void *data,
+                struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
+                const char *path)
+{
+
+}
+
+static void
+tablet_pad_buttons(void *data,
+                   struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
+                   uint32_t buttons)
+{
+    struct xwl_tablet_pad *pad = data;
+
+    pad->nbuttons = buttons;
+}
+
+static void
+tablet_pad_done(void *data,
+                struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2)
+{
+    struct xwl_tablet_pad *pad = data;
+
+    pad->xdevice = add_device(pad->seat, "xwayland-pad",
+                              xwl_tablet_pad_proc);
+    pad->xdevice->public.devicePrivate = pad;
+    ActivateDevice(pad->xdevice, TRUE);
+    EnableDevice(pad->xdevice, TRUE);
+}
+
+static void
+tablet_pad_button(void *data,
+                  struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
+                  uint32_t time,
+                  uint32_t button,
+                  uint32_t state)
+{
+    struct xwl_tablet_pad *pad = data;
+    ValuatorMask mask;
+
+    button++; /* wayland index vs X's 1-offset */
+    /* skip scroll wheel buttons 4-7 */
+    button = button > 3 ? button + 4 : button;
+
+    valuator_mask_zero(&mask);
+    QueuePointerEvents(pad->xdevice,
+                       state ? ButtonPress : ButtonRelease, button, 0, &mask);
+}
+
+static void
+tablet_pad_enter(void *data,
+                 struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
+                 uint32_t serial,
+                 struct zwp_tablet_v2 *tablet,
+                 struct wl_surface *surface)
+{
+    /* pairs the pad with the tablet but also to set the focus. We
+     * don't care about the pairing and always use X's focus */
+}
+
+static void
+tablet_pad_leave(void *data,
+                 struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
+                 uint32_t serial,
+                 struct wl_surface *surface)
+{
+    /* pairs the pad with the tablet but also to set the focus. We
+     * don't care about the pairing and always use X's focus */
+}
+
+static void
+tablet_pad_removed(void *data,
+                   struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2)
+{
+    struct xwl_tablet_pad *pad = data;
+    struct xwl_tablet_pad_group *g, *tg;
+
+    xorg_list_for_each_entry_safe(g, tg, &pad->pad_group_list, link)
+        tablet_pad_group_destroy(g);
+
+    RemoveDevice(pad->xdevice, TRUE);
+    xorg_list_del(&pad->link);
+    zwp_tablet_pad_v2_destroy(pad->pad);
+    free(pad);
+}
+
+static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = {
+    tablet_pad_group,
+    tablet_pad_path,
+    tablet_pad_buttons,
+    tablet_pad_done,
+    tablet_pad_button,
+    tablet_pad_enter,
+    tablet_pad_leave,
+    tablet_pad_removed,
+};
+
+static void
 tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
                               struct zwp_tablet_v2 *tablet)
 {
@@ -1763,8 +2176,12 @@ tablet_seat_handle_add_pad(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
 
     xwl_tablet_pad->pad = pad;
     xwl_tablet_pad->seat = xwl_seat;
+    xorg_list_init(&xwl_tablet_pad->pad_group_list);
 
     xorg_list_add(&xwl_tablet_pad->link, &xwl_seat->tablet_pads);
+
+    zwp_tablet_pad_v2_add_listener(pad, &tablet_pad_listener,
+                                   xwl_tablet_pad);
 }
 
 static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index e611c2995..b37e73b94 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -219,10 +219,38 @@ struct xwl_tablet_tool {
     struct xwl_cursor cursor;
 };
 
+struct xwl_tablet_pad_ring {
+    unsigned int index;
+    struct xorg_list link;
+    struct xwl_tablet_pad_group *group;
+    struct zwp_tablet_pad_ring_v2 *ring;
+};
+
+struct xwl_tablet_pad_strip {
+    unsigned int index;
+    struct xorg_list link;
+    struct xwl_tablet_pad_group *group;
+    struct zwp_tablet_pad_strip_v2 *strip;
+};
+
+struct xwl_tablet_pad_group {
+    struct xorg_list link;
+    struct xwl_tablet_pad *pad;
+    struct zwp_tablet_pad_group_v2 *group;
+
+    struct xorg_list pad_group_ring_list;
+    struct xorg_list pad_group_strip_list;
+};
+
 struct xwl_tablet_pad {
     struct xorg_list link;
     struct zwp_tablet_pad_v2 *pad;
     struct xwl_seat *seat;
+
+    DeviceIntPtr xdevice;
+
+    unsigned int nbuttons;
+    struct xorg_list pad_group_list;
 };
 
 struct xwl_output {
commit f471b5b8eb451b442554517c7cb6f0aa90d218c4
Author: Carlos Garnacho <carlosg at gnome.org>
Date:   Fri Nov 4 19:58:04 2016 +0100

    xwayland: update cursor on tablet tools in proximity
    
    Each xwl_tablet_tool gets a xwl_cursor, as on wayland each of those
    will get an independent cursor that can be set through
    zwp_tablet_tool.set_cursor.
    
    However, all tools (and the pointer) share conceptually the same VCP
    on Xwayland, so have cursor changes trigger a xwl_cursor update on
    every tool (and the pointer, again). Maybe Xwayland could keep track
    of the most recent device and only update that cursor to get better
    visual results, but this is simpler, and it's going to be odd
    anyway...
    
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index fdae3ce85..c95f4e830 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -175,11 +175,62 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
     wl_surface_commit(xwl_cursor->surface);
 }
 
+void
+xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
+{
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor;
+    PixmapPtr pixmap;
+    CursorPtr cursor;
+    int stride;
+
+    if (!xwl_seat->x_cursor) {
+        zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
+                                      xwl_tablet_tool->proximity_in_serial,
+                                      NULL, 0, 0);
+        return;
+    }
+
+    if (xwl_cursor->frame_cb) {
+        xwl_cursor->needs_update = TRUE;
+        return;
+    }
+
+    cursor = xwl_seat->x_cursor;
+    pixmap = dixGetPrivate(&cursor->devPrivates, &xwl_cursor_private_key);
+    if (!pixmap)
+        return;
+
+    stride = cursor->bits->width * 4;
+    if (cursor->bits->argb)
+        memcpy(pixmap->devPrivate.ptr,
+               cursor->bits->argb, cursor->bits->height * stride);
+    else
+        expand_source_and_mask(cursor, pixmap->devPrivate.ptr);
+
+    zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
+                                  xwl_tablet_tool->proximity_in_serial,
+                                  xwl_cursor->surface,
+                                  xwl_seat->x_cursor->bits->xhot,
+                                  xwl_seat->x_cursor->bits->yhot);
+    wl_surface_attach(xwl_cursor->surface,
+                      xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0);
+    wl_surface_damage(xwl_cursor->surface, 0, 0,
+                      xwl_seat->x_cursor->bits->width,
+                      xwl_seat->x_cursor->bits->height);
+
+    xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface);
+    wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor);
+
+    wl_surface_commit(xwl_cursor->surface);
+}
+
 static void
 xwl_set_cursor(DeviceIntPtr device,
                ScreenPtr screen, CursorPtr cursor, int x, int y)
 {
     struct xwl_seat *xwl_seat;
+    struct xwl_tablet_tool *xwl_tablet_tool;
     Bool cursor_visibility_changed;
 
     xwl_seat = device->public.devicePrivate;
@@ -194,6 +245,11 @@ xwl_set_cursor(DeviceIntPtr device,
         xwl_seat_cursor_visibility_changed(xwl_seat);
 
     xwl_seat_set_cursor(xwl_seat);
+
+    xorg_list_for_each_entry(xwl_tablet_tool, &xwl_seat->tablet_tools, link) {
+        if (xwl_tablet_tool->proximity_in_serial != 0)
+            xwl_tablet_tool_set_cursor(xwl_tablet_tool);
+    }
 }
 
 static void
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 93cf72109..e80b94e08 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1399,6 +1399,7 @@ tablet_tool_receive_removed(void *data, struct zwp_tablet_tool_v2 *tool)
     struct xwl_tablet_tool *xwl_tablet_tool = data;
 
     xorg_list_del(&xwl_tablet_tool->link);
+    xwl_cursor_release(&xwl_tablet_tool->cursor);
     zwp_tablet_tool_v2_destroy(tool);
     free(xwl_tablet_tool);
 }
@@ -1422,7 +1423,10 @@ tablet_tool_proximity_in(void *data, struct zwp_tablet_tool_v2 *tool,
     if (wl_surface == NULL)
         return;
 
+    xwl_tablet_tool->proximity_in_serial = serial;
     xwl_seat->focus_window = wl_surface_get_user_data(wl_surface);
+
+    xwl_tablet_tool_set_cursor(xwl_tablet_tool);
 }
 
 static void
@@ -1431,6 +1435,7 @@ tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *tool)
     struct xwl_tablet_tool *xwl_tablet_tool = data;
     struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
 
+    xwl_tablet_tool->proximity_in_serial = 0;
     xwl_seat->focus_window = NULL;
 
     xwl_tablet_tool->pressure = 0;
@@ -1711,10 +1716,20 @@ tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat
 }
 
 static void
+xwl_tablet_tool_update_cursor(struct xwl_cursor *xwl_cursor)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = wl_container_of(xwl_cursor,
+                                                              xwl_tablet_tool,
+                                                              cursor);
+    xwl_tablet_tool_set_cursor(xwl_tablet_tool);
+}
+
+static void
 tablet_seat_handle_add_tool(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
                             struct zwp_tablet_tool_v2 *tool)
 {
     struct xwl_seat *xwl_seat = data;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
     struct xwl_tablet_tool *xwl_tablet_tool;
 
     xwl_tablet_tool = calloc(sizeof *xwl_tablet_tool, 1);
@@ -1725,6 +1740,8 @@ tablet_seat_handle_add_tool(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
 
     xwl_tablet_tool->tool = tool;
     xwl_tablet_tool->seat = xwl_seat;
+    xwl_cursor_init(&xwl_tablet_tool->cursor, xwl_screen,
+                    xwl_tablet_tool_update_cursor);
 
     xorg_list_add(&xwl_tablet_tool->link, &xwl_seat->tablet_tools);
 
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index a152eab97..e611c2995 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -44,6 +44,7 @@
 
 #include "relative-pointer-unstable-v1-client-protocol.h"
 #include "pointer-constraints-unstable-v1-client-protocol.h"
+#include "tablet-unstable-v2-client-protocol.h"
 
 struct xwl_screen {
     int width;
@@ -203,6 +204,7 @@ struct xwl_tablet_tool {
     struct xwl_seat *seat;
 
     DeviceIntPtr xdevice;
+    uint32_t proximity_in_serial;
     uint32_t x;
     uint32_t y;
     uint32_t pressure;
@@ -213,6 +215,8 @@ struct xwl_tablet_tool {
 
     uint32_t buttons_now,
              buttons_prev;
+
+    struct xwl_cursor cursor;
 };
 
 struct xwl_tablet_pad {
@@ -240,6 +244,7 @@ Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen);
 
 struct xwl_screen *xwl_screen_get(ScreenPtr screen);
 
+void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool);
 void xwl_seat_set_cursor(struct xwl_seat *xwl_seat);
 
 void xwl_seat_destroy(struct xwl_seat *xwl_seat);
commit 6d1ad39fe6c18220dd39b0653fd1e4145140e2dc
Author: Carlos Garnacho <carlosg at gnome.org>
Date:   Fri Nov 4 19:36:10 2016 +0100

    xwayland: Refactor cursor management into xwl_cursor
    
    This struct takes away the cursor info in xwl_seat, and has
    an update function so we can share the frame handling code
    across several xwl_cursors.
    
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index f334f1ca5..fdae3ce85 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -96,11 +96,11 @@ xwl_unrealize_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor)
 }
 
 static void
-clear_cursor_frame_callback(struct xwl_seat *xwl_seat)
+clear_cursor_frame_callback(struct xwl_cursor *xwl_cursor)
 {
-   if (xwl_seat->cursor_frame_cb) {
-       wl_callback_destroy (xwl_seat->cursor_frame_cb);
-       xwl_seat->cursor_frame_cb = NULL;
+   if (xwl_cursor->frame_cb) {
+       wl_callback_destroy (xwl_cursor->frame_cb);
+       xwl_cursor->frame_cb = NULL;
    }
 }
 
@@ -109,12 +109,12 @@ frame_callback(void *data,
                struct wl_callback *callback,
                uint32_t time)
 {
-    struct xwl_seat *xwl_seat = data;
+    struct xwl_cursor *xwl_cursor = data;
 
-    clear_cursor_frame_callback(xwl_seat);
-    if (xwl_seat->cursor_needs_update) {
-        xwl_seat->cursor_needs_update = FALSE;
-        xwl_seat_set_cursor(xwl_seat);
+    clear_cursor_frame_callback(xwl_cursor);
+    if (xwl_cursor->needs_update) {
+        xwl_cursor->needs_update = FALSE;
+        xwl_cursor->update_proc(xwl_cursor);
     }
 }
 
@@ -125,6 +125,7 @@ static const struct wl_callback_listener frame_listener = {
 void
 xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
 {
+    struct xwl_cursor *xwl_cursor = &xwl_seat->cursor;
     PixmapPtr pixmap;
     CursorPtr cursor;
     int stride;
@@ -135,13 +136,13 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
     if (!xwl_seat->x_cursor) {
         wl_pointer_set_cursor(xwl_seat->wl_pointer,
                               xwl_seat->pointer_enter_serial, NULL, 0, 0);
-        clear_cursor_frame_callback(xwl_seat);
-        xwl_seat->cursor_needs_update = FALSE;
+        clear_cursor_frame_callback(xwl_cursor);
+        xwl_cursor->needs_update = FALSE;
         return;
     }
 
-    if (xwl_seat->cursor_frame_cb) {
-        xwl_seat->cursor_needs_update = TRUE;
+    if (xwl_cursor->frame_cb) {
+        xwl_cursor->needs_update = TRUE;
         return;
     }
 
@@ -159,19 +160,19 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
 
     wl_pointer_set_cursor(xwl_seat->wl_pointer,
                           xwl_seat->pointer_enter_serial,
-                          xwl_seat->cursor,
+                          xwl_cursor->surface,
                           xwl_seat->x_cursor->bits->xhot,
                           xwl_seat->x_cursor->bits->yhot);
-    wl_surface_attach(xwl_seat->cursor,
+    wl_surface_attach(xwl_cursor->surface,
                       xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0);
-    wl_surface_damage(xwl_seat->cursor, 0, 0,
+    wl_surface_damage(xwl_cursor->surface, 0, 0,
                       xwl_seat->x_cursor->bits->width,
                       xwl_seat->x_cursor->bits->height);
 
-    xwl_seat->cursor_frame_cb = wl_surface_frame(xwl_seat->cursor);
-    wl_callback_add_listener(xwl_seat->cursor_frame_cb, &frame_listener, xwl_seat);
+    xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface);
+    wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor);
 
-    wl_surface_commit(xwl_seat->cursor);
+    wl_surface_commit(xwl_cursor->surface);
 }
 
 static void
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 89b8f36bf..93cf72109 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -418,9 +418,9 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
      * of our surfaces might not have been shown. In that case we'll
      * have a cursor surface frame callback pending which we need to
      * clear so that we can continue submitting new cursor frames. */
-    if (xwl_seat->cursor_frame_cb) {
-        wl_callback_destroy(xwl_seat->cursor_frame_cb);
-        xwl_seat->cursor_frame_cb = NULL;
+    if (xwl_seat->cursor.frame_cb) {
+        wl_callback_destroy(xwl_seat->cursor.frame_cb);
+        xwl_seat->cursor.frame_cb = NULL;
         xwl_seat_set_cursor(xwl_seat);
     }
 
@@ -1197,6 +1197,31 @@ static const struct wl_seat_listener seat_listener = {
 };
 
 static void
+xwl_cursor_init(struct xwl_cursor *xwl_cursor, struct xwl_screen *xwl_screen,
+                void (* update_proc)(struct xwl_cursor *))
+{
+    xwl_cursor->surface = wl_compositor_create_surface(xwl_screen->compositor);
+    xwl_cursor->update_proc = update_proc;
+    xwl_cursor->frame_cb = NULL;
+    xwl_cursor->needs_update = FALSE;
+}
+
+static void
+xwl_cursor_release(struct xwl_cursor *xwl_cursor)
+{
+    wl_surface_destroy(xwl_cursor->surface);
+    if (xwl_cursor->frame_cb)
+        wl_callback_destroy(xwl_cursor->frame_cb);
+}
+
+static void
+xwl_seat_update_cursor(struct xwl_cursor *xwl_cursor)
+{
+    struct xwl_seat *xwl_seat = wl_container_of(xwl_cursor, xwl_seat, cursor);
+    xwl_seat_set_cursor(xwl_seat);
+}
+
+static void
 create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version)
 {
     struct xwl_seat *xwl_seat;
@@ -1215,7 +1240,8 @@ create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version
                          &wl_seat_interface, min(version, 5));
     xwl_seat->id = id;
 
-    xwl_seat->cursor = wl_compositor_create_surface(xwl_screen->compositor);
+    xwl_cursor_init(&xwl_seat->cursor, xwl_seat->xwl_screen,
+                    xwl_seat_update_cursor);
     wl_seat_add_listener(xwl_seat->seat, &seat_listener, xwl_seat);
 
     init_tablet_manager_seat(xwl_screen, xwl_seat);
@@ -1246,9 +1272,7 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
     release_tablet_manager_seat(xwl_seat);
 
     wl_seat_destroy(xwl_seat->seat);
-    wl_surface_destroy(xwl_seat->cursor);
-    if (xwl_seat->cursor_frame_cb)
-        wl_callback_destroy(xwl_seat->cursor_frame_cb);
+    xwl_cursor_release(&xwl_seat->cursor);
     wl_array_release(&xwl_seat->keys);
     free(xwl_seat);
 }
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 30088b03a..a152eab97 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -130,6 +130,13 @@ struct xwl_pointer_warp_emulator {
     struct zwp_locked_pointer_v1 *locked_pointer;
 };
 
+struct xwl_cursor {
+    void (* update_proc) (struct xwl_cursor *);
+    struct wl_surface *surface;
+    struct wl_callback *frame_cb;
+    Bool needs_update;
+};
+
 struct xwl_seat {
     DeviceIntPtr pointer;
     DeviceIntPtr relative_pointer;
@@ -151,9 +158,7 @@ struct xwl_seat {
     uint32_t pointer_enter_serial;
     struct xorg_list link;
     CursorPtr x_cursor;
-    struct wl_surface *cursor;
-    struct wl_callback *cursor_frame_cb;
-    Bool cursor_needs_update;
+    struct xwl_cursor cursor;
     WindowPtr last_xwindow;
 
     struct xorg_list touches;
commit 773b04748d0c839bc8b12e33f74bb8d11c447f5b
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Feb 7 12:23:46 2017 +1000

    xwayland: handle button events after motion events
    
    Make sure the button events are sent after the motion events into the new
    position.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 076da7923..89b8f36bf 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -34,6 +34,7 @@
 #include <inpututils.h>
 #include <mipointer.h>
 #include <mipointrst.h>
+#include <misc.h>
 #include "tablet-unstable-v2-client-protocol.h"
 
 struct sync_pending {
@@ -1537,8 +1538,8 @@ tablet_tool_button_state(void *data, struct zwp_tablet_tool_v2 *tool,
 {
     struct xwl_tablet_tool *xwl_tablet_tool = data;
     struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    uint32_t *mask = &xwl_tablet_tool->buttons_now;
     int xbtn = 0;
-    ValuatorMask mask;
 
     /* BTN_0 .. BTN_9 */
     if (button >= 0x100 && button <= 0x109) {
@@ -1586,11 +1587,14 @@ tablet_tool_button_state(void *data, struct zwp_tablet_tool_v2 *tool,
         return;
     }
 
-    xwl_seat->xwl_screen->serial = serial;
+    BUG_RETURN(xbtn >= 8 * sizeof(*mask));
 
-    valuator_mask_zero(&mask);
-    QueuePointerEvents(xwl_tablet_tool->xdevice,
-                       state ? ButtonPress : ButtonRelease, xbtn, 0, &mask);
+    if (state)
+        SetBit(mask, xbtn);
+    else
+        ClearBit(mask, xbtn);
+
+    xwl_seat->xwl_screen->serial = serial;
 }
 
 static void
@@ -1598,6 +1602,8 @@ tablet_tool_frame(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t time)
 {
     struct xwl_tablet_tool *xwl_tablet_tool = data;
     ValuatorMask mask;
+    uint32_t released, pressed, diff;
+    int button;
 
     valuator_mask_zero(&mask);
     valuator_mask_set(&mask, 0, xwl_tablet_tool->x);
@@ -1607,10 +1613,34 @@ tablet_tool_frame(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t time)
     valuator_mask_set(&mask, 4, xwl_tablet_tool->tilt_y);
     valuator_mask_set(&mask, 5, xwl_tablet_tool->rotation + xwl_tablet_tool->slider);
 
-    /* FIXME: Store button mask in xwl_tablet_tool and send events *HERE* if
-       changed */
     QueuePointerEvents(xwl_tablet_tool->xdevice, MotionNotify, 0,
                POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
+
+    valuator_mask_zero(&mask);
+
+    diff = xwl_tablet_tool->buttons_prev ^ xwl_tablet_tool->buttons_now;
+    released = diff & ~xwl_tablet_tool->buttons_now;
+    pressed = diff & xwl_tablet_tool->buttons_now;
+
+    button = 1;
+    while (released) {
+        if (released & 0x1)
+            QueuePointerEvents(xwl_tablet_tool->xdevice,
+                               ButtonRelease, button, 0, &mask);
+        button++;
+        released >>= 1;
+    }
+
+    button = 1;
+    while (pressed) {
+        if (pressed & 0x1)
+            QueuePointerEvents(xwl_tablet_tool->xdevice,
+                               ButtonPress, button, 0, &mask);
+        button++;
+        pressed >>= 1;
+    }
+
+    xwl_tablet_tool->buttons_prev = xwl_tablet_tool->buttons_now;
 }
 
 static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 7bd658812..30088b03a 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -205,6 +205,9 @@ struct xwl_tablet_tool {
     float tilt_y;
     float rotation;
     float slider;
+
+    uint32_t buttons_now,
+             buttons_prev;
 };
 
 struct xwl_tablet_pad {
commit 8a1defcc634daddbb3570519d69ec5c9e39a8b56
Author: Jason Gerecke <killertofu at gmail.com>
Date:   Fri Oct 14 14:31:46 2016 -0700

    xwayland: Handle tablet_tool events
    
    Translates Wayland tablet events into corresponding X11 tablet events. As
    with the prior commit, these events are modeled after those created by the
    xf86-input-wacom driver to maximize compatibility with existing applications.
    
    Signed-off-by: Jason Gerecke <jason.gerecke at wacom.com>
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 6e701bce8..076da7923 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1325,6 +1325,317 @@ static const struct zwp_tablet_v2_listener tablet_listener = {
 };
 
 static void
+tablet_tool_receive_type(void *data, struct zwp_tablet_tool_v2 *tool,
+                         uint32_t type)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+
+    switch (type) {
+        case ZWP_TABLET_TOOL_V2_TYPE_ERASER:
+            xwl_tablet_tool->xdevice = xwl_seat->eraser;
+            break;
+        case ZWP_TABLET_TOOL_V2_TYPE_MOUSE:
+        case ZWP_TABLET_TOOL_V2_TYPE_LENS:
+            xwl_tablet_tool->xdevice = xwl_seat->puck;
+            break;
+        default:
+            xwl_tablet_tool->xdevice = xwl_seat->stylus;
+            break;
+    }
+}
+
+static void
+tablet_tool_receive_hardware_serial(void *data, struct zwp_tablet_tool_v2 *tool,
+                                    uint32_t hi, uint32_t low)
+{
+}
+
+static void
+tablet_tool_receive_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *tool,
+                                      uint32_t hi, uint32_t low)
+{
+}
+
+static void
+tablet_tool_receive_capability(void *data, struct zwp_tablet_tool_v2 *tool,
+                               uint32_t capability)
+{
+}
+
+static void
+tablet_tool_receive_done(void *data, struct zwp_tablet_tool_v2 *tool)
+{
+}
+
+static void
+tablet_tool_receive_removed(void *data, struct zwp_tablet_tool_v2 *tool)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+
+    xorg_list_del(&xwl_tablet_tool->link);
+    zwp_tablet_tool_v2_destroy(tool);
+    free(xwl_tablet_tool);
+}
+
+static void
+tablet_tool_proximity_in(void *data, struct zwp_tablet_tool_v2 *tool,
+                         uint32_t serial, struct zwp_tablet_v2 *tablet,
+                         struct wl_surface *wl_surface)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+
+    /* There's a race here where if we create and then immediately
+     * destroy a surface, we might end up in a state where the Wayland
+     * compositor sends us an event for a surface that doesn't exist.
+     *
+     * Don't process enter events in this case.
+     *
+     * see pointer_handle_enter()
+     */
+    if (wl_surface == NULL)
+        return;
+
+    xwl_seat->focus_window = wl_surface_get_user_data(wl_surface);
+}
+
+static void
+tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *tool)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+
+    xwl_seat->focus_window = NULL;
+
+    xwl_tablet_tool->pressure = 0;
+    xwl_tablet_tool->tilt_x = 0;
+    xwl_tablet_tool->tilt_y = 0;
+    xwl_tablet_tool->rotation = 0;
+    xwl_tablet_tool->slider = 0;
+}
+
+static void
+tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    ValuatorMask mask;
+
+    xwl_seat->xwl_screen->serial = serial;
+
+    valuator_mask_zero(&mask);
+    QueuePointerEvents(xwl_tablet_tool->xdevice, ButtonPress, 1, 0, &mask);
+}
+
+static void
+tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *tool)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    ValuatorMask mask;
+
+    valuator_mask_zero(&mask);
+    QueuePointerEvents(xwl_tablet_tool->xdevice, ButtonRelease, 1, 0, &mask);
+}
+
+static void
+tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
+                   wl_fixed_t x, wl_fixed_t y)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    int32_t dx, dy;
+    int sx = wl_fixed_to_int(x);
+    int sy = wl_fixed_to_int(y);
+
+    if (!xwl_seat->focus_window)
+        return;
+
+    dx = xwl_seat->focus_window->window->drawable.x;
+    dy = xwl_seat->focus_window->window->drawable.y;
+
+    xwl_tablet_tool->x = dx + sx;
+    xwl_tablet_tool->y = dy + sy;
+}
+
+static void
+tablet_tool_pressure(void *data, struct zwp_tablet_tool_v2 *tool,
+                     uint32_t pressure)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+
+    if (!xwl_seat->focus_window)
+        return;
+
+    /* normalized to 65535 already */
+    xwl_tablet_tool->pressure = pressure;
+}
+
+static void
+tablet_tool_distance(void *data, struct zwp_tablet_tool_v2 *tool,
+                     uint32_t distance_raw)
+{
+}
+
+static void
+tablet_tool_tilt(void *data, struct zwp_tablet_tool_v2 *tool,
+                 wl_fixed_t tilt_x, wl_fixed_t tilt_y)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+
+    if (!xwl_seat->focus_window)
+        return;
+
+    xwl_tablet_tool->tilt_x = wl_fixed_to_double(tilt_x);
+    xwl_tablet_tool->tilt_y = wl_fixed_to_double(tilt_y);
+}
+
+static void
+tablet_tool_rotation(void *data, struct zwp_tablet_tool_v2 *tool,
+                     wl_fixed_t angle)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    double rotation = wl_fixed_to_double(angle);
+
+    if (!xwl_seat->focus_window)
+        return;
+
+    /* change origin (buttons facing right [libinput +90 degrees]) and
+     * scaling (5 points per degree) to match wacom driver behavior
+     */
+    rotation = remainderf(rotation + 90.0f, 360.0f);
+    rotation *= 5.0f;
+    xwl_tablet_tool->rotation = rotation;
+}
+
+static void
+tablet_tool_slider(void *data, struct zwp_tablet_tool_v2 *tool,
+                   int32_t position_raw)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    float position = position_raw / 65535.0;
+
+    if (!xwl_seat->focus_window)
+        return;
+
+    xwl_tablet_tool->slider = (position * 1799.0f) - 900.0f;
+}
+
+static void
+tablet_tool_wheel(void *data, struct zwp_tablet_tool_v2 *tool,
+                  wl_fixed_t degrees, int32_t clicks)
+{
+}
+
+static void
+tablet_tool_button_state(void *data, struct zwp_tablet_tool_v2 *tool,
+                         uint32_t serial, uint32_t button, uint32_t state)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+    int xbtn = 0;
+    ValuatorMask mask;
+
+    /* BTN_0 .. BTN_9 */
+    if (button >= 0x100 && button <= 0x109) {
+        xbtn = button - 0x100 + 1;
+    }
+    /* BTN_A .. BTN_Z */
+    else if (button >= 0x130 && button <= 0x135) {
+        xbtn = button - 0x130 + 10;
+    }
+    /* BTN_BASE .. BTN_BASE6 */
+    else if (button >= 0x126 && button <= 0x12b) {
+        xbtn = button - 0x126 + 16;
+    }
+    else {
+        switch (button) {
+        case 0x110: /* BTN_LEFT    */
+        case 0x14a: /* BTN_TOUCH   */
+            xbtn = 1;
+            break;
+
+        case 0x112: /* BTN_MIDDLE  */
+        case 0x14b: /* BTN_STYLUS  */
+            xbtn = 2;
+            break;
+
+        case 0x111: /* BTN_RIGHT   */
+        case 0x14c: /* BTN_STYLUS2 */
+            xbtn = 3;
+            break;
+
+        case 0x113: /* BTN_SIDE    */
+        case 0x116: /* BTN_BACK    */
+            xbtn = 8;
+            break;
+
+        case 0x114: /* BTN_EXTRA   */
+        case 0x115: /* BTN_FORWARD */
+            xbtn = 9;
+            break;
+        }
+    }
+
+    if (!xbtn) {
+        ErrorF("unknown tablet button number %d\n", button);
+        return;
+    }
+
+    xwl_seat->xwl_screen->serial = serial;
+
+    valuator_mask_zero(&mask);
+    QueuePointerEvents(xwl_tablet_tool->xdevice,
+                       state ? ButtonPress : ButtonRelease, xbtn, 0, &mask);
+}
+
+static void
+tablet_tool_frame(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t time)
+{
+    struct xwl_tablet_tool *xwl_tablet_tool = data;
+    ValuatorMask mask;
+
+    valuator_mask_zero(&mask);
+    valuator_mask_set(&mask, 0, xwl_tablet_tool->x);
+    valuator_mask_set(&mask, 1, xwl_tablet_tool->y);
+    valuator_mask_set(&mask, 2, xwl_tablet_tool->pressure);
+    valuator_mask_set(&mask, 3, xwl_tablet_tool->tilt_x);
+    valuator_mask_set(&mask, 4, xwl_tablet_tool->tilt_y);
+    valuator_mask_set(&mask, 5, xwl_tablet_tool->rotation + xwl_tablet_tool->slider);
+
+    /* FIXME: Store button mask in xwl_tablet_tool and send events *HERE* if
+       changed */
+    QueuePointerEvents(xwl_tablet_tool->xdevice, MotionNotify, 0,
+               POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
+}
+
+static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
+    tablet_tool_receive_type,
+    tablet_tool_receive_hardware_serial,
+    tablet_tool_receive_hardware_id_wacom,
+    tablet_tool_receive_capability,
+    tablet_tool_receive_done,
+    tablet_tool_receive_removed,
+    tablet_tool_proximity_in,
+    tablet_tool_proximity_out,
+    tablet_tool_down,
+    tablet_tool_up,
+    tablet_tool_motion,
+    tablet_tool_pressure,
+    tablet_tool_distance,
+    tablet_tool_tilt,
+    tablet_tool_rotation,
+    tablet_tool_slider,
+    tablet_tool_wheel,
+    tablet_tool_button_state,
+    tablet_tool_frame
+};
+
+static void
 tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
                               struct zwp_tablet_v2 *tablet)
 {
@@ -1362,6 +1673,8 @@ tablet_seat_handle_add_tool(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
     xwl_tablet_tool->seat = xwl_seat;
 
     xorg_list_add(&xwl_tablet_tool->link, &xwl_seat->tablet_tools);
+
+    zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, xwl_tablet_tool);
 }
 
 static void
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 796282cd7..7bd658812 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -196,6 +196,15 @@ struct xwl_tablet_tool {
     struct xorg_list link;
     struct zwp_tablet_tool_v2 *tool;
     struct xwl_seat *seat;
+
+    DeviceIntPtr xdevice;
+    uint32_t x;
+    uint32_t y;
+    uint32_t pressure;
+    float tilt_x;
+    float tilt_y;
+    float rotation;
+    float slider;
 };
 
 struct xwl_tablet_pad {
commit 5812d1c28f4fb7b7de8b96a81415a21425561fd4
Author: Jason Gerecke <killertofu at gmail.com>
Date:   Fri Jan 15 17:01:38 2016 -0800

    xwayland: Handle wp_tablet events
    
    Creates and maintains the canonical trio of X devices (stylus, eraser,
    and cursor) to be shared by all connected tablets. A per-tablet trio
    could be created instead, but there are very few benefits to such a
    configuration since all tablets still ultimately share control of a
    single master pointer.
    
    The three X devices are modeled after those created by xf86-input-wacom
    but use a generic maximum X and Y that should be large enough to
    accurately represent values from even the largest currently-available
    tablets.
    
    Signed-off-by: Jason Gerecke <jason.gerecke at wacom.com>
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 77dd06051..6e701bce8 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -288,6 +288,75 @@ xwl_touch_proc(DeviceIntPtr device, int what)
 #undef NTOUCHPOINTS
 }
 
+static int
+xwl_tablet_proc(DeviceIntPtr device, int what)
+{
+#define NBUTTONS 9
+#define NAXES 6
+    Atom btn_labels[NBUTTONS] = { 0 };
+    Atom axes_labels[NAXES] = { 0 };
+    BYTE map[NBUTTONS + 1] = { 0 };
+    int i;
+
+    switch (what) {
+    case DEVICE_INIT:
+        device->public.on = FALSE;
+
+        for (i = 1; i <= NBUTTONS; i++)
+            map[i] = i;
+
+        axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
+        axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
+        axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_PRESSURE);
+        axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_X);
+        axes_labels[4] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_Y);
+        axes_labels[5] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_WHEEL);
+
+        if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels,
+                                           GetMotionHistorySize(), Absolute))
+            return BadValue;
+
+        /* Valuators - match the xf86-input-wacom ranges */
+        InitValuatorAxisStruct(device, 0, axes_labels[0],
+                               0, 262143, 10000, 0, 10000, Absolute);
+        InitValuatorAxisStruct(device, 1, axes_labels[1],
+                               0, 262143, 10000, 0, 10000, Absolute);
+        /* pressure */
+        InitValuatorAxisStruct(device, 2, axes_labels[2],
+                               0, 65535, 1, 0, 1, Absolute);
+        /* tilt x */
+        InitValuatorAxisStruct(device, 3, axes_labels[3],
+                               -64, 63, 57, 0, 57, Absolute);
+        /* tilt y */
+        InitValuatorAxisStruct(device, 4, axes_labels[4],
+                               -64, 63, 57, 0, 57, Absolute);
+        /* abs wheel (airbrush) or rotation (artpen) */
+        InitValuatorAxisStruct(device, 5, axes_labels[5],
+                               -900, 899, 1, 0, 1, Absolute);
+
+        if (!InitPtrFeedbackClassDeviceStruct(device, xwl_pointer_control))
+            return BadValue;
+
+        if (!InitButtonClassDeviceStruct(device, NBUTTONS, btn_labels, map))
+            return BadValue;
+
+        return Success;
+
+    case DEVICE_ON:
+        device->public.on = TRUE;
+        return Success;
+
+    case DEVICE_OFF:
+    case DEVICE_CLOSE:
+        device->public.on = FALSE;
+        return Success;
+    }
+
+    return BadMatch;
+#undef NAXES
+#undef NBUTTONS
+}
+
 static void
 pointer_handle_enter(void *data, struct wl_pointer *pointer,
                      uint32_t serial, struct wl_surface *surface,
@@ -1183,6 +1252,77 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
     free(xwl_seat);
 }
 
+static void
+tablet_handle_name(void *data, struct zwp_tablet_v2 *tablet, const char *name)
+{
+}
+
+static void
+tablet_handle_id(void *data, struct zwp_tablet_v2 *tablet, uint32_t vid,
+                  uint32_t pid)
+{
+}
+
+static void
+tablet_handle_path(void *data, struct zwp_tablet_v2 *tablet, const char *path)
+{
+}
+
+static void
+tablet_handle_done(void *data, struct zwp_tablet_v2 *tablet)
+{
+    struct xwl_tablet *xwl_tablet = data;
+    struct xwl_seat *xwl_seat = xwl_tablet->seat;
+
+    if (xwl_seat->stylus == NULL) {
+        xwl_seat->stylus = add_device(xwl_seat, "xwayland-stylus", xwl_tablet_proc);
+        ActivateDevice(xwl_seat->stylus, TRUE);
+    }
+    EnableDevice(xwl_seat->stylus, TRUE);
+
+    if (xwl_seat->eraser == NULL) {
+        xwl_seat->eraser = add_device(xwl_seat, "xwayland-eraser", xwl_tablet_proc);
+        ActivateDevice(xwl_seat->eraser, TRUE);
+    }
+    EnableDevice(xwl_seat->eraser, TRUE);
+
+    if (xwl_seat->puck == NULL) {
+        xwl_seat->puck = add_device(xwl_seat, "xwayland-cursor", xwl_tablet_proc);
+        ActivateDevice(xwl_seat->puck, TRUE);
+    }
+    EnableDevice(xwl_seat->puck, TRUE);
+}
+
+static void
+tablet_handle_removed(void *data, struct zwp_tablet_v2 *tablet)
+{
+    struct xwl_tablet *xwl_tablet = data;
+    struct xwl_seat *xwl_seat = xwl_tablet->seat;
+
+    xorg_list_del(&xwl_tablet->link);
+
+    /* The tablet is merely disabled, not removed. The next tablet
+       will re-use the same X devices */
+    if (xorg_list_is_empty(&xwl_seat->tablets)) {
+        if (xwl_seat->stylus)
+            DisableDevice(xwl_seat->stylus, TRUE);
+        if (xwl_seat->eraser)
+            DisableDevice(xwl_seat->eraser, TRUE);
+        if (xwl_seat->puck)
+            DisableDevice(xwl_seat->puck, TRUE);
+    }
+
+    zwp_tablet_v2_destroy(tablet);
+    free(xwl_tablet);
+}
+
+static const struct zwp_tablet_v2_listener tablet_listener = {
+    tablet_handle_name,
+    tablet_handle_id,
+    tablet_handle_path,
+    tablet_handle_done,
+    tablet_handle_removed
+};
 
 static void
 tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
@@ -1201,6 +1341,8 @@ tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat
     xwl_tablet->seat = xwl_seat;
 
     xorg_list_add(&xwl_tablet->link, &xwl_seat->tablets);
+
+    zwp_tablet_v2_add_listener(tablet, &tablet_listener, xwl_tablet);
 }
 
 static void
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 7a4d5ee3c..796282cd7 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -135,6 +135,9 @@ struct xwl_seat {
     DeviceIntPtr relative_pointer;
     DeviceIntPtr keyboard;
     DeviceIntPtr touch;
+    DeviceIntPtr stylus;
+    DeviceIntPtr eraser;
+    DeviceIntPtr puck;
     struct xwl_screen *xwl_screen;
     struct wl_seat *seat;
     struct wl_pointer *wl_pointer;
commit 47c4415912b5b16b115135be365beb370858df76
Author: Jason Gerecke <killertofu at gmail.com>
Date:   Fri Oct 14 14:50:18 2016 -0700

    xwayland: Listen for wp_tablet_seat events
    
    The wp_tablet_seat interface provides us with notifications as tablets,
    tools, and pads are connected to the system. Add listener functions and
    store references to the obtained devices.
    
    Signed-off-by: Jason Gerecke <jason.gerecke at wacom.com>
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 8ef2e3cf7..77dd06051 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1185,6 +1185,69 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
 
 
 static void
+tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
+                              struct zwp_tablet_v2 *tablet)
+{
+    struct xwl_seat *xwl_seat = data;
+    struct xwl_tablet *xwl_tablet;
+
+    xwl_tablet = calloc(sizeof *xwl_tablet, 1);
+    if (xwl_tablet == NULL) {
+        ErrorF("%s ENOMEM\n", __func__);
+        return;
+    }
+
+    xwl_tablet->tablet = tablet;
+    xwl_tablet->seat = xwl_seat;
+
+    xorg_list_add(&xwl_tablet->link, &xwl_seat->tablets);
+}
+
+static void
+tablet_seat_handle_add_tool(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
+                            struct zwp_tablet_tool_v2 *tool)
+{
+    struct xwl_seat *xwl_seat = data;
+    struct xwl_tablet_tool *xwl_tablet_tool;
+
+    xwl_tablet_tool = calloc(sizeof *xwl_tablet_tool, 1);
+    if (xwl_tablet_tool == NULL) {
+        ErrorF("%s ENOMEM\n", __func__);
+        return;
+    }
+
+    xwl_tablet_tool->tool = tool;
+    xwl_tablet_tool->seat = xwl_seat;
+
+    xorg_list_add(&xwl_tablet_tool->link, &xwl_seat->tablet_tools);
+}
+
+static void
+tablet_seat_handle_add_pad(void *data, struct zwp_tablet_seat_v2 *tablet_seat,
+                           struct zwp_tablet_pad_v2 *pad)
+{
+    struct xwl_seat *xwl_seat = data;
+    struct xwl_tablet_pad *xwl_tablet_pad;
+
+    xwl_tablet_pad = calloc(sizeof *xwl_tablet_pad, 1);
+    if (xwl_tablet_pad == NULL) {
+        ErrorF("%s ENOMEM\n", __func__);
+        return;
+    }
+
+    xwl_tablet_pad->pad = pad;
+    xwl_tablet_pad->seat = xwl_seat;
+
+    xorg_list_add(&xwl_tablet_pad->link, &xwl_seat->tablet_pads);
+}
+
+static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
+    tablet_seat_handle_add_tablet,
+    tablet_seat_handle_add_tool,
+    tablet_seat_handle_add_pad
+};
+
+static void
 init_tablet_manager_seat(struct xwl_screen *xwl_screen,
                          struct xwl_seat *xwl_seat)
 {
@@ -1194,11 +1257,42 @@ init_tablet_manager_seat(struct xwl_screen *xwl_screen,
     xwl_seat->tablet_seat =
         zwp_tablet_manager_v2_get_tablet_seat(xwl_screen->tablet_manager,
                                               xwl_seat->seat);
+
+    xorg_list_init(&xwl_seat->tablets);
+    xorg_list_init(&xwl_seat->tablet_tools);
+    xorg_list_init(&xwl_seat->tablet_pads);
+
+    zwp_tablet_seat_v2_add_listener(xwl_seat->tablet_seat, &tablet_seat_listener, xwl_seat);
 }
 
 static void
 release_tablet_manager_seat(struct xwl_seat *xwl_seat)
 {
+    struct xwl_tablet *xwl_tablet, *next_xwl_tablet;
+    struct xwl_tablet_tool *xwl_tablet_tool, *next_xwl_tablet_tool;
+    struct xwl_tablet_pad *xwl_tablet_pad, *next_xwl_tablet_pad;
+
+    xorg_list_for_each_entry_safe(xwl_tablet_pad, next_xwl_tablet_pad,
+                                  &xwl_seat->tablet_pads, link) {
+        xorg_list_del(&xwl_tablet_pad->link);
+        zwp_tablet_pad_v2_destroy(xwl_tablet_pad->pad);
+        free(xwl_tablet_pad);
+    }
+
+    xorg_list_for_each_entry_safe(xwl_tablet_tool, next_xwl_tablet_tool,
+                                  &xwl_seat->tablet_tools, link) {
+        xorg_list_del(&xwl_tablet_tool->link);
+        zwp_tablet_tool_v2_destroy(xwl_tablet_tool->tool);
+        free(xwl_tablet_tool);
+    }
+
+    xorg_list_for_each_entry_safe(xwl_tablet, next_xwl_tablet,
+                                  &xwl_seat->tablets, link) {
+        xorg_list_del(&xwl_tablet->link);
+        zwp_tablet_v2_destroy(xwl_tablet->tablet);
+        free(xwl_tablet);
+    }
+
     if (xwl_seat->tablet_seat) {
         zwp_tablet_seat_v2_destroy(xwl_seat->tablet_seat);
         xwl_seat->tablet_seat = NULL;
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 7ac1a9838..7a4d5ee3c 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -177,6 +177,28 @@ struct xwl_seat {
         double dx_unaccel;
         double dy_unaccel;
     } pending_pointer_event;
+
+    struct xorg_list tablets;
+    struct xorg_list tablet_tools;
+    struct xorg_list tablet_pads;
+};
+
+struct xwl_tablet {
+    struct xorg_list link;
+    struct zwp_tablet_v2 *tablet;
+    struct xwl_seat *seat;
+};
+
+struct xwl_tablet_tool {
+    struct xorg_list link;
+    struct zwp_tablet_tool_v2 *tool;
+    struct xwl_seat *seat;
+};
+
+struct xwl_tablet_pad {
+    struct xorg_list link;
+    struct zwp_tablet_pad_v2 *pad;
+    struct xwl_seat *seat;
 };
 
 struct xwl_output {
commit 7d48b758a601ce0252ebd21297a7c42263adfaaf
Author: Jason Gerecke <killertofu at gmail.com>
Date:   Fri Jan 15 17:29:37 2016 -0800

    xwayland: Bind to wp_tablet_manager if available and get its seats
    
    If we're notified about the existence of the wp_tablet_manager interface,
    we bind to it so that we can make use of any tablets that are (or later
    become) available. For each seat that exists or comes into existance at
    a later point, obtain the associated tablet_seat.
    
    Signed-off-by: Jason Gerecke <jason.gerecke at wacom.com>
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 7298658f7..8ef2e3cf7 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -57,6 +57,12 @@ static void
 xwl_seat_destroy_confined_pointer(struct xwl_seat *xwl_seat);
 
 static void
+init_tablet_manager_seat(struct xwl_screen *xwl_screen,
+                         struct xwl_seat *xwl_seat);
+static void
+release_tablet_manager_seat(struct xwl_seat *xwl_seat);
+
+static void
 xwl_pointer_control(DeviceIntPtr device, PtrCtrl *ctrl)
 {
     /* Nothing to do, dix handles all settings */
@@ -1141,6 +1147,9 @@ create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version
 
     xwl_seat->cursor = wl_compositor_create_surface(xwl_screen->compositor);
     wl_seat_add_listener(xwl_seat->seat, &seat_listener, xwl_seat);
+
+    init_tablet_manager_seat(xwl_screen, xwl_seat);
+
     wl_array_init(&xwl_seat->keys);
 
     xorg_list_init(&xwl_seat->touches);
@@ -1164,6 +1173,8 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
         free (p);
     }
 
+    release_tablet_manager_seat(xwl_seat);
+
     wl_seat_destroy(xwl_seat->seat);
     wl_surface_destroy(xwl_seat->cursor);
     if (xwl_seat->cursor_frame_cb)
@@ -1172,6 +1183,52 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
     free(xwl_seat);
 }
 
+
+static void
+init_tablet_manager_seat(struct xwl_screen *xwl_screen,
+                         struct xwl_seat *xwl_seat)
+{
+    if (!xwl_screen->tablet_manager)
+        return;
+
+    xwl_seat->tablet_seat =
+        zwp_tablet_manager_v2_get_tablet_seat(xwl_screen->tablet_manager,
+                                              xwl_seat->seat);
+}
+
+static void
+release_tablet_manager_seat(struct xwl_seat *xwl_seat)
+{
+    if (xwl_seat->tablet_seat) {
+        zwp_tablet_seat_v2_destroy(xwl_seat->tablet_seat);
+        xwl_seat->tablet_seat = NULL;
+    }
+}
+
+static void
+init_tablet_manager(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version)
+{
+    struct xwl_seat *xwl_seat;
+
+    xwl_screen->tablet_manager = wl_registry_bind(xwl_screen->registry,
+                                                  id,
+                                                  &zwp_tablet_manager_v2_interface,
+                                                  min(version,1));
+
+    xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) {
+        init_tablet_manager_seat(xwl_screen, xwl_seat);
+    }
+}
+
+void
+xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen)
+{
+    if (xwl_screen->tablet_manager) {
+        zwp_tablet_manager_v2_destroy(xwl_screen->tablet_manager);
+        xwl_screen->tablet_manager = NULL;
+    }
+}
+
 static void
 init_relative_pointer_manager(struct xwl_screen *xwl_screen,
                               uint32_t id, uint32_t version)
@@ -1205,6 +1262,8 @@ input_handler(void *data, struct wl_registry *registry, uint32_t id,
         init_relative_pointer_manager(xwl_screen, id, version);
     } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
         init_pointer_constraints(xwl_screen, id, version);
+    } else if (strcmp(interface, "zwp_tablet_manager_v2") == 0) {
+        init_tablet_manager(xwl_screen, id, version);
     }
 }
 
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 9cb4954e9..7fc9bc0be 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -222,6 +222,8 @@ xwl_close_screen(ScreenPtr screen)
                                   &xwl_screen->seat_list, link)
         xwl_seat_destroy(xwl_seat);
 
+    xwl_screen_release_tablet_manager(xwl_screen);
+
     RemoveNotifyFd(xwl_screen->wayland_fd);
 
     wl_display_disconnect(xwl_screen->display);
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 91b76200a..7ac1a9838 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -76,6 +76,7 @@ struct xwl_screen {
     struct wl_registry *registry;
     struct wl_registry *input_registry;
     struct wl_compositor *compositor;
+    struct zwp_tablet_manager_v2 *tablet_manager;
     struct wl_shm *shm;
     struct wl_shell *shell;
     struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
@@ -140,6 +141,7 @@ struct xwl_seat {
     struct zwp_relative_pointer_v1 *wp_relative_pointer;
     struct wl_keyboard *wl_keyboard;
     struct wl_touch *wl_touch;
+    struct zwp_tablet_seat_v2 *tablet_seat;
     struct wl_array keys;
     struct xwl_window *focus_window;
     uint32_t id;
@@ -244,6 +246,8 @@ Bool xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
                          uint32_t id, uint32_t version);
 struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap);
 
+void xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen);
+
 #ifdef XV
 /* glamor Xv Adaptor */
 Bool xwl_glamor_xv_init(ScreenPtr pScreen);
commit 89c841915ac4fba6d2a5ad0051c778f1a76ffbf3
Author: Jason Gerecke <killertofu at gmail.com>
Date:   Thu Oct 13 10:39:46 2016 -0700

    xwayland: Depend on wayland-protocols to build tablet protocol headers
    
    Signed-off-by: Jason Gerecke <jason.gerecke at wacom.com>
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Ping Cheng <ping.cheng at wacom.com>

diff --git a/configure.ac b/configure.ac
index 4ee43d2d0..8ef201709 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2355,7 +2355,7 @@ AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes])
 
 dnl Xwayland DDX
 
-XWAYLANDMODULES="wayland-client >= 1.3.0 wayland-protocols >= 1.1 $LIBDRM epoxy"
+XWAYLANDMODULES="wayland-client >= 1.3.0 wayland-protocols >= 1.5 $LIBDRM epoxy"
 if test "x$XF86VIDMODE" = xyes; then
 	XWAYLANDMODULES="$XWAYLANDMODULES $VIDMODEPROTO"
 fi
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 770e87f9b..7eda9be34 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -55,7 +55,9 @@ Xwayland_built_sources +=					\
 	relative-pointer-unstable-v1-client-protocol.h		\
 	relative-pointer-unstable-v1-protocol.c			\
 	pointer-constraints-unstable-v1-client-protocol.h	\
-	pointer-constraints-unstable-v1-protocol.c
+	pointer-constraints-unstable-v1-protocol.c		\
+	tablet-unstable-v2-client-protocol.h			\
+	tablet-unstable-v2-protocol.c
 
 nodist_Xwayland_SOURCES = $(Xwayland_built_sources)
 CLEANFILES = $(Xwayland_built_sources)
@@ -78,6 +80,11 @@ pointer-constraints-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstab
 pointer-constraints-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
 
+tablet-unstable-v2-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tablet-unstable-v2.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+tablet-unstable-v2-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tablet-unstable-v2.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
 %-protocol.c : %.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index fbbd213c3..d2791fe14 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -17,6 +17,7 @@ protodir = protocols_dep.get_pkgconfig_variable('pkgdatadir')
 
 pointer_xml = join_paths(protodir, 'unstable', 'pointer-constraints', 'pointer-constraints-unstable-v1.xml')
 relative_xml = join_paths(protodir, 'unstable', 'relative-pointer', 'relative-pointer-unstable-v1.xml')
+tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml')
 
 client_header = generator(scanner,
     output : '@BASENAME at -client-protocol.h',
@@ -28,8 +29,10 @@ code = generator(scanner,
 )
 srcs += client_header.process(relative_xml)
 srcs += client_header.process(pointer_xml)
+srcs += client_header.process(tablet_xml)
 srcs += code.process(relative_xml)
 srcs += code.process(pointer_xml)
+srcs += code.process(tablet_xml)
 
 xwayland_glamor = []
 if gbm_dep.found()
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 1f5d32324..7298658f7 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -34,6 +34,7 @@
 #include <inpututils.h>
 #include <mipointer.h>
 #include <mipointrst.h>
+#include "tablet-unstable-v2-client-protocol.h"
 
 struct sync_pending {
     struct xorg_list l;
diff --git a/meson.build b/meson.build
index 2b2b43092..c05249ae9 100644
--- a/meson.build
+++ b/meson.build
@@ -100,7 +100,7 @@ if (host_machine.system() != 'darwin' and
 
         xwayland_dep = [
             dependency('wayland-client', version: '>= 1.3.0', required: xwayland_required),
-            dependency('wayland-protocols', version: '>= 1.1.0', required: xwayland_required),
+            dependency('wayland-protocols', version: '>= 1.5.0', required: xwayland_required),
             dependency('libdrm', version: '>= 2.3.1', required: xwayland_required),
             dependency('epoxy', required: xwayland_required),
         ]


More information about the xorg-commit mailing list