You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
511 lines
15 KiB
511 lines
15 KiB
From 6f79f4993d351a891a715e994ab9574542e64b35 Mon Sep 17 00:00:00 2001 |
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
|
Date: Tue, 7 Feb 2017 15:04:46 +1000 |
|
Subject: [PATCH xserver 09/12] 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@who-t.net> |
|
Acked-by: Ping Cheng <ping.cheng@wacom.com> |
|
(cherry picked from commit 8475e6360ce31551d50fd63a26f7a44d1e8928f2) |
|
--- |
|
hw/xwayland/xwayland-input.c | 417 +++++++++++++++++++++++++++++++++++++++++++ |
|
hw/xwayland/xwayland.h | 28 +++ |
|
2 files changed, 445 insertions(+) |
|
|
|
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c |
|
index 77cd42789..8011b965c 100644 |
|
--- a/hw/xwayland/xwayland-input.c |
|
+++ b/hw/xwayland/xwayland-input.c |
|
@@ -1341,6 +1341,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); |
|
@@ -1701,6 +1702,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) |
|
{ |
|
@@ -1769,8 +2182,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 02a218c43..250564f73 100644 |
|
--- a/hw/xwayland/xwayland.h |
|
+++ b/hw/xwayland/xwayland.h |
|
@@ -216,10 +216,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 { |
|
-- |
|
2.13.5 |
|
|
|
|