On Thursday, February 9, 2017, Peter Hutterer <<a href="mailto:peter.hutterer@who-t.net">peter.hutterer@who-t.net</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Thu, Feb 09, 2017 at 12:14:47PM -0800, Jason Gerecke wrote:<br>
> On Tue, Feb 7, 2017 at 6:42 PM, Peter Hutterer <<a href="javascript:;" onclick="_e(event, 'cvml', 'peter.hutterer@who-t.net')">peter.hutterer@who-t.net</a>> wrote:<br>
> > Hooked up a bit differently to the other tools. Those tools can be static for<br>
> > all and be re-used. The wacom driver initializes the pad with the correct<br>
> > number of buttons though and we can't do this until we have the pad done event.<br>
> ><br>
> > If the tablet is removed and we plug a different one in, we should initialize<br>
> > that correctly, so unlike the other tools the pad is properly removed and<br>
> > re-initialized on plug.<br>
> ><br>
> > Signed-off-by: Peter Hutterer <<a href="javascript:;" onclick="_e(event, 'cvml', 'peter.hutterer@who-t.net')">peter.hutterer@who-t.net</a>><br>
> > ---<br>
> > New in this series<br>
> ><br>
> > hw/xwayland/xwayland-input.c | 417 ++++++++++++++++++++++++++++++<wbr>+++++++++++++<br>
> > hw/xwayland/xwayland.h | 28 +++<br>
> > 2 files changed, 445 insertions(+)<br>
> ><br>
> > diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c<br>
> > index 31e2473..1079ff4 100644<br>
> > --- a/hw/xwayland/xwayland-input.c<br>
> > +++ b/hw/xwayland/xwayland-input.c<br>
> > @@ -1334,6 +1334,7 @@ tablet_handle_removed(void *data, struct zwp_tablet_v2 *tablet)<br>
> > DisableDevice(xwl_seat-><wbr>eraser, TRUE);<br>
> > if (xwl_seat->puck)<br>
> > DisableDevice(xwl_seat->puck, TRUE);<br>
> > + /* pads are removed separately */<br>
> > }<br>
> ><br>
> > zwp_tablet_v2_destroy(tablet);<br>
> > @@ -1694,6 +1695,418 @@ static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {<br>
> > };<br>
> ><br>
> > static void<br>
> > +tablet_pad_ring_destroy(<wbr>struct xwl_tablet_pad_ring *ring)<br>
> > +{<br>
> > + zwp_tablet_pad_ring_v2_<wbr>destroy(ring->ring);<br>
> > + xorg_list_del(&ring->link);<br>
> > + free(ring);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_ring_source(void *data,<br>
> > + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,<br>
> > + uint32_t source)<br>
> > +{<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_ring_angle(void *data,<br>
> > + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,<br>
> > + wl_fixed_t degrees)<br>
> > +{<br>
> > + struct xwl_tablet_pad_ring *ring = data;<br>
> > + struct xwl_tablet_pad *pad = ring->group->pad;<br>
> > + double deg = wl_fixed_to_double(degrees);<br>
> > + ValuatorMask mask;<br>
> > +<br>
> > + valuator_mask_zero(&mask);<br>
> > + valuator_mask_set(&mask, 5 + ring->index, deg/360.0 * 71);<br>
> > + QueuePointerEvents(pad-><wbr>xdevice, MotionNotify, 0, 0, &mask);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_ring_stop(void *data,<br>
> > + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2)<br>
> > +{<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_ring_frame(void *data,<br>
> > + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,<br>
> > + uint32_t time)<br>
> > +{<br>
> > +}<br>
> > +<br>
> > +static const struct zwp_tablet_pad_ring_v2_<wbr>listener tablet_pad_ring_listener = {<br>
> > + tablet_pad_ring_source,<br>
> > + tablet_pad_ring_angle,<br>
> > + tablet_pad_ring_stop,<br>
> > + tablet_pad_ring_frame,<br>
> > +};<br>
> > +<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_strip_destroy(<wbr>struct xwl_tablet_pad_strip *strip)<br>
> > +{<br>
> > + zwp_tablet_pad_strip_v2_<wbr>destroy(strip->strip);<br>
> > + xorg_list_del(&strip->link);<br>
> > + free(strip);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_strip_source(void *data,<br>
> > + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,<br>
> > + uint32_t source)<br>
> > +{<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_strip_position(<wbr>void *data,<br>
> > + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,<br>
> > + uint32_t position)<br>
> > +{<br>
> > + struct xwl_tablet_pad_strip *strip = data;<br>
> > + struct xwl_tablet_pad *pad = strip->group->pad;<br>
> > + ValuatorMask mask;<br>
> > +<br>
> > + valuator_mask_zero(&mask);<br>
> > + valuator_mask_set(&mask, 3 + strip->index, position/65535.0 * 2048);<br>
><br>
> Note: the values reported by xf86-input-wacom are the raw hardware<br>
> values which use a walking bit to indicate where the finger is along<br>
> the strip. When your finger is at the top of the strip, we report '1';<br>
> moving down slightly '2', then '4', then '8', and so on until you<br>
> reach the bottom and we report '4096'.<br>
><br>
> The linear relationship you use here won't be compatible with software<br>
> that expects the exponential relationship used by xf86-input-wacom.<br>
> You could potentially use something like round(pow(2.0,<br>
> 12*position/65535.0)) to get the "expected" values, along with<br>
> changing the axis maximums to 4096.<br>
<br>
hmm. for the libinput xorg driver I also just forward the strip events<br>
as-is, in the hope that eventually we can get rid of the pow2 which is<br>
effectively just a long-standing bug that we never removed for fear of<br>
breaking applications. Do we *know* about applications that actually rely<br>
on this exact behaviour and that cannot change?</blockquote><div><br></div><div>There are most likely applications relying on that data format. But, I think it should be fine to change it here.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I'm really uncomfortable continuing this in xwayland (and the libinput xorg<br>
driver).</blockquote><div><br></div><div>Since it is now in Wayland, those application developers will need to update their applications anyway. They should be prepared for changes like this too. The whole set of patches is:</div><div><br></div>Acked-by: Ping Cheng <<a href="mailto:ping.cheng@wacom.com">ping.cheng@wacom.com</a>><div><br></div><div>Ping<br><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Cheers,<br>
Peter<br>
<br>
> > + QueuePointerEvents(pad-><wbr>xdevice, MotionNotify, 0, 0, &mask);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_strip_stop(void *data,<br>
> > + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2)<br>
> > +{<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_strip_frame(void *data,<br>
> > + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,<br>
> > + uint32_t time)<br>
> > +{<br>
> > +}<br>
> > +<br>
> > +static const struct zwp_tablet_pad_strip_v2_<wbr>listener tablet_pad_strip_listener = {<br>
> > + tablet_pad_strip_source,<br>
> > + tablet_pad_strip_position,<br>
> > + tablet_pad_strip_stop,<br>
> > + tablet_pad_strip_frame,<br>
> > +};<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group_destroy(<wbr>struct xwl_tablet_pad_group *group)<br>
> > +{<br>
> > + struct xwl_tablet_pad_ring *r, *tr;<br>
> > + struct xwl_tablet_pad_strip *s, *ts;<br>
> > +<br>
> > + xorg_list_for_each_entry_safe(<wbr>r, tr,<br>
> > + &group->pad_group_ring_list,<br>
> > + link)<br>
> > + tablet_pad_ring_destroy(r);<br>
> > +<br>
> > + xorg_list_for_each_entry_safe(<wbr>s, ts,<br>
> > + &group->pad_group_strip_list,<br>
> > + link)<br>
> > + tablet_pad_strip_destroy(s);<br>
> > +<br>
> > + zwp_tablet_pad_group_v2_<wbr>destroy(group->group);<br>
> > + xorg_list_del(&group->link);<br>
> > + free(group);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group_buttons(void *data,<br>
> > + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,<br>
> > + struct wl_array *buttons)<br>
> > +{<br>
> > +<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group_ring(void *data,<br>
> > + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,<br>
> > + struct zwp_tablet_pad_ring_v2 *wp_ring)<br>
> > +{<br>
> > + static unsigned int ring_index = 0;<br>
> > + struct xwl_tablet_pad_group *group = data;<br>
> > + struct xwl_tablet_pad_ring *ring;<br>
> > +<br>
> > + ring = calloc(1, sizeof *ring);<br>
> > + if (ring == NULL) {<br>
> > + ErrorF("%s ENOMEM\n", __func__);<br>
> > + return;<br>
> > + }<br>
> > +<br>
> > + ring->index = ring_index++;<br>
> > + ring->group = group;<br>
> > + ring->ring = wp_ring;<br>
> > +<br>
> > + xorg_list_add(&ring->link, &group->pad_group_ring_list);<br>
> > +<br>
> > + zwp_tablet_pad_ring_v2_add_<wbr>listener(wp_ring, &tablet_pad_ring_listener,<br>
> > + ring);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group_strip(void *data,<br>
> > + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,<br>
> > + struct zwp_tablet_pad_strip_v2 *wp_strip)<br>
> > +{<br>
> > + static unsigned int strip_index = 0;<br>
> > + struct xwl_tablet_pad_group *group = data;<br>
> > + struct xwl_tablet_pad_strip *strip;<br>
> > +<br>
> > + strip = calloc(1, sizeof *strip);<br>
> > + if (strip == NULL) {<br>
> > + ErrorF("%s ENOMEM\n", __func__);<br>
> > + return;<br>
> > + }<br>
> > +<br>
> > + strip->index = strip_index++;<br>
> > + strip->group = group;<br>
> > + strip->strip = wp_strip;<br>
> > +<br>
> > + xorg_list_add(&strip->link, &group->pad_group_strip_list);<br>
> > +<br>
> > + zwp_tablet_pad_strip_v2_add_<wbr>listener(wp_strip, &tablet_pad_strip_listener,<br>
> > + strip);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group_modes(void *data,<br>
> > + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,<br>
> > + uint32_t modes)<br>
> > +{<br>
> > +<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group_done(void *data,<br>
> > + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2)<br>
> > +{<br>
> > +<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group_mode_switch(<wbr>void *data,<br>
> > + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2,<br>
> > + uint32_t time,<br>
> > + uint32_t serial,<br>
> > + uint32_t mode)<br>
> > +{<br>
> > +<br>
> > +}<br>
> > +<br>
> > +static struct zwp_tablet_pad_group_v2_<wbr>listener tablet_pad_group_listener = {<br>
> > + tablet_pad_group_buttons,<br>
> > + tablet_pad_group_ring,<br>
> > + tablet_pad_group_strip,<br>
> > + tablet_pad_group_modes,<br>
> > + tablet_pad_group_done,<br>
> > + tablet_pad_group_mode_switch,<br>
> > +};<br>
> > +<br>
> > +static int<br>
> > +xwl_tablet_pad_proc(<wbr>DeviceIntPtr device, int what)<br>
> > +{<br>
> > + struct xwl_tablet_pad *pad = device->public.devicePrivate;<br>
> > + /* Axis layout mirrors that of xf86-input-wacom to have better<br>
> > + compatibility with existing clients */<br>
> > +#define NAXES 7<br>
> > + Atom axes_labels[NAXES] = { 0 };<br>
> > + BYTE map[MAX_BUTTONS + 1];<br>
> > + int i = 0;<br>
> > + Atom btn_labels[MAX_BUTTONS] = { 0 }; /* btn labels are meaningless */<br>
> > + int nbuttons;<br>
> > +<br>
> > + switch (what) {<br>
> > + case DEVICE_INIT:<br>
> > + device->public.on = FALSE;<br>
> > +<br>
> > + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_<wbr>PROP_ABS_X);<br>
> > + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_<wbr>PROP_ABS_Y);<br>
> > + /* The others have no good mapping */<br>
> > +<br>
> > + if (!<wbr>InitValuatorClassDeviceStruct(<wbr>device, NAXES, axes_labels,<br>
> > + GetMotionHistorySize(), Absolute))<br>
> > + return BadValue;<br>
> > +<br>
> > + for (i = 1; i <= MAX_BUTTONS; i++)<br>
> > + map[i] = i;<br>
> > +<br>
> > + /* We need at least 7 buttons to allow scrolling */<br>
> > + nbuttons = min(max(pad->nbuttons + 4, 7), MAX_BUTTONS);<br>
> > +<br>
> > + if (!InitButtonClassDeviceStruct(<wbr>device, nbuttons,<br>
> > + btn_labels, map))<br>
> > + return BadValue;<br>
> > +<br>
> > + /* Valuators */<br>
> > + InitValuatorAxisStruct(device, 0, axes_labels[0],<br>
> > + 0, 100, 1, 0, 1, Absolute);<br>
> > + InitValuatorAxisStruct(device, 1, axes_labels[1],<br>
> > + 0, 100, 1, 0, 1, Absolute);<br>
> > + /* Pressure - unused, for backwards compat only */<br>
> > + InitValuatorAxisStruct(device, 2, axes_labels[2],<br>
> > + 0, 2048, 1, 0, 1, Absolute);<br>
> > + /* strip x */<br>
> > + InitValuatorAxisStruct(device, 3, axes_labels[3],<br>
> > + 0, 2048, 1, 0, 1, Absolute);<br>
> > + /* strip y */<br>
> > + InitValuatorAxisStruct(device, 4, axes_labels[4],<br>
> > + 0, 2048, 1, 0, 1, Absolute);<br>
> > + /* ring */<br>
> > + InitValuatorAxisStruct(device, 5, axes_labels[5],<br>
> > + 0, 71, 1, 0, 1, Absolute);<br>
> > + /* ring2 */<br>
> > + InitValuatorAxisStruct(device, 6, axes_labels[6],<br>
> > + 0, 71, 1, 0, 1, Absolute);<br>
> > +<br>
> > + if (!<wbr>InitPtrFeedbackClassDeviceStru<wbr>ct(device, xwl_pointer_control))<br>
> > + return BadValue;<br>
> > +<br>
> > + return Success;<br>
> > +<br>
> > + case DEVICE_ON:<br>
> > + device->public.on = TRUE;<br>
> > + return Success;<br>
> > +<br>
> > + case DEVICE_OFF:<br>
> > + case DEVICE_CLOSE:<br>
> > + device->public.on = FALSE;<br>
> > + return Success;<br>
> > + }<br>
> > +<br>
> > + return BadMatch;<br>
> > +#undef NAXES<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_group(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,<br>
> > + struct zwp_tablet_pad_group_v2 *pad_group)<br>
> > +{<br>
> > + struct xwl_tablet_pad *pad = data;<br>
> > + struct xwl_tablet_pad_group *group;<br>
> > +<br>
> > + group = calloc(1, sizeof *group);<br>
> > + if (pad == NULL) {<br>
> > + ErrorF("%s ENOMEM\n", __func__);<br>
> > + return;<br>
> > + }<br>
> > +<br>
> > + group->pad = pad;<br>
> > + group->group = pad_group;<br>
> > + xorg_list_init(&group->pad_<wbr>group_ring_list);<br>
> > + xorg_list_init(&group->pad_<wbr>group_strip_list);<br>
> > +<br>
> > + xorg_list_add(&group->link, &pad->pad_group_list);<br>
> > +<br>
> > + zwp_tablet_pad_group_v2_add_<wbr>listener(pad_group,<br>
> > + &tablet_pad_group_listener,<br>
> > + group);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_path(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,<br>
> > + const char *path)<br>
> > +{<br>
> > +<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_buttons(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,<br>
> > + uint32_t buttons)<br>
> > +{<br>
> > + struct xwl_tablet_pad *pad = data;<br>
> > +<br>
> > + pad->nbuttons = buttons;<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_done(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2)<br>
> > +{<br>
> > + struct xwl_tablet_pad *pad = data;<br>
> > +<br>
> > + pad->xdevice = add_device(pad->seat, "xwayland-pad",<br>
> > + xwl_tablet_pad_proc);<br>
> > + pad->xdevice->public.<wbr>devicePrivate = pad;<br>
> > + ActivateDevice(pad->xdevice, TRUE);<br>
> > + EnableDevice(pad->xdevice, TRUE);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_button(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,<br>
> > + uint32_t time,<br>
> > + uint32_t button,<br>
> > + uint32_t state)<br>
> > +{<br>
> > + struct xwl_tablet_pad *pad = data;<br>
> > + ValuatorMask mask;<br>
> > +<br>
> > + button++; /* wayland index vs X's 1-offset */<br>
> > + /* skip scroll wheel buttons 4-7 */<br>
> > + button = button > 3 ? button + 4 : button;<br>
> > +<br>
> > + valuator_mask_zero(&mask);<br>
> > + QueuePointerEvents(pad-><wbr>xdevice,<br>
> > + state ? ButtonPress : ButtonRelease, button, 0, &mask);<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_enter(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,<br>
> > + uint32_t serial,<br>
> > + struct zwp_tablet_v2 *tablet,<br>
> > + struct wl_surface *surface)<br>
> > +{<br>
> > + /* pairs the pad with the tablet but also to set the focus. We<br>
> > + * don't care about the pairing and always use X's focus */<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_leave(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,<br>
> > + uint32_t serial,<br>
> > + struct wl_surface *surface)<br>
> > +{<br>
> > + /* pairs the pad with the tablet but also to set the focus. We<br>
> > + * don't care about the pairing and always use X's focus */<br>
> > +}<br>
> > +<br>
> > +static void<br>
> > +tablet_pad_removed(void *data,<br>
> > + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2)<br>
> > +{<br>
> > + struct xwl_tablet_pad *pad = data;<br>
> > + struct xwl_tablet_pad_group *g, *tg;<br>
> > +<br>
> > + xorg_list_for_each_entry_safe(<wbr>g, tg, &pad->pad_group_list, link)<br>
> > + tablet_pad_group_destroy(g);<br>
> > +<br>
> > + RemoveDevice(pad->xdevice, TRUE);<br>
> > + xorg_list_del(&pad->link);<br>
> > + zwp_tablet_pad_v2_destroy(pad-<wbr>>pad);<br>
> > + free(pad);<br>
> > +}<br>
> > +<br>
> > +static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = {<br>
> > + tablet_pad_group,<br>
> > + tablet_pad_path,<br>
> > + tablet_pad_buttons,<br>
> > + tablet_pad_done,<br>
> > + tablet_pad_button,<br>
> > + tablet_pad_enter,<br>
> > + tablet_pad_leave,<br>
> > + tablet_pad_removed,<br>
> > +};<br>
> > +<br>
> > +static void<br>
> > tablet_seat_handle_add_tablet(<wbr>void *data, struct zwp_tablet_seat_v2 *tablet_seat,<br>
> > struct zwp_tablet_v2 *tablet)<br>
> > {<br>
> > @@ -1762,8 +2175,12 @@ tablet_seat_handle_add_pad(<wbr>void *data, struct zwp_tablet_seat_v2 *tablet_seat,<br>
> ><br>
> > xwl_tablet_pad->pad = pad;<br>
> > xwl_tablet_pad->seat = xwl_seat;<br>
> > + xorg_list_init(&xwl_tablet_<wbr>pad->pad_group_list);<br>
> ><br>
> > xorg_list_add(&xwl_tablet_pad-<wbr>>link, &xwl_seat->tablet_pads);<br>
> > +<br>
> > + zwp_tablet_pad_v2_add_<wbr>listener(pad, &tablet_pad_listener,<br>
> > + xwl_tablet_pad);<br>
> > }<br>
> ><br>
> > static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {<br>
> > diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h<br>
> > index eceac32..40d08b6 100644<br>
> > --- a/hw/xwayland/xwayland.h<br>
> > +++ b/hw/xwayland/xwayland.h<br>
> > @@ -216,10 +216,38 @@ struct xwl_tablet_tool {<br>
> > struct xwl_cursor cursor;<br>
> > };<br>
> ><br>
> > +struct xwl_tablet_pad_ring {<br>
> > + unsigned int index;<br>
> > + struct xorg_list link;<br>
> > + struct xwl_tablet_pad_group *group;<br>
> > + struct zwp_tablet_pad_ring_v2 *ring;<br>
> > +};<br>
> > +<br>
> > +struct xwl_tablet_pad_strip {<br>
> > + unsigned int index;<br>
> > + struct xorg_list link;<br>
> > + struct xwl_tablet_pad_group *group;<br>
> > + struct zwp_tablet_pad_strip_v2 *strip;<br>
> > +};<br>
> > +<br>
> > +struct xwl_tablet_pad_group {<br>
> > + struct xorg_list link;<br>
> > + struct xwl_tablet_pad *pad;<br>
> > + struct zwp_tablet_pad_group_v2 *group;<br>
> > +<br>
> > + struct xorg_list pad_group_ring_list;<br>
> > + struct xorg_list pad_group_strip_list;<br>
> > +};<br>
> > +<br>
> > struct xwl_tablet_pad {<br>
> > struct xorg_list link;<br>
> > struct zwp_tablet_pad_v2 *pad;<br>
> > struct xwl_seat *seat;<br>
> > +<br>
> > + DeviceIntPtr xdevice;<br>
> > +<br>
> > + unsigned int nbuttons;<br>
> > + struct xorg_list pad_group_list;<br>
> > };<br>
> ><br>
> > struct xwl_output {<br>
> > --<br>
> > 2.9.3<br>
> ><br>
><br>
</blockquote></div>