diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
index fbf3178b9..9d4d36ec3 100644
--- a/clutter/clutter/clutter-actor.c
+++ b/clutter/clutter/clutter-actor.c
@@ -13994,6 +13994,7 @@ clutter_actor_event (ClutterActor *actor,
break;
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
+ case CLUTTER_TOUCHPAD_HOLD:
detail = quark_touchpad;
break;
case CLUTTER_PROXIMITY_IN:
diff --git a/clutter/clutter/clutter-enums.h b/clutter/clutter/clutter-enums.h
index a12e7ec63..92bac41fd 100644
--- a/clutter/clutter/clutter-enums.h
+++ b/clutter/clutter/clutter-enums.h
@@ -896,6 +896,11 @@ typedef enum /*< flags prefix=CLUTTER_EVENT >*/
* determined by its phase field; event added in 1.24
* @CLUTTER_TOUCHPAD_SWIPE: A swipe gesture event, the current state is
* determined by its phase field; event added in 1.24
+ * @CLUTTER_TOUCHPAD_HOLD: A hold gesture event, the current state is
+ * determined by its phase field. A hold gesture starts when the user places a
+ * finger on the touchpad and ends when all fingers are lifted. It is
+ * cancelled when the finger(s) move past a certain threshold.
+ * Event added in 6.5
* @CLUTTER_PROXIMITY_IN: A tool entered in proximity to a tablet;
* event added in 1.28
* @CLUTTER_PROXIMITY_OUT: A tool left from the proximity area of a tablet;
@@ -928,6 +933,7 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_TOUCH_CANCEL,
CLUTTER_TOUCHPAD_PINCH,
CLUTTER_TOUCHPAD_SWIPE,
+ CLUTTER_TOUCHPAD_HOLD,
CLUTTER_PROXIMITY_IN,
CLUTTER_PROXIMITY_OUT,
CLUTTER_PAD_BUTTON_PRESS,
diff --git a/clutter/clutter/clutter-event.c b/clutter/clutter/clutter-event.c
index 43ca0e5de..ebc7e8f2f 100644
--- a/clutter/clutter/clutter-event.c
+++ b/clutter/clutter/clutter-event.c
@@ -457,6 +457,11 @@ clutter_event_get_position (const ClutterEvent *event,
graphene_point_init (position, event->touchpad_swipe.x,
event->touchpad_swipe.y);
break;
+
+ case CLUTTER_TOUCHPAD_HOLD:
+ graphene_point_init (position, event->touchpad_hold.x,
+ event->touchpad_hold.y);
+ break;
}
}
@@ -540,6 +545,11 @@ clutter_event_set_coords (ClutterEvent *event,
event->touchpad_swipe.x = x;
event->touchpad_swipe.y = y;
break;
+
+ case CLUTTER_TOUCHPAD_HOLD:
+ event->touchpad_hold.x = x;
+ event->touchpad_hold.y = y;
+ break;
}
}
@@ -1154,6 +1164,7 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
+ case CLUTTER_TOUCHPAD_HOLD:
/* Rely on priv data for these */
break;
@@ -1259,6 +1270,7 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
+ case CLUTTER_TOUCHPAD_HOLD:
/* Rely on priv data for these */
break;
@@ -1814,6 +1826,7 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
+ case CLUTTER_TOUCHPAD_HOLD:
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
@@ -2073,12 +2086,15 @@ clutter_event_get_touchpad_gesture_finger_count (const ClutterEvent *event)
{
g_return_val_if_fail (event != NULL, 0);
g_return_val_if_fail (event->type == CLUTTER_TOUCHPAD_SWIPE ||
- event->type == CLUTTER_TOUCHPAD_PINCH, 0);
+ event->type == CLUTTER_TOUCHPAD_PINCH ||
+ event->type == CLUTTER_TOUCHPAD_HOLD, 0);
if (event->type == CLUTTER_TOUCHPAD_SWIPE)
return event->touchpad_swipe.n_fingers;
else if (event->type == CLUTTER_TOUCHPAD_PINCH)
return event->touchpad_pinch.n_fingers;
+ else if (event->type == CLUTTER_TOUCHPAD_HOLD)
+ return event->touchpad_hold.n_fingers;
return 0;
}
@@ -2137,12 +2153,15 @@ clutter_event_get_gesture_phase (const ClutterEvent *event)
{
g_return_val_if_fail (event != NULL, 0);
g_return_val_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH ||
- event->type == CLUTTER_TOUCHPAD_SWIPE, 0);
+ event->type == CLUTTER_TOUCHPAD_SWIPE ||
+ event->type == CLUTTER_TOUCHPAD_HOLD, 0);
if (event->type == CLUTTER_TOUCHPAD_PINCH)
return event->touchpad_pinch.phase;
else if (event->type == CLUTTER_TOUCHPAD_SWIPE)
return event->touchpad_swipe.phase;
+ else if (event->type == CLUTTER_TOUCHPAD_HOLD)
+ return event->touchpad_hold.phase;
/* Shouldn't ever happen */
return CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN;
@@ -2168,7 +2187,8 @@ clutter_event_get_gesture_motion_delta (const ClutterEvent *event,
{
g_return_if_fail (event != NULL);
g_return_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH ||
- event->type == CLUTTER_TOUCHPAD_SWIPE);
+ event->type == CLUTTER_TOUCHPAD_SWIPE ||
+ event->type == CLUTTER_TOUCHPAD_HOLD);
if (event->type == CLUTTER_TOUCHPAD_PINCH)
{
@@ -2184,6 +2204,13 @@ clutter_event_get_gesture_motion_delta (const ClutterEvent *event,
if (dy)
*dy = event->touchpad_swipe.dy;
}
+ else if (event->type == CLUTTER_TOUCHPAD_HOLD)
+ {
+ if (dx)
+ *dx = 0;
+ if (dy)
+ *dy = 0;
+ }
}
/**
diff --git a/clutter/clutter/clutter-event.h b/clutter/clutter/clutter-event.h
index 7afdb4a6d..78bd7f42d 100644
--- a/clutter/clutter/clutter-event.h
+++ b/clutter/clutter/clutter-event.h
@@ -117,6 +117,7 @@ typedef struct _ClutterCrossingEvent ClutterCrossingEvent;
typedef struct _ClutterTouchEvent ClutterTouchEvent;
typedef struct _ClutterTouchpadPinchEvent ClutterTouchpadPinchEvent;
typedef struct _ClutterTouchpadSwipeEvent ClutterTouchpadSwipeEvent;
+typedef struct _ClutterTouchpadHoldEvent ClutterTouchpadHoldEvent;
typedef struct _ClutterProximityEvent ClutterProximityEvent;
typedef struct _ClutterPadButtonEvent ClutterPadButtonEvent;
typedef struct _ClutterPadStripEvent ClutterPadStripEvent;
@@ -500,6 +501,43 @@ struct _ClutterTouchpadSwipeEvent
gfloat dy;
};
+/**
+ * ClutterTouchpadHoldEvent
+ * @type: event type
+ * @time: event time
+ * @flags: event flags
+ * @stage: event source stage
+ * @source: event source actor (unused)
+ * @phase: the current phase of the gesture
+ * @n_fingers: the number of fingers triggering the swipe
+ * @x: the X coordinate of the pointer, relative to the stage
+ * @y: the Y coordinate of the pointer, relative to the stage
+ *
+ * Used for touchpad hold gesture events. The current state of the
+ * gesture will be determined by the @phase field.
+ *
+ * A hold gesture starts when the user places one or many fingers on the
+ * touchpad and ends when all fingers are lifted. It is cancelled when the
+ * finger(s) move past a certain threshold.
+ * Unlike swipe and pinch, @phase can only be
+ * CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN, CLUTTER_TOUCHPAD_GESTURE_PHASE_END and
+ * CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL.
+ */
+struct _ClutterTouchpadHoldEvent
+{
+ ClutterEventType type;
+ guint32 time;
+ ClutterEventFlags flags;
+ ClutterStage *stage;
+ ClutterActor *source;
+
+ ClutterTouchpadGesturePhase phase;
+ uint32_t n_fingers;
+ float x;
+ float y;
+};
+
+
struct _ClutterPadButtonEvent
{
ClutterEventType type;
@@ -592,6 +630,7 @@ union _ClutterEvent
ClutterTouchEvent touch;
ClutterTouchpadPinchEvent touchpad_pinch;
ClutterTouchpadSwipeEvent touchpad_swipe;
+ ClutterTouchpadHoldEvent touchpad_hold;
ClutterProximityEvent proximity;
ClutterPadButtonEvent pad_button;
ClutterPadStripEvent pad_strip;
diff --git a/clutter/clutter/clutter-main.c b/clutter/clutter/clutter-main.c
index b61e45cd2..27c48574d 100644
--- a/clutter/clutter/clutter-main.c
+++ b/clutter/clutter/clutter-main.c
@@ -1892,6 +1892,7 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_SCROLL:
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
+ case CLUTTER_TOUCHPAD_HOLD:
{
ClutterActor *actor;
gfloat x, y;
diff --git a/meson.build b/meson.build
index ee2c89b16..f9bf3b5d0 100644
--- a/meson.build
+++ b/meson.build
@@ -38,10 +38,10 @@ gudev_req = '>= 232'
# wayland version requirements
wayland_server_req = '>= 1.20'
-wayland_protocols_req = '>= 1.19'
+wayland_protocols_req = '>= 1.23'
# native backend version requirements
-libinput_req = '>= 1.7'
+libinput_req = '>= 1.19.0'
gbm_req = '>= 10.3'
# screen cast version requirements
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index b4f1b3f57..51f0225f7 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -1094,6 +1094,48 @@ notify_swipe_gesture_event (ClutterInputDevice *input_device,
queue_event (event);
}
+static void
+notify_hold_gesture_event (ClutterInputDevice *input_device,
+ ClutterTouchpadGesturePhase phase,
+ uint64_t time_us,
+ uint32_t n_fingers)
+{
+ MetaInputDeviceNative *device_evdev;
+ MetaSeatNative *seat;
+ ClutterStage *stage;
+ ClutterEvent *event = NULL;
+ graphene_point_t pos;
+
+ /* We can drop the event on the floor if no stage has been
+ * associated with the device yet. */
+ stage = _clutter_input_device_get_stage (input_device);
+ if (stage == NULL)
+ return;
+
+ device_evdev = META_INPUT_DEVICE_NATIVE (input_device);
+ seat = meta_input_device_native_get_seat (device_evdev);
+
+ event = clutter_event_new (CLUTTER_TOUCHPAD_HOLD);
+
+ meta_event_native_set_time_usec (event, time_us);
+ event->touchpad_hold.phase = phase;
+ event->touchpad_hold.time = us2ms (time_us);
+ event->touchpad_hold.stage = CLUTTER_STAGE (stage);
+
+ clutter_input_device_get_coords (seat->core_pointer, NULL, &pos);
+ event->touchpad_hold.x = pos.x;
+ event->touchpad_hold.y = pos.y;
+ event->touchpad_hold.n_fingers = n_fingers;
+
+ meta_xkb_translate_state (event, seat->xkb, seat->button_state);
+
+ clutter_event_set_device (event, seat->core_pointer);
+ clutter_event_set_source_device (event, input_device);
+
+ queue_event (event);
+}
+
+
static void
notify_proximity (ClutterInputDevice *input_device,
uint64_t time_us,
@@ -2187,6 +2229,28 @@ process_device_event (MetaSeatNative *seat,
time_us, n_fingers, dx, dy);
break;
}
+ case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
+ case LIBINPUT_EVENT_GESTURE_HOLD_END:
+ {
+ struct libinput_event_gesture *gesture_event =
+ libinput_event_get_gesture_event (event);
+ ClutterTouchpadGesturePhase phase;
+ uint32_t n_fingers;
+ uint64_t time_us;
+
+ device = libinput_device_get_user_data (libinput_device);
+ time_us = libinput_event_gesture_get_time_usec (gesture_event);
+ n_fingers = libinput_event_gesture_get_finger_count (gesture_event);
+
+ if (libinput_event_get_type (event) == LIBINPUT_EVENT_GESTURE_HOLD_BEGIN)
+ phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN;
+ else
+ phase = libinput_event_gesture_get_cancelled (gesture_event) ?
+ CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL : CLUTTER_TOUCHPAD_GESTURE_PHASE_END;
+
+ notify_hold_gesture_event (device, phase, time_us, n_fingers);
+ break;
+ }
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
{
process_tablet_axis (seat, event);
diff --git a/src/core/events.c b/src/core/events.c
index e16927cde..35839bd94 100644
--- a/src/core/events.c
+++ b/src/core/events.c
@@ -42,6 +42,7 @@
#define IS_GESTURE_EVENT(e) ((e)->type == CLUTTER_TOUCHPAD_SWIPE || \
(e)->type == CLUTTER_TOUCHPAD_PINCH || \
+ (e)->type == CLUTTER_TOUCHPAD_HOLD || \
(e)->type == CLUTTER_TOUCH_BEGIN || \
(e)->type == CLUTTER_TOUCH_UPDATE || \
(e)->type == CLUTTER_TOUCH_END || \
diff --git a/src/meson.build b/src/meson.build
index 838407eb4..e4be36537 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -530,6 +530,8 @@ if have_wayland
'wayland/meta-wayland-pointer.c',
'wayland/meta-wayland-pointer-constraints.c',
'wayland/meta-wayland-pointer-constraints.h',
+ 'wayland/meta-wayland-pointer-gesture-hold.c',
+ 'wayland/meta-wayland-pointer-gesture-hold.h',
'wayland/meta-wayland-pointer-gesture-pinch.c',
'wayland/meta-wayland-pointer-gesture-pinch.h',
'wayland/meta-wayland-pointer-gestures.c',
diff --git a/src/tests/clutter/conform/actor-event-hold.c b/src/tests/clutter/conform/actor-event-hold.c
new file mode 100644
index 000000000..3d0e01c80
--- /dev/null
+++ b/src/tests/clutter/conform/actor-event-hold.c
@@ -0,0 +1,137 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Author: José Expósito
+ */
+#include
+#include
+
+#include
+
+#include "tests/clutter-test-utils.h"
+
+#define EVENT_TIME 1000
+
+typedef struct {
+ ClutterTouchpadGesturePhase phase;
+ guint n_fingers;
+ gfloat x;
+ gfloat y;
+} HoldTestCase;
+
+static const HoldTestCase test_cases[] = {
+ {
+ .phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN,
+ .n_fingers = 1,
+ .x = 100,
+ .y = 150,
+ },
+ {
+ .phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_END,
+ .n_fingers = 2,
+ .x = 200,
+ .y = 250,
+ },
+ {
+ .phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL,
+ .n_fingers = 3,
+ .x = 300,
+ .y = 350,
+ },
+};
+
+static gboolean
+on_stage_captured_event (ClutterActor *stage,
+ ClutterEvent *event,
+ ClutterEvent **captured_event)
+{
+ *captured_event = clutter_event_copy (event);
+ return TRUE;
+}
+
+static void
+actor_event_hold (void)
+{
+ ClutterActor *stage;
+ ClutterBackend *backend;
+ ClutterSeat *seat;
+ ClutterInputDevice *device;
+ ClutterEvent *event;
+ ClutterEvent *captured_event;
+ size_t n_test_case;
+
+ /* Get the stage and listen for touchpad events */
+ stage = clutter_test_get_stage ();
+ g_signal_connect (stage, "captured-event::touchpad",
+ G_CALLBACK (on_stage_captured_event),
+ &captured_event);
+ clutter_actor_show (stage);
+
+ /* Get the input device*/
+ backend = clutter_get_default_backend ();
+ seat = clutter_backend_get_default_seat (backend);
+ device = clutter_seat_get_pointer (seat);
+
+ for (n_test_case = 0; n_test_case < G_N_ELEMENTS (test_cases); n_test_case++)
+ {
+ graphene_point_t actual_position;
+ gdouble *actual_axes;
+ ClutterTouchpadGesturePhase actual_phase;
+ guint actual_n_fingers;
+ gdouble dx, dy, udx, udy;
+
+ const HoldTestCase *test_case = test_cases + n_test_case;
+
+ /* Create a synthetic hold event */
+ event = clutter_event_new (CLUTTER_TOUCHPAD_HOLD);
+ event->touchpad_hold.phase = test_case->phase;
+ event->touchpad_hold.time = EVENT_TIME;
+ event->touchpad_hold.n_fingers = test_case->n_fingers;
+ event->touchpad_hold.stage = (ClutterStage *) stage;
+ event->touchpad_hold.source = stage;
+ clutter_event_set_coords (event, test_case->x, test_case->y);
+ clutter_event_set_device (event, device);
+
+ clutter_event_put (event);
+ clutter_event_free (event);
+
+ /* Capture the event received by the stage */
+ captured_event = NULL;
+ while (captured_event == NULL)
+ g_main_context_iteration (NULL, FALSE);
+
+ /* Check that expected the event params match the actual values */
+ clutter_event_get_position (captured_event, &actual_position);
+ actual_axes = clutter_event_get_axes (captured_event, 0);
+ actual_phase = clutter_event_get_gesture_phase (captured_event);
+ actual_n_fingers = clutter_event_get_touchpad_gesture_finger_count (captured_event);
+ clutter_event_get_gesture_motion_delta (captured_event, &dx, &dy);
+
+ g_assert (actual_position.x == test_case->x);
+ g_assert (actual_position.y == test_case->y);
+ g_assert_null (actual_axes);
+ g_assert (actual_phase == test_case->phase);
+ g_assert (actual_n_fingers == test_case->n_fingers);
+ g_assert (dx == 0);
+ g_assert (dy == 0);
+ g_assert (udx == 0);
+ g_assert (udy == 0);
+
+ clutter_event_free (captured_event);
+ }
+}
+
+CLUTTER_TEST_SUITE (
+ CLUTTER_TEST_UNIT ("/actor/event/hold", actor_event_hold)
+)
diff --git a/src/tests/clutter/conform/meson.build b/src/tests/clutter/conform/meson.build
index 35221bb8d..31f51e016 100644
--- a/src/tests/clutter/conform/meson.build
+++ b/src/tests/clutter/conform/meson.build
@@ -12,6 +12,7 @@ clutter_conform_tests_actor_tests = [
'actor-anchors',
'actor-clone',
'actor-destroy',
+ 'actor-event-hold',
'actor-graph',
'actor-invariants',
'actor-iter',
diff --git a/src/tests/clutter/interactive/test-events.c b/src/tests/clutter/interactive/test-events.c
index f31c7d228..7baa1dce5 100644
--- a/src/tests/clutter/interactive/test-events.c
+++ b/src/tests/clutter/interactive/test-events.c
@@ -361,6 +361,9 @@ input_cb (ClutterActor *actor,
case CLUTTER_TOUCHPAD_SWIPE:
g_print ("[%s] TOUCHPAD SWIPE", clutter_actor_get_name (source_actor));
break;
+ case CLUTTER_TOUCHPAD_HOLD:
+ g_print ("[%s] TOUCHPAD HOLD", clutter_actor_get_name (source_actor));
+ break;
case CLUTTER_PROXIMITY_IN:
g_print ("[%s] PROXIMITY IN", clutter_actor_get_name (source_actor));
break;
diff --git a/src/tests/clutter/interactive/test-grab.c b/src/tests/clutter/interactive/test-grab.c
index eabec8778..cf8b25600 100644
--- a/src/tests/clutter/interactive/test-grab.c
+++ b/src/tests/clutter/interactive/test-grab.c
@@ -87,6 +87,9 @@ debug_event_cb (ClutterActor *actor,
case CLUTTER_TOUCHPAD_SWIPE:
g_print ("[%s] TOUCHPAD SWIPE", source);
break;
+ case CLUTTER_TOUCHPAD_HOLD:
+ g_print ("[%s] TOUCHPAD HOLD", source);
+ break;
case CLUTTER_PROXIMITY_IN:
g_print ("[%s] PROXIMITY IN", source);
break;
diff --git a/src/wayland/meta-wayland-pointer-gesture-hold.c b/src/wayland/meta-wayland-pointer-gesture-hold.c
new file mode 100644
index 000000000..17ba5cc4e
--- /dev/null
+++ b/src/wayland/meta-wayland-pointer-gesture-hold.c
@@ -0,0 +1,135 @@
+/*
+ * Wayland Support
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Author: José Expósito
+ */
+
+#include "config.h"
+
+#include "wayland/meta-wayland-pointer-gesture-hold.h"
+
+#include
+
+#include "wayland/meta-wayland-pointer.h"
+#include "wayland/meta-wayland-seat.h"
+#include "wayland/meta-wayland-surface.h"
+
+#include "pointer-gestures-unstable-v1-server-protocol.h"
+
+static void
+handle_hold_begin (MetaWaylandPointer *pointer,
+ const ClutterEvent *event)
+{
+ MetaWaylandPointerClient *pointer_client;
+ MetaWaylandSeat *seat;
+ struct wl_resource *resource;
+ uint32_t serial, fingers;
+
+ pointer_client = pointer->focus_client;
+ seat = meta_wayland_pointer_get_seat (pointer);
+ serial = wl_display_next_serial (seat->wl_display);
+ fingers = clutter_event_get_touchpad_gesture_finger_count (event);
+
+ wl_resource_for_each (resource, &pointer_client->hold_gesture_resources)
+ {
+ zwp_pointer_gesture_hold_v1_send_begin (resource, serial,
+ clutter_event_get_time (event),
+ pointer->focus_surface->resource,
+ fingers);
+ }
+}
+
+static void
+handle_hold_end (MetaWaylandPointer *pointer,
+ const ClutterEvent *event)
+{
+ MetaWaylandPointerClient *pointer_client;
+ MetaWaylandSeat *seat;
+ struct wl_resource *resource;
+ gboolean cancelled = FALSE;
+ uint32_t serial;
+
+ pointer_client = pointer->focus_client;
+ seat = meta_wayland_pointer_get_seat (pointer);
+ serial = wl_display_next_serial (seat->wl_display);
+
+ if (event->touchpad_hold.phase == CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL)
+ cancelled = TRUE;
+
+ wl_resource_for_each (resource, &pointer_client->hold_gesture_resources)
+ {
+ zwp_pointer_gesture_hold_v1_send_end (resource, serial,
+ clutter_event_get_time (event),
+ cancelled);
+ }
+}
+
+gboolean
+meta_wayland_pointer_gesture_hold_handle_event (MetaWaylandPointer *pointer,
+ const ClutterEvent *event)
+{
+ if (event->type != CLUTTER_TOUCHPAD_HOLD)
+ return FALSE;
+
+ if (!pointer->focus_client)
+ return FALSE;
+
+ switch (event->touchpad_hold.phase)
+ {
+ case CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN:
+ handle_hold_begin (pointer, event);
+ break;
+ case CLUTTER_TOUCHPAD_GESTURE_PHASE_END:
+ case CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL:
+ handle_hold_end (pointer, event);
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+pointer_gesture_hold_release (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static const struct zwp_pointer_gesture_hold_v1_interface pointer_gesture_hold_interface = {
+ pointer_gesture_hold_release
+};
+
+void
+meta_wayland_pointer_gesture_hold_create_new_resource (MetaWaylandPointer *pointer,
+ struct wl_client *client,
+ struct wl_resource *pointer_resource,
+ uint32_t id)
+{
+ MetaWaylandPointerClient *pointer_client;
+ struct wl_resource *res;
+
+ pointer_client = meta_wayland_pointer_get_pointer_client (pointer, client);
+ g_return_if_fail (pointer_client != NULL);
+
+ res = wl_resource_create (client, &zwp_pointer_gesture_hold_v1_interface,
+ wl_resource_get_version (pointer_resource), id);
+ wl_resource_set_implementation (res, &pointer_gesture_hold_interface, pointer,
+ meta_wayland_pointer_unbind_pointer_client_resource);
+ wl_list_insert (&pointer_client->hold_gesture_resources,
+ wl_resource_get_link (res));
+}
diff --git a/src/wayland/meta-wayland-pointer-gesture-hold.h b/src/wayland/meta-wayland-pointer-gesture-hold.h
new file mode 100644
index 000000000..55846bff6
--- /dev/null
+++ b/src/wayland/meta-wayland-pointer-gesture-hold.h
@@ -0,0 +1,37 @@
+/*
+ * Wayland Support
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Author: José Expósito
+ */
+
+#ifndef META_WAYLAND_POINTER_GESTURE_HOLD_H
+#define META_WAYLAND_POINTER_GESTURE_HOLD_H
+
+#include
+#include
+
+#include "clutter/clutter.h"
+#include "wayland/meta-wayland-types.h"
+
+gboolean meta_wayland_pointer_gesture_hold_handle_event (MetaWaylandPointer *pointer,
+ const ClutterEvent *event);
+
+void meta_wayland_pointer_gesture_hold_create_new_resource (MetaWaylandPointer *pointer,
+ struct wl_client *client,
+ struct wl_resource *gestures_resource,
+ uint32_t id);
+
+#endif /* META_WAYLAND_POINTER_GESTURE_HOLD_H */
diff --git a/src/wayland/meta-wayland-pointer-gestures.c b/src/wayland/meta-wayland-pointer-gestures.c
index 7222a8a8c..559531d34 100644
--- a/src/wayland/meta-wayland-pointer-gestures.c
+++ b/src/wayland/meta-wayland-pointer-gestures.c
@@ -54,9 +54,29 @@ gestures_get_pinch (struct wl_client *client,
meta_wayland_pointer_gesture_pinch_create_new_resource (pointer, client, resource, id);
}
+static void
+gestures_get_hold (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *pointer_resource)
+{
+ MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
+
+ meta_wayland_pointer_gesture_hold_create_new_resource (pointer, client, resource, id);
+}
+
+static void
+gestures_release (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
static const struct zwp_pointer_gestures_v1_interface pointer_gestures_interface = {
gestures_get_swipe,
- gestures_get_pinch
+ gestures_get_pinch,
+ gestures_release,
+ gestures_get_hold
};
static void
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
index 397128b3c..43d8be9b5 100644
--- a/src/wayland/meta-wayland-pointer.c
+++ b/src/wayland/meta-wayland-pointer.c
@@ -104,6 +104,7 @@ meta_wayland_pointer_client_new (void)
wl_list_init (&pointer_client->pointer_resources);
wl_list_init (&pointer_client->swipe_gesture_resources);
wl_list_init (&pointer_client->pinch_gesture_resources);
+ wl_list_init (&pointer_client->hold_gesture_resources);
wl_list_init (&pointer_client->relative_pointer_resources);
return pointer_client;
@@ -133,6 +134,11 @@ meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
+ wl_resource_for_each_safe (resource, next, &pointer_client->hold_gesture_resources)
+ {
+ wl_list_remove (wl_resource_get_link (resource));
+ wl_list_init (wl_resource_get_link (resource));
+ }
wl_resource_for_each_safe (resource, next, &pointer_client->relative_pointer_resources)
{
wl_list_remove (wl_resource_get_link (resource));
@@ -148,6 +154,7 @@ meta_wayland_pointer_client_is_empty (MetaWaylandPointerClient *pointer_client)
return (wl_list_empty (&pointer_client->pointer_resources) &&
wl_list_empty (&pointer_client->swipe_gesture_resources) &&
wl_list_empty (&pointer_client->pinch_gesture_resources) &&
+ wl_list_empty (&pointer_client->hold_gesture_resources) &&
wl_list_empty (&pointer_client->relative_pointer_resources));
}
@@ -835,6 +842,10 @@ meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
meta_wayland_pointer_gesture_pinch_handle_event (pointer, event);
break;
+ case CLUTTER_TOUCHPAD_HOLD:
+ meta_wayland_pointer_gesture_hold_handle_event (pointer, event);
+ break;
+
default:
break;
}
diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h
index 529177b8c..80087c0be 100644
--- a/src/wayland/meta-wayland-pointer.h
+++ b/src/wayland/meta-wayland-pointer.h
@@ -25,6 +25,7 @@
#include "meta/meta-cursor-tracker.h"
#include "wayland/meta-wayland-pointer-constraints.h"
+#include "wayland/meta-wayland-pointer-gesture-hold.h"
#include "wayland/meta-wayland-pointer-gesture-pinch.h"
#include "wayland/meta-wayland-pointer-gesture-swipe.h"
#include "wayland/meta-wayland-seat.h"
@@ -57,6 +58,7 @@ struct _MetaWaylandPointerClient
{
struct wl_list pointer_resources;
struct wl_list swipe_gesture_resources;
+ struct wl_list hold_gesture_resources;
struct wl_list pinch_gesture_resources;
struct wl_list relative_pointer_resources;
};
diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c
index 2315fecee..782c798d0 100644
--- a/src/wayland/meta-wayland-seat.c
+++ b/src/wayland/meta-wayland-seat.c
@@ -387,6 +387,7 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
case CLUTTER_SCROLL:
case CLUTTER_TOUCHPAD_SWIPE:
case CLUTTER_TOUCHPAD_PINCH:
+ case CLUTTER_TOUCHPAD_HOLD:
if (meta_wayland_seat_has_pointer (seat))
return meta_wayland_pointer_handle_event (seat->pointer, event);
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index af67cb4b5..1ba947a45 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -43,7 +43,7 @@
#define META_XSERVER_VERSION 1
#define META_GTK_SHELL1_VERSION 3
#define META_WL_SUBCOMPOSITOR_VERSION 1
-#define META_ZWP_POINTER_GESTURES_V1_VERSION 1
+#define META_ZWP_POINTER_GESTURES_V1_VERSION 3
#define META_ZXDG_EXPORTER_V1_VERSION 1
#define META_ZXDG_IMPORTER_V1_VERSION 1
#define META_ZXDG_EXPORTER_V2_VERSION 1