diff options
author | Povilas Kanapickas <povilas@radix.lt> | 2021-12-03 02:40:58 +0200 |
---|---|---|
committer | Povilas Kanapickas <povilas@radix.lt> | 2021-12-04 15:55:21 +0000 |
commit | ff2de0b87ee9ab64fe4f07d019a4386f802492ca (patch) | |
tree | 74792c90dc686ae6b718538611f9d8272f4d38fa | |
parent | 04c93b98e9e4593aa2e6701bb08f5e27c3544d8a (diff) |
xwayland: Implement support for touchpad gestures
The implementation is relatively straightforward because both wayland
and Xorg use libinput semantics for touchpad gestures.
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
-rw-r--r-- | hw/xwayland/meson.build | 3 | ||||
-rw-r--r-- | hw/xwayland/xwayland-input.c | 238 | ||||
-rw-r--r-- | hw/xwayland/xwayland-input.h | 7 | ||||
-rw-r--r-- | hw/xwayland/xwayland-screen.h | 1 |
4 files changed, 249 insertions, 0 deletions
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 1dea64bff..093d7552b 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -36,6 +36,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') +gestures_xml = join_paths(protodir, 'unstable', 'pointer-gestures', 'pointer-gestures-unstable-v1.xml') tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml') kbgrab_xml = join_paths(protodir, 'unstable', 'xwayland-keyboard-grab', 'xwayland-keyboard-grab-unstable-v1.xml') xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unstable-v1.xml') @@ -60,6 +61,7 @@ code = generator(scanner, ) srcs += client_header.process(relative_xml) srcs += client_header.process(pointer_xml) +srcs += client_header.process(gestures_xml) srcs += client_header.process(tablet_xml) srcs += client_header.process(kbgrab_xml) srcs += client_header.process(xdg_output_xml) @@ -68,6 +70,7 @@ srcs += client_header.process(viewporter_xml) srcs += client_header.process(xdg_shell_xml) srcs += code.process(relative_xml) srcs += code.process(pointer_xml) +srcs += code.process(gestures_xml) srcs += code.process(tablet_xml) srcs += code.process(kbgrab_xml) srcs += code.process(xdg_output_xml) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index f5c24048f..db73c3528 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -47,6 +47,7 @@ #include "pointer-constraints-unstable-v1-client-protocol.h" #include "relative-pointer-unstable-v1-client-protocol.h" #include "tablet-unstable-v2-client-protocol.h" +#include "pointer-gestures-unstable-v1-client-protocol.h" #include "xwayland-keyboard-grab-unstable-v1-client-protocol.h" struct axis_discrete_pending { @@ -242,6 +243,51 @@ xwl_pointer_proc_relative(DeviceIntPtr device, int what) #undef NAXES } +static int +xwl_pointer_proc_pointer_gestures(DeviceIntPtr device, int what) +{ +#define NTOUCHPOINTS 20 +#define NAXES 2 + Atom axes_labels[NAXES] = { 0 }; + + switch (what) { + case DEVICE_INIT: + device->public.on = FALSE; + + /* We need to setup a pointer device so that the device is attached to + master pointer device. + */ + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + + if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels, + GetMotionHistorySize(), Relative)) + return BadValue; + + InitValuatorAxisStruct(device, 0, axes_labels[0], + NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative); + InitValuatorAxisStruct(device, 1, axes_labels[1], + NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative); + + InitGestureClassDeviceStruct(device, NTOUCHPOINTS); + 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 NTOUCHPOINTS +#undef NAXES +} + static void xwl_keyboard_control(DeviceIntPtr device, KeybdCtrl *ctrl) { @@ -756,6 +802,132 @@ static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = }; static void +pointer_gesture_swipe_handle_begin(void *data, + struct zwp_pointer_gesture_swipe_v1 *swipe, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + struct xwl_seat *xwl_seat = data; + + xwl_seat->pointer_gesture_swipe_fingers = fingers; + QueueGestureSwipeEvents(xwl_seat->pointer_gestures, + XI_GestureSwipeBegin, fingers, 0, 0.0, 0.0, 0.0, 0.0); +} + +static void +pointer_gesture_swipe_handle_update(void *data, + struct zwp_pointer_gesture_swipe_v1 *swipe, + uint32_t time, + wl_fixed_t dxf, + wl_fixed_t dyf) +{ + struct xwl_seat *xwl_seat = data; + double dx = wl_fixed_to_double(dxf); + double dy = wl_fixed_to_double(dyf); + + QueueGestureSwipeEvents(xwl_seat->pointer_gestures, + XI_GestureSwipeUpdate, + xwl_seat->pointer_gesture_swipe_fingers, + 0, + dx, dy, + dx, dy); +} + +static void +pointer_gesture_swipe_handle_end(void *data, + struct zwp_pointer_gesture_swipe_v1 *swipe, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + struct xwl_seat *xwl_seat = data; + uint32_t flags = 0; + + if (cancelled) + flags |= XIGestureSwipeEventCancelled; + + QueueGestureSwipeEvents(xwl_seat->pointer_gestures, + XI_GestureSwipeEnd, + xwl_seat->pointer_gesture_swipe_fingers, + flags, 0.0, 0.0, 0.0, 0.0); +} + +static const struct zwp_pointer_gesture_swipe_v1_listener pointer_gesture_swipe_listener = { + pointer_gesture_swipe_handle_begin, + pointer_gesture_swipe_handle_update, + pointer_gesture_swipe_handle_end +}; + +static void +pointer_gesture_pinch_handle_begin(void *data, + struct zwp_pointer_gesture_pinch_v1 *pinch, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + struct xwl_seat *xwl_seat = data; + + xwl_seat->pointer_gesture_pinch_fingers = fingers; + xwl_seat->pointer_gesture_pinch_last_scale = 1.0; + QueueGesturePinchEvents(xwl_seat->pointer_gestures, + XI_GesturePinchBegin, fingers, 0, 0.0, 0.0, 0.0, 0.0, + 1.0, 0.0); +} + +static void +pointer_gesture_pinch_handle_update(void *data, + struct zwp_pointer_gesture_pinch_v1 *pinch, + uint32_t time, + wl_fixed_t dxf, + wl_fixed_t dyf, + wl_fixed_t scalef, + wl_fixed_t rotation) +{ + struct xwl_seat *xwl_seat = data; + double dx = wl_fixed_to_double(dxf); + double dy = wl_fixed_to_double(dyf); + double scale = wl_fixed_to_double(scalef); + + xwl_seat->pointer_gesture_pinch_last_scale = scale; + QueueGesturePinchEvents(xwl_seat->pointer_gestures, + XI_GesturePinchUpdate, + xwl_seat->pointer_gesture_pinch_fingers, + 0, + dx, dy, + dx, dy, + scale, wl_fixed_to_double(rotation)); +} + +static void +pointer_gesture_pinch_handle_end(void *data, + struct zwp_pointer_gesture_pinch_v1 *pinch, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + struct xwl_seat *xwl_seat = data; + uint32_t flags = 0; + + if (cancelled) + flags |= XIGesturePinchEventCancelled; + + QueueGesturePinchEvents(xwl_seat->pointer_gestures, + XI_GesturePinchEnd, + xwl_seat->pointer_gesture_pinch_fingers, + flags, 0.0, 0.0, 0.0, 0.0, + xwl_seat->pointer_gesture_pinch_last_scale, 0.0); +} + +static const struct zwp_pointer_gesture_pinch_v1_listener pointer_gesture_pinch_listener = { + pointer_gesture_pinch_handle_begin, + pointer_gesture_pinch_handle_update, + pointer_gesture_pinch_handle_end +}; + +static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { @@ -1332,6 +1504,58 @@ release_relative_pointer(struct xwl_seat *xwl_seat) } static void +init_pointer_gestures_device(struct xwl_seat *xwl_seat) +{ + struct zwp_pointer_gestures_v1 *pointer_gestures = + xwl_seat->xwl_screen->pointer_gestures; + + if (pointer_gestures) { + xwl_seat->wp_pointer_gesture_swipe = + zwp_pointer_gestures_v1_get_swipe_gesture(pointer_gestures, + xwl_seat->wl_pointer); + zwp_pointer_gesture_swipe_v1_set_user_data(xwl_seat->wp_pointer_gesture_swipe, + xwl_seat); + zwp_pointer_gesture_swipe_v1_add_listener(xwl_seat->wp_pointer_gesture_swipe, + &pointer_gesture_swipe_listener, + xwl_seat); + + xwl_seat->wp_pointer_gesture_pinch = + zwp_pointer_gestures_v1_get_pinch_gesture(pointer_gestures, + xwl_seat->wl_pointer); + zwp_pointer_gesture_pinch_v1_set_user_data(xwl_seat->wp_pointer_gesture_pinch, + xwl_seat); + zwp_pointer_gesture_pinch_v1_add_listener(xwl_seat->wp_pointer_gesture_pinch, + &pointer_gesture_pinch_listener, + xwl_seat); + } + + if (xwl_seat->pointer_gestures == NULL) { + xwl_seat->pointer_gestures = + add_device(xwl_seat, "xwayland-pointer-gestures", + xwl_pointer_proc_pointer_gestures); + ActivateDevice(xwl_seat->pointer_gestures, TRUE); + } + enable_device(xwl_seat, xwl_seat->pointer_gestures); +} + +static void +release_pointer_gestures_device(struct xwl_seat *xwl_seat) +{ + if (xwl_seat->wp_pointer_gesture_swipe) { + zwp_pointer_gesture_swipe_v1_destroy(xwl_seat->wp_pointer_gesture_swipe); + xwl_seat->wp_pointer_gesture_swipe = NULL; + } + + if (xwl_seat->wp_pointer_gesture_pinch) { + zwp_pointer_gesture_pinch_v1_destroy(xwl_seat->wp_pointer_gesture_pinch); + xwl_seat->wp_pointer_gesture_pinch = NULL; + } + + if (xwl_seat->pointer_gestures) + disable_device(xwl_seat->pointer_gestures); +} + +static void init_keyboard(struct xwl_seat *xwl_seat) { DeviceIntPtr master; @@ -1403,9 +1627,11 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, if (caps & WL_SEAT_CAPABILITY_POINTER && xwl_seat->wl_pointer == NULL) { init_pointer(xwl_seat); init_relative_pointer(xwl_seat); + init_pointer_gestures_device(xwl_seat); } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && xwl_seat->wl_pointer) { release_pointer(xwl_seat); release_relative_pointer(xwl_seat); + release_pointer_gestures_device(xwl_seat); } if (caps & WL_SEAT_CAPABILITY_KEYBOARD && xwl_seat->wl_keyboard == NULL) { @@ -2556,6 +2782,16 @@ init_pointer_constraints(struct xwl_screen *xwl_screen, } static void +init_pointer_gestures(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) +{ + xwl_screen->pointer_gestures = + wl_registry_bind(xwl_screen->registry, id, + &zwp_pointer_gestures_v1_interface, + 1); +} + +static void init_keyboard_grab(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version) { @@ -2589,6 +2825,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_pointer_gestures_v1") == 0) { + init_pointer_gestures(xwl_screen, id, version); } else if (strcmp(interface, "zwp_tablet_manager_v2") == 0) { init_tablet_manager(xwl_screen, id, version); } else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) { diff --git a/hw/xwayland/xwayland-input.h b/hw/xwayland/xwayland-input.h index 0c6591b5e..dbe215bdb 100644 --- a/hw/xwayland/xwayland-input.h +++ b/hw/xwayland/xwayland-input.h @@ -56,6 +56,7 @@ struct xwl_cursor { struct xwl_seat { DeviceIntPtr pointer; DeviceIntPtr relative_pointer; + DeviceIntPtr pointer_gestures; DeviceIntPtr keyboard; DeviceIntPtr touch; DeviceIntPtr stylus; @@ -65,6 +66,8 @@ struct xwl_seat { struct wl_seat *seat; struct wl_pointer *wl_pointer; struct zwp_relative_pointer_v1 *wp_relative_pointer; + struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe; + struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch; struct wl_keyboard *wl_keyboard; struct wl_touch *wl_touch; struct zwp_tablet_seat_v2 *tablet_seat; @@ -80,6 +83,10 @@ struct xwl_seat { struct xwl_cursor cursor; WindowPtr last_xwindow; + uint32_t pointer_gesture_swipe_fingers; + uint32_t pointer_gesture_pinch_fingers; + double pointer_gesture_pinch_last_scale; + struct xorg_list touches; size_t keymap_size; diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index b965dddd7..137e94b55 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -82,6 +82,7 @@ struct xwl_screen { struct xdg_wm_base *xdg_wm_base; struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; struct zwp_pointer_constraints_v1 *pointer_constraints; + struct zwp_pointer_gestures_v1 *pointer_gestures; struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab; struct zwp_linux_dmabuf_v1 *dmabuf; struct zxdg_output_manager_v1 *xdg_output_manager; |