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>
This commit is contained in:
Povilas Kanapickas 2021-12-03 02:40:58 +02:00
parent 04c93b98e9
commit ff2de0b87e
4 changed files with 249 additions and 0 deletions

View File

@ -36,6 +36,7 @@ protodir = protocols_dep.get_pkgconfig_variable('pkgdatadir')
pointer_xml = join_paths(protodir, 'unstable', 'pointer-constraints', 'pointer-constraints-unstable-v1.xml') 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') 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') 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') 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') 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(relative_xml)
srcs += client_header.process(pointer_xml) srcs += client_header.process(pointer_xml)
srcs += client_header.process(gestures_xml)
srcs += client_header.process(tablet_xml) srcs += client_header.process(tablet_xml)
srcs += client_header.process(kbgrab_xml) srcs += client_header.process(kbgrab_xml)
srcs += client_header.process(xdg_output_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 += client_header.process(xdg_shell_xml)
srcs += code.process(relative_xml) srcs += code.process(relative_xml)
srcs += code.process(pointer_xml) srcs += code.process(pointer_xml)
srcs += code.process(gestures_xml)
srcs += code.process(tablet_xml) srcs += code.process(tablet_xml)
srcs += code.process(kbgrab_xml) srcs += code.process(kbgrab_xml)
srcs += code.process(xdg_output_xml) srcs += code.process(xdg_output_xml)

View File

@ -47,6 +47,7 @@
#include "pointer-constraints-unstable-v1-client-protocol.h" #include "pointer-constraints-unstable-v1-client-protocol.h"
#include "relative-pointer-unstable-v1-client-protocol.h" #include "relative-pointer-unstable-v1-client-protocol.h"
#include "tablet-unstable-v2-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" #include "xwayland-keyboard-grab-unstable-v1-client-protocol.h"
struct axis_discrete_pending { struct axis_discrete_pending {
@ -242,6 +243,51 @@ xwl_pointer_proc_relative(DeviceIntPtr device, int what)
#undef NAXES #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 static void
xwl_keyboard_control(DeviceIntPtr device, KeybdCtrl *ctrl) xwl_keyboard_control(DeviceIntPtr device, KeybdCtrl *ctrl)
{ {
@ -755,6 +801,132 @@ static const struct zwp_relative_pointer_v1_listener relative_pointer_listener =
relative_pointer_handle_relative_motion, relative_pointer_handle_relative_motion,
}; };
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 static void
keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial,
uint32_t time, uint32_t key, uint32_t state) uint32_t time, uint32_t key, uint32_t state)
@ -1331,6 +1503,58 @@ release_relative_pointer(struct xwl_seat *xwl_seat)
disable_device(xwl_seat->relative_pointer); disable_device(xwl_seat->relative_pointer);
} }
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 static void
init_keyboard(struct xwl_seat *xwl_seat) init_keyboard(struct xwl_seat *xwl_seat)
{ {
@ -1403,9 +1627,11 @@ seat_handle_capabilities(void *data, struct wl_seat *seat,
if (caps & WL_SEAT_CAPABILITY_POINTER && xwl_seat->wl_pointer == NULL) { if (caps & WL_SEAT_CAPABILITY_POINTER && xwl_seat->wl_pointer == NULL) {
init_pointer(xwl_seat); init_pointer(xwl_seat);
init_relative_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) { } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && xwl_seat->wl_pointer) {
release_pointer(xwl_seat); release_pointer(xwl_seat);
release_relative_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) { if (caps & WL_SEAT_CAPABILITY_KEYBOARD && xwl_seat->wl_keyboard == NULL) {
@ -2555,6 +2781,16 @@ init_pointer_constraints(struct xwl_screen *xwl_screen,
1); 1);
} }
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 static void
init_keyboard_grab(struct xwl_screen *xwl_screen, init_keyboard_grab(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version) 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); init_relative_pointer_manager(xwl_screen, id, version);
} else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) { } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
init_pointer_constraints(xwl_screen, id, version); 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) { } else if (strcmp(interface, "zwp_tablet_manager_v2") == 0) {
init_tablet_manager(xwl_screen, id, version); init_tablet_manager(xwl_screen, id, version);
} else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) { } else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) {

View File

@ -56,6 +56,7 @@ struct xwl_cursor {
struct xwl_seat { struct xwl_seat {
DeviceIntPtr pointer; DeviceIntPtr pointer;
DeviceIntPtr relative_pointer; DeviceIntPtr relative_pointer;
DeviceIntPtr pointer_gestures;
DeviceIntPtr keyboard; DeviceIntPtr keyboard;
DeviceIntPtr touch; DeviceIntPtr touch;
DeviceIntPtr stylus; DeviceIntPtr stylus;
@ -65,6 +66,8 @@ struct xwl_seat {
struct wl_seat *seat; struct wl_seat *seat;
struct wl_pointer *wl_pointer; struct wl_pointer *wl_pointer;
struct zwp_relative_pointer_v1 *wp_relative_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_keyboard *wl_keyboard;
struct wl_touch *wl_touch; struct wl_touch *wl_touch;
struct zwp_tablet_seat_v2 *tablet_seat; struct zwp_tablet_seat_v2 *tablet_seat;
@ -80,6 +83,10 @@ struct xwl_seat {
struct xwl_cursor cursor; struct xwl_cursor cursor;
WindowPtr last_xwindow; 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; struct xorg_list touches;
size_t keymap_size; size_t keymap_size;

View File

@ -82,6 +82,7 @@ struct xwl_screen {
struct xdg_wm_base *xdg_wm_base; struct xdg_wm_base *xdg_wm_base;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints; 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_xwayland_keyboard_grab_manager_v1 *wp_grab;
struct zwp_linux_dmabuf_v1 *dmabuf; struct zwp_linux_dmabuf_v1 *dmabuf;
struct zxdg_output_manager_v1 *xdg_output_manager; struct zxdg_output_manager_v1 *xdg_output_manager;