Changeset View
Changeset View
Standalone View
Standalone View
files/0009-xwayland-add-tablet-pad-support.patch
- This file was added.
| 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 | |||||
Copyright © 2015-2021 Solus Project. The Solus logo is Copyright © 2016-2021 Solus Project. All Rights Reserved.