diff --git a/pointer-gestures-unstable-v1.xml b/pointer-gestures-unstable-v1.xml
new file mode 100644
index 0000000..f92a116
--- /dev/null
+++ b/pointer-gestures-unstable-v1.xml
@@ -0,0 +1,253 @@
+
+
+
+
+
+ A global interface to provide semantic touchpad gestures for a given
+ pointer.
+
+ Three gestures are currently supported: swipe, pinch, and hold.
+ Pinch and swipe gestures follow a three-stage cycle: begin, update,
+ end, hold gestures follow a two-stage cycle: begin and end. All
+ gestures are identified by a unique id.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+
+
+
+
+ Create a swipe gesture object. See the
+ wl_pointer_gesture_swipe interface for details.
+
+
+
+
+
+
+
+ Create a pinch gesture object. See the
+ wl_pointer_gesture_pinch interface for details.
+
+
+
+
+
+
+
+
+
+ Destroy the pointer gesture object. Swipe, pinch and hold objects
+ created via this gesture object remain valid.
+
+
+
+
+
+
+
+ Create a hold gesture object. See the
+ wl_pointer_gesture_hold interface for details.
+
+
+
+
+
+
+
+
+
+ A swipe gesture object notifies a client about a multi-finger swipe
+ gesture detected on an indirect input device such as a touchpad.
+ The gesture is usually initiated by multiple fingers moving in the
+ same direction but once initiated the direction may change.
+ The precise conditions of when such a gesture is detected are
+ implementation-dependent.
+
+ A gesture consists of three stages: begin, update (optional) and end.
+ There cannot be multiple simultaneous hold, pinch or swipe gestures on a
+ same pointer/seat, how compositors prevent these situations is
+ implementation-dependent.
+
+ A gesture may be cancelled by the compositor or the hardware.
+ Clients should not consider performing permanent or irreversible
+ actions until the end of a gesture has been received.
+
+
+
+
+
+
+
+
+ This event is sent when a multi-finger swipe gesture is detected
+ on the device.
+
+
+
+
+
+
+
+
+
+ This event is sent when a multi-finger swipe gesture changes the
+ position of the logical center.
+
+ The dx and dy coordinates are relative coordinates of the logical
+ center of the gesture compared to the previous event.
+
+
+
+
+
+
+
+
+ This event is sent when a multi-finger swipe gesture ceases to
+ be valid. This may happen when one or more fingers are lifted or
+ the gesture is cancelled.
+
+ When a gesture is cancelled, the client should undo state changes
+ caused by this gesture. What causes a gesture to be cancelled is
+ implementation-dependent.
+
+
+
+
+
+
+
+
+
+ A pinch gesture object notifies a client about a multi-finger pinch
+ gesture detected on an indirect input device such as a touchpad.
+ The gesture is usually initiated by multiple fingers moving towards
+ each other or away from each other, or by two or more fingers rotating
+ around a logical center of gravity. The precise conditions of when
+ such a gesture is detected are implementation-dependent.
+
+ A gesture consists of three stages: begin, update (optional) and end.
+ There cannot be multiple simultaneous hold, pinch or swipe gestures on a
+ same pointer/seat, how compositors prevent these situations is
+ implementation-dependent.
+
+ A gesture may be cancelled by the compositor or the hardware.
+ Clients should not consider performing permanent or irreversible
+ actions until the end of a gesture has been received.
+
+
+
+
+
+
+
+
+ This event is sent when a multi-finger pinch gesture is detected
+ on the device.
+
+
+
+
+
+
+
+
+
+ This event is sent when a multi-finger pinch gesture changes the
+ position of the logical center, the rotation or the relative scale.
+
+ The dx and dy coordinates are relative coordinates in the
+ surface coordinate space of the logical center of the gesture.
+
+ The scale factor is an absolute scale compared to the
+ pointer_gesture_pinch.begin event, e.g. a scale of 2 means the fingers
+ are now twice as far apart as on pointer_gesture_pinch.begin.
+
+ The rotation is the relative angle in degrees clockwise compared to the previous
+ pointer_gesture_pinch.begin or pointer_gesture_pinch.update event.
+
+
+
+
+
+
+
+
+
+
+ This event is sent when a multi-finger pinch gesture ceases to
+ be valid. This may happen when one or more fingers are lifted or
+ the gesture is cancelled.
+
+ When a gesture is cancelled, the client should undo state changes
+ caused by this gesture. What causes a gesture to be cancelled is
+ implementation-dependent.
+
+
+
+
+
+
+
+
+
+
+ A hold gesture object notifies a client about a single- or
+ multi-finger hold gesture detected on an indirect input device such as
+ a touchpad. The gesture is usually initiated by one or more fingers
+ being held down without significant movement. The precise conditions
+ of when such a gesture is detected are implementation-dependent.
+
+ In particular, this gesture may be used to cancel kinetic scrolling.
+
+ A hold gesture consists of two stages: begin and end. Unlike pinch and
+ swipe there is no update stage.
+ There cannot be multiple simultaneous hold, pinch or swipe gestures on a
+ same pointer/seat, how compositors prevent these situations is
+ implementation-dependent.
+
+ A gesture may be cancelled by the compositor or the hardware.
+ Clients should not consider performing permanent or irreversible
+ actions until the end of a gesture has been received.
+
+
+
+
+
+
+
+
+ This event is sent when a hold gesture is detected on the device.
+
+
+
+
+
+
+
+
+
+ This event is sent when a hold gesture ceases to
+ be valid. This may happen when the holding fingers are lifted or
+ the gesture is cancelled, for example if the fingers move past an
+ implementation-defined threshold, the finger count changes or the hold
+ gesture changes into a different type of gesture.
+
+ When a gesture is cancelled, the client may need to undo state changes
+ caused by this gesture. What causes a gesture to be cancelled is
+ implementation-dependent.
+
+
+
+
+
+
+
+
diff --git a/pointer_gestures.c b/pointer_gestures.c
new file mode 100644
index 0000000..cf49559
--- /dev/null
+++ b/pointer_gestures.c
@@ -0,0 +1,205 @@
+/* Wayland compositor running on top of an X server.
+
+Copyright (C) 2022 to various contributors.
+
+This file is part of 12to11.
+
+12to11 is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+12to11 is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with 12to11. If not, see . */
+
+#include "compositor.h"
+#include "pointer-gestures-unstable-v1.h"
+
+/* The struct zwp_pointer_gestures_v1 global. */
+static struct wl_global *pointer_gestures_global;
+
+static void
+DestroySwipeGesture (struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static struct zwp_pointer_gesture_swipe_v1_interface gesture_swipe_impl =
+ {
+ .destroy = DestroySwipeGesture,
+ };
+
+static void
+HandleSwipeGestureResourceDestroy (struct wl_resource *resource)
+{
+ SwipeGesture *gesture;
+
+ gesture = wl_resource_get_user_data (resource);
+ XLSeatDestroySwipeGesture (gesture);
+}
+
+
+
+static void
+DestroyPinchGesture (struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static struct zwp_pointer_gesture_pinch_v1_interface gesture_pinch_impl =
+ {
+ .destroy = DestroyPinchGesture,
+ };
+
+static void
+HandlePinchGestureResourceDestroy (struct wl_resource *resource)
+{
+ PinchGesture *gesture;
+
+ gesture = wl_resource_get_user_data (resource);
+ XLSeatDestroyPinchGesture (gesture);
+}
+
+
+
+static void
+DestroyHoldGesture (struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static struct zwp_pointer_gesture_hold_v1_interface gesture_hold_impl =
+ {
+ .destroy = DestroyHoldGesture,
+ };
+
+
+
+static void
+GetSwipeGesture (struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, struct wl_resource *pointer_resource)
+{
+ struct wl_resource *gesture_resource;
+ Pointer *pointer;
+ Seat *seat;
+ SwipeGesture *gesture_swipe;
+
+ pointer = wl_resource_get_user_data (pointer_resource);
+ seat = XLPointerGetSeat (pointer);
+ gesture_resource
+ = wl_resource_create (client,
+ &zwp_pointer_gesture_swipe_v1_interface,
+ wl_resource_get_version (resource), id);
+
+ if (!gesture_resource)
+ {
+ wl_resource_post_no_memory (resource);
+ return;
+ }
+
+ gesture_swipe = XLSeatGetSwipeGesture (seat, gesture_resource);
+ wl_resource_set_implementation (gesture_resource, &gesture_swipe_impl,
+ gesture_swipe,
+ HandleSwipeGestureResourceDestroy);
+}
+
+static void
+GetPinchGesture (struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, struct wl_resource *pointer_resource)
+{
+ struct wl_resource *gesture_resource;
+ Pointer *pointer;
+ Seat *seat;
+ PinchGesture *gesture_pinch;
+
+ pointer = wl_resource_get_user_data (pointer_resource);
+ seat = XLPointerGetSeat (pointer);
+ gesture_resource
+ = wl_resource_create (client,
+ &zwp_pointer_gesture_pinch_v1_interface,
+ wl_resource_get_version (resource), id);
+
+ if (!gesture_resource)
+ {
+ wl_resource_post_no_memory (resource);
+ return;
+ }
+
+ gesture_pinch = XLSeatGetPinchGesture (seat, gesture_resource);
+ wl_resource_set_implementation (gesture_resource, &gesture_pinch_impl,
+ gesture_pinch,
+ HandlePinchGestureResourceDestroy);
+}
+
+static void
+Release (struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static void
+GetHoldGesture (struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, struct wl_resource *pointer_resource)
+{
+ struct wl_resource *gesture_resource;
+
+ /* Hold gestures are not supported by the X Input extension, so a
+ dummy resource is created that just does nothing. */
+ gesture_resource
+ = wl_resource_create (client, &zwp_pointer_gesture_hold_v1_interface,
+ wl_resource_get_version (resource), id);
+
+ if (!gesture_resource)
+ {
+ wl_resource_post_no_memory (resource);
+ return;
+ }
+
+ wl_resource_set_implementation (gesture_resource, &gesture_hold_impl,
+ NULL, NULL);
+}
+
+static struct zwp_pointer_gestures_v1_interface pointer_gestures_impl =
+ {
+ .get_swipe_gesture = GetSwipeGesture,
+ .get_pinch_gesture = GetPinchGesture,
+ .release = Release,
+ .get_hold_gesture = GetHoldGesture,
+ };
+
+static void
+HandleBind (struct wl_client *client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create (client, &zwp_pointer_gestures_v1_interface,
+ version, id);
+
+ if (!resource)
+ {
+ wl_client_post_no_memory (client);
+ return;
+ }
+
+ wl_resource_set_implementation (resource, &pointer_gestures_impl,
+ NULL, NULL);
+}
+
+void
+XLInitPointerGestures (void)
+{
+ if (xi2_major > 2 || xi2_minor >= 4)
+ /* Create the pointer gestures global. */
+ pointer_gestures_global
+ = wl_global_create (compositor.wl_display,
+ &zwp_pointer_gestures_v1_interface,
+ 3, NULL, HandleBind);
+
+ /* Pointer gestures are not supported without XI 2.4 or later. */
+}