diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 454e69ed64..127e92e547 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -2496,7 +2496,8 @@ static const GdkEventTypeInfo gdk_touchpad_event_info = { GDK_DEFINE_EVENT_TYPE (GdkTouchpadEvent, gdk_touchpad_event, &gdk_touchpad_event_info, GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_SWIPE) - GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH)) + GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH) + GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_HOLD)) GdkEvent * gdk_touchpad_event_new_swipe (GdkSurface *surface, @@ -2570,6 +2571,27 @@ gdk_touchpad_event_new_pinch (GdkSurface *surface, return (GdkEvent *) self; } +GdkEvent * +gdk_touchpad_event_new_hold (GdkSurface *surface, + GdkDevice *device, + guint32 time, + GdkModifierType state, + GdkTouchpadGesturePhase phase, + double x, + double y, + int n_fingers) +{ + GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_HOLD, surface, device, time); + + self->state = state; + self->phase = phase; + self->x = x; + self->y = y; + self->n_fingers = n_fingers; + + return (GdkEvent *) self; +} + /** * gdk_touchpad_event_get_gesture_phase: * @event: (type GdkTouchpadEvent): a touchpad event @@ -2585,7 +2607,8 @@ gdk_touchpad_event_get_gesture_phase (GdkEvent *event) g_return_val_if_fail (GDK_IS_EVENT (event), 0); g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) || - GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE), 0); + GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE) || + GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_HOLD), 0); return self->phase; } @@ -2605,7 +2628,8 @@ gdk_touchpad_event_get_n_fingers (GdkEvent *event) g_return_val_if_fail (GDK_IS_EVENT (event), 0); g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) || - GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE), 0); + GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE) || + GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_HOLD), 0); return self->n_fingers; } diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index 748341e80c..99fecbc689 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -169,6 +169,8 @@ typedef struct _GdkTouchpadEvent GdkTouchpadEvent; * @GDK_PAD_RING: A tablet pad axis event from a "ring". * @GDK_PAD_STRIP: A tablet pad axis event from a "strip". * @GDK_PAD_GROUP_MODE: A tablet pad group mode change. + * @GDK_TOUCHPAD_HOLD: A touchpad hold gesture event, the current state + * is determined by its phase field. Since: 4.6 * @GDK_EVENT_LAST: marks the end of the GdkEventType enumeration. * * Specifies the type of the event. @@ -203,6 +205,7 @@ typedef enum GDK_PAD_RING, GDK_PAD_STRIP, GDK_PAD_GROUP_MODE, + GDK_TOUCHPAD_HOLD, GDK_EVENT_LAST /* helper variable for decls */ } GdkEventType; diff --git a/gdk/gdkeventsprivate.h b/gdk/gdkeventsprivate.h index 065cf1f3d3..a16fc0f654 100644 --- a/gdk/gdkeventsprivate.h +++ b/gdk/gdkeventsprivate.h @@ -533,6 +533,15 @@ GdkEvent * gdk_touchpad_event_new_pinch (GdkSurface *surface, double scale, double angle_delta); +GdkEvent * gdk_touchpad_event_new_hold (GdkSurface *surface, + GdkDevice *device, + guint32 time, + GdkModifierType state, + GdkTouchpadGesturePhase phase, + double x, + double y, + int n_fingers); + GdkEvent * gdk_pad_event_new_ring (GdkSurface *surface, GdkDevice *device, guint32 time, diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index d82db04fb2..9c21a6a989 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -227,6 +227,7 @@ struct _GdkWaylandSeat struct wl_touch *wl_touch; struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe; struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch; + struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold; struct zwp_tablet_seat_v2 *wp_tablet_seat; GdkDisplay *display; @@ -2856,6 +2857,81 @@ gesture_pinch_end (void *data, 0, 0, 1, 0); } +static void +emit_gesture_hold_event (GdkWaylandSeat *seat, + GdkTouchpadGesturePhase phase, + guint32 _time, + guint32 n_fingers) +{ + GdkEvent *event; + + if (!seat->pointer_info.focus) + return; + + seat->pointer_info.time = _time; + + event = gdk_touchpad_event_new_hold (seat->pointer_info.focus, + seat->logical_pointer, + _time, + device_get_modifiers (seat->logical_pointer), + phase, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + n_fingers); + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double x, y; + gdk_event_get_position (event, &x, &y); + g_message ("hold event %d, coords: %f %f, seat %p state %d", + gdk_event_get_event_type (event), + x, y, seat, + gdk_event_get_modifier_state (event)); + } + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +gesture_hold_begin (void *data, + struct zwp_pointer_gesture_hold_v1 *hold, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + GdkWaylandSeat *seat = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); + + _gdk_wayland_display_update_serial (display, serial); + + emit_gesture_hold_event (seat, + GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, + time, fingers); + seat->gesture_n_fingers = fingers; +} + +static void +gesture_hold_end (void *data, + struct zwp_pointer_gesture_hold_v1 *hold, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + GdkWaylandSeat *seat = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); + GdkTouchpadGesturePhase phase; + + _gdk_wayland_display_update_serial (display, serial); + + phase = (cancelled) ? + GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : + GDK_TOUCHPAD_GESTURE_PHASE_END; + + emit_gesture_hold_event (seat, phase, time, + seat->gesture_n_fingers); +} + static void _gdk_wayland_seat_remove_tool (GdkWaylandSeat *seat, GdkWaylandTabletToolData *tool) @@ -3065,6 +3141,11 @@ static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener gesture_pinch_end }; +static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = { + gesture_hold_begin, + gesture_hold_end +}; + static const struct zwp_tablet_v2_listener tablet_listener = { tablet_handle_name, tablet_handle_id, @@ -3120,6 +3201,17 @@ seat_handle_capabilities (void *data, seat); zwp_pointer_gesture_pinch_v1_add_listener (seat->wp_pointer_gesture_pinch, &gesture_pinch_listener, seat); + + if (display_wayland->pointer_gestures_version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE_SINCE_VERSION) + { + seat->wp_pointer_gesture_hold = + zwp_pointer_gestures_v1_get_hold_gesture (display_wayland->pointer_gestures, + seat->wl_pointer); + zwp_pointer_gesture_hold_v1_set_user_data (seat->wp_pointer_gesture_hold, + seat); + zwp_pointer_gesture_hold_v1_add_listener (seat->wp_pointer_gesture_hold, + &gesture_hold_listener, seat); + } } } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index 1401d91415..ea64041aa7 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -431,6 +431,9 @@ gdk_registry_handle_global (void *data, } else if (strcmp (interface, "zwp_pointer_gestures_v1") == 0) { + display_wayland->pointer_gestures_version = + MIN (version, GDK_ZWP_POINTER_GESTURES_V1_VERSION); + display_wayland->pointer_gestures = wl_registry_bind (display_wayland->wl_registry, id, &zwp_pointer_gestures_v1_interface, diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index e4924fb6f9..b9ab698c19 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -52,7 +52,7 @@ G_BEGIN_DECLS -#define GDK_ZWP_POINTER_GESTURES_V1_VERSION 1 +#define GDK_ZWP_POINTER_GESTURES_V1_VERSION 3 typedef struct _GdkWaylandSelection GdkWaylandSelection; @@ -140,6 +140,7 @@ struct _GdkWaylandDisplay int data_device_manager_version; int gtk_shell_version; int xdg_output_manager_version; + int pointer_gestures_version; int xdg_activation_version; uint32_t server_decoration_mode; diff --git a/gtk/gtkeventcontrollerscroll.c b/gtk/gtkeventcontrollerscroll.c index b246bb22db..67dafb73ed 100644 --- a/gtk/gtkeventcontrollerscroll.c +++ b/gtk/gtkeventcontrollerscroll.c @@ -66,6 +66,7 @@ #include "gtkprivate.h" #define SCROLL_CAPTURE_THRESHOLD_MS 150 +#define HOLD_TIMEOUT_MS 50 typedef struct { @@ -84,6 +85,7 @@ struct _GtkEventControllerScroll double cur_dx; double cur_dy; + guint hold_timeout_id; guint active : 1; }; @@ -193,6 +195,7 @@ gtk_event_controller_scroll_finalize (GObject *object) GtkEventControllerScroll *scroll = GTK_EVENT_CONTROLLER_SCROLL (object); g_array_unref (scroll->scroll_history); + g_clear_handle_id (&scroll->hold_timeout_id, g_source_remove); G_OBJECT_CLASS (gtk_event_controller_scroll_parent_class)->finalize (object); } @@ -235,6 +238,107 @@ gtk_event_controller_scroll_get_property (GObject *object, } } +static gboolean +gtk_event_controller_scroll_begin (GtkEventController *controller) +{ + GtkEventControllerScroll *scroll = GTK_EVENT_CONTROLLER_SCROLL (controller); + + if (scroll->active) + return FALSE; + + g_signal_emit (controller, signals[SCROLL_BEGIN], 0); + scroll_history_reset (scroll); + scroll->active = TRUE; + + return TRUE; +} + +static gboolean +gtk_event_controller_scroll_end (GtkEventController *controller) +{ + GtkEventControllerScroll *scroll = GTK_EVENT_CONTROLLER_SCROLL (controller); + + if (!scroll->active) + return FALSE; + + g_signal_emit (controller, signals[SCROLL_END], 0); + scroll->active = FALSE; + + if (scroll->flags & GTK_EVENT_CONTROLLER_SCROLL_KINETIC) + { + double vel_x, vel_y; + + scroll_history_finish (scroll, &vel_x, &vel_y); + g_signal_emit (controller, signals[DECELERATE], 0, vel_x, vel_y); + } + + return TRUE; +} + +static gboolean +gtk_event_controller_scroll_hold_timeout (gpointer user_data) +{ + GtkEventController *controller; + GtkEventControllerScroll *scroll; + + controller = user_data; + scroll = GTK_EVENT_CONTROLLER_SCROLL (controller); + + gtk_event_controller_scroll_end (controller); + scroll->hold_timeout_id = 0; + + return G_SOURCE_REMOVE; +} + +static gboolean +gtk_event_controller_scroll_handle_hold_event (GtkEventController *controller, + GdkEvent *event) +{ + GtkEventControllerScroll *scroll = GTK_EVENT_CONTROLLER_SCROLL (controller); + gboolean handled = GDK_EVENT_PROPAGATE; + GdkTouchpadGesturePhase phase; + guint n_fingers = 0; + + if (gdk_event_get_event_type (event) != GDK_TOUCHPAD_HOLD) + return handled; + + n_fingers = gdk_touchpad_event_get_n_fingers (event); + if (n_fingers != 1 && n_fingers != 2) + return handled; + + if (scroll->hold_timeout_id != 0) + return handled; + + phase = gdk_touchpad_event_get_gesture_phase (event); + + switch (phase) + { + case GDK_TOUCHPAD_GESTURE_PHASE_BEGIN: + handled = gtk_event_controller_scroll_begin (controller); + break; + + case GDK_TOUCHPAD_GESTURE_PHASE_END: + handled = gtk_event_controller_scroll_end (controller); + break; + + case GDK_TOUCHPAD_GESTURE_PHASE_CANCEL: + if (scroll->hold_timeout_id == 0) + { + scroll->hold_timeout_id = + g_timeout_add (HOLD_TIMEOUT_MS, + gtk_event_controller_scroll_hold_timeout, + controller); + } + break; + + case GDK_TOUCHPAD_GESTURE_PHASE_UPDATE: + default: + break; + } + + return handled; +} + static gboolean gtk_event_controller_scroll_handle_event (GtkEventController *controller, GdkEvent *event, @@ -245,26 +349,28 @@ gtk_event_controller_scroll_handle_event (GtkEventController *controller, GdkScrollDirection direction = GDK_SCROLL_SMOOTH; double dx = 0, dy = 0; gboolean handled = GDK_EVENT_PROPAGATE; + GdkEventType event_type; - if (gdk_event_get_event_type (event) != GDK_SCROLL) + event_type = gdk_event_get_event_type (event); + + if (event_type == GDK_TOUCHPAD_HOLD) + return gtk_event_controller_scroll_handle_hold_event (controller, event); + + if (event_type != GDK_SCROLL) return FALSE; if ((scroll->flags & (GTK_EVENT_CONTROLLER_SCROLL_VERTICAL | GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL)) == 0) return FALSE; + g_clear_handle_id (&scroll->hold_timeout_id, g_source_remove); + /* FIXME: Handle device changes */ direction = gdk_scroll_event_get_direction (event); if (direction == GDK_SCROLL_SMOOTH) { gdk_scroll_event_get_deltas (event, &dx, &dy); - - if (!scroll->active) - { - g_signal_emit (controller, signals[SCROLL_BEGIN], 0); - scroll_history_reset (scroll); - scroll->active = TRUE; - } + gtk_event_controller_scroll_begin (controller); if ((scroll->flags & GTK_EVENT_CONTROLLER_SCROLL_VERTICAL) == 0) dy = 0; @@ -334,17 +440,8 @@ gtk_event_controller_scroll_handle_event (GtkEventController *controller, if (scroll->active && gdk_scroll_event_is_stop (event)) { - g_signal_emit (controller, signals[SCROLL_END], 0); - scroll->active = FALSE; + gtk_event_controller_scroll_end (controller); handled = FALSE; - - if (scroll->flags & GTK_EVENT_CONTROLLER_SCROLL_KINETIC) - { - double vel_x, vel_y; - - scroll_history_finish (scroll, &vel_x, &vel_y); - g_signal_emit (controller, signals[DECELERATE], 0, vel_x, vel_y); - } } return handled; @@ -462,6 +559,7 @@ gtk_event_controller_scroll_init (GtkEventControllerScroll *scroll) { scroll->scroll_history = g_array_new (FALSE, FALSE, sizeof (ScrollHistoryElem)); + scroll->hold_timeout_id = 0; } /** diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c index 33b2fb9326..59fee6bcbf 100644 --- a/gtk/gtkgesture.c +++ b/gtk/gtkgesture.c @@ -162,6 +162,7 @@ struct _GtkGesturePrivate GdkDevice *device; GList *group_link; guint n_points; + guint hold_timeout_id; guint recognized : 1; guint touchpad : 1; }; @@ -171,7 +172,10 @@ static guint signals[N_SIGNALS] = { 0 }; #define BUTTONS_MASK (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK) #define EVENT_IS_TOUCHPAD_GESTURE(e) (gdk_event_get_event_type (e) == GDK_TOUCHPAD_SWIPE || \ - gdk_event_get_event_type (e) == GDK_TOUCHPAD_PINCH) + gdk_event_get_event_type (e) == GDK_TOUCHPAD_PINCH || \ + gdk_event_get_event_type (e) == GDK_TOUCHPAD_HOLD) + +#define HOLD_TIMEOUT_MS 50 GList * _gtk_gesture_get_group_link (GtkGesture *gesture); @@ -221,6 +225,7 @@ gtk_gesture_finalize (GObject *object) gtk_gesture_ungroup (gesture); g_list_free (priv->group_link); + g_clear_handle_id (&priv->hold_timeout_id, g_source_remove); g_hash_table_destroy (priv->points); @@ -258,7 +263,8 @@ _gtk_gesture_get_n_touchpad_points (GtkGesture *gesture, if (only_active && (data->state == GTK_EVENT_SEQUENCE_DENIED || (event_type == GDK_TOUCHPAD_SWIPE && phase == GDK_TOUCHPAD_GESTURE_PHASE_END) || - (event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_END))) + (event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_END) || + (event_type == GDK_TOUCHPAD_HOLD && phase == GDK_TOUCHPAD_GESTURE_PHASE_END))) return 0; return n_fingers; @@ -390,8 +396,8 @@ _update_touchpad_deltas (PointData *data) { GdkEvent *event = data->event; GdkTouchpadGesturePhase phase; - double dx; - double dy; + double dx = 0; + double dy = 0; if (!event) return; @@ -399,7 +405,10 @@ _update_touchpad_deltas (PointData *data) if (EVENT_IS_TOUCHPAD_GESTURE (event)) { phase = gdk_touchpad_event_get_gesture_phase (event); - gdk_touchpad_event_get_deltas (event, &dx, &dy); + + if (gdk_event_get_event_type (event) != GDK_TOUCHPAD_HOLD) + gdk_touchpad_event_get_deltas (event, &dx, &dy); + if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) data->accum_dx = data->accum_dy = 0; else if (phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE) @@ -574,6 +583,22 @@ _gtk_gesture_cancel_all (GtkGesture *gesture) _gtk_gesture_check_empty (gesture); } +static gboolean +gtk_gesture_hold_timeout (gpointer user_data) +{ + GtkGesture *gesture; + GtkGesturePrivate *priv; + + gesture = user_data; + priv = gtk_gesture_get_instance_private (gesture); + + if (priv->touchpad) + _gtk_gesture_cancel_sequence (gesture, priv->last_sequence); + + priv->hold_timeout_id = 0; + return G_SOURCE_REMOVE; +} + static gboolean gesture_within_surface (GtkGesture *gesture, GdkSurface *surface) @@ -636,8 +661,13 @@ gtk_gesture_handle_event (GtkEventController *controller, if (event_type == GDK_BUTTON_PRESS || event_type == GDK_TOUCH_BEGIN || (event_type == GDK_TOUCHPAD_SWIPE && phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) || - (event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)) + (event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) || + (event_type == GDK_TOUCHPAD_HOLD && phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)) { + if ((event_type == GDK_TOUCHPAD_PINCH || event_type == GDK_TOUCHPAD_SWIPE) && + _gtk_gesture_has_matching_touchpoints (gesture)) + g_clear_handle_id (&priv->hold_timeout_id, g_source_remove); + if (_gtk_gesture_update_point (gesture, event, target, x, y, TRUE)) { gboolean triggered_recognition; @@ -668,7 +698,8 @@ gtk_gesture_handle_event (GtkEventController *controller, else if (event_type == GDK_BUTTON_RELEASE || event_type == GDK_TOUCH_END || (event_type == GDK_TOUCHPAD_SWIPE && phase == GDK_TOUCHPAD_GESTURE_PHASE_END) || - (event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_END)) + (event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_END) || + (event_type == GDK_TOUCHPAD_HOLD && phase == GDK_TOUCHPAD_GESTURE_PHASE_END)) { gboolean was_claimed = FALSE; @@ -712,6 +743,15 @@ gtk_gesture_handle_event (GtkEventController *controller, if (priv->touchpad) _gtk_gesture_cancel_sequence (gesture, sequence); } + else if (event_type == GDK_TOUCHPAD_HOLD && phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL) + { + if (priv->hold_timeout_id == 0) + { + priv->hold_timeout_id = g_timeout_add (HOLD_TIMEOUT_MS, + gtk_gesture_hold_timeout, + gesture); + } + } else if (event_type == GDK_GRAB_BROKEN) { GdkSurface *surface; @@ -737,6 +777,10 @@ gtk_gesture_handle_event (GtkEventController *controller, static void gtk_gesture_reset (GtkEventController *controller) { + GtkGesture *gesture = GTK_GESTURE (controller); + GtkGesturePrivate *priv = gtk_gesture_get_instance_private (gesture); + + g_clear_handle_id (&priv->hold_timeout_id, g_source_remove); _gtk_gesture_cancel_all (GTK_GESTURE (controller)); } @@ -908,6 +952,7 @@ gtk_gesture_init (GtkGesture *gesture) priv->points = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) free_point_data); priv->group_link = g_list_prepend (NULL, gesture); + priv->hold_timeout_id = 0; } /** diff --git a/gtk/gtkgesturerotate.c b/gtk/gtkgesturerotate.c index 5ecf7490b1..df174bf646 100644 --- a/gtk/gtkgesturerotate.c +++ b/gtk/gtkgesturerotate.c @@ -172,8 +172,9 @@ static gboolean gtk_gesture_rotate_filter_event (GtkEventController *controller, GdkEvent *event) { - /* Let 2-finger touchpad pinch events go through */ - if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_PINCH) + /* Let 2-finger touchpad pinch and hold events go through */ + if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_PINCH || + gdk_event_get_event_type (event) == GDK_TOUCHPAD_HOLD) { guint n_fingers; diff --git a/gtk/gtkgesturesingle.c b/gtk/gtkgesturesingle.c index 8a4b7a14c5..bf415698b7 100644 --- a/gtk/gtkgesturesingle.c +++ b/gtk/gtkgesturesingle.c @@ -197,6 +197,10 @@ gtk_gesture_single_handle_event (GtkEventController *controller, } break; + case GDK_TOUCHPAD_HOLD: + if (gdk_touchpad_event_get_n_fingers (event) == 1) + return FALSE; + /* fallthrough */ case GDK_TOUCH_CANCEL: case GDK_GRAB_BROKEN: case GDK_TOUCHPAD_SWIPE: diff --git a/gtk/gtkgestureswipe.c b/gtk/gtkgestureswipe.c index ac52638298..e168aa84a3 100644 --- a/gtk/gtkgestureswipe.c +++ b/gtk/gtkgestureswipe.c @@ -84,8 +84,9 @@ static gboolean gtk_gesture_swipe_filter_event (GtkEventController *controller, GdkEvent *event) { - /* Let touchpad swipe events go through, only if they match n-points */ - if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_SWIPE) + /* Let touchpad swipe and hold events go through, only if they match n-points */ + if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_SWIPE || + gdk_event_get_event_type (event) == GDK_TOUCHPAD_HOLD) { guint n_points; guint n_fingers; diff --git a/gtk/gtkgesturezoom.c b/gtk/gtkgesturezoom.c index 0baf55fb7c..9d6116bce1 100644 --- a/gtk/gtkgesturezoom.c +++ b/gtk/gtkgesturezoom.c @@ -149,8 +149,9 @@ static gboolean gtk_gesture_zoom_filter_event (GtkEventController *controller, GdkEvent *event) { - /* Let 2-finger touchpad pinch events go through */ - if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_PINCH) + /* Let 2-finger touchpad pinch and hold events go through */ + if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_PINCH || + gdk_event_get_event_type (event) == GDK_TOUCHPAD_HOLD) { guint n_fingers; diff --git a/gtk/gtkkineticscrolling.c b/gtk/gtkkineticscrolling.c index 87618acd7c..4eab5dcc84 100644 --- a/gtk/gtkkineticscrolling.c +++ b/gtk/gtkkineticscrolling.c @@ -202,9 +202,7 @@ gtk_kinetic_scrolling_tick (GtkKineticScrolling *data, else if (fabs(data->velocity) < 1 || (last_time != 0.0 && fabs(data->position - last_position) < 1)) { - data->phase = GTK_KINETIC_SCROLLING_PHASE_FINISHED; - data->position = round(data->position); - data->velocity = 0; + gtk_kinetic_scrolling_stop (data); } break; } @@ -249,3 +247,13 @@ gtk_kinetic_scrolling_tick (GtkKineticScrolling *data, return data->phase != GTK_KINETIC_SCROLLING_PHASE_FINISHED; } +void +gtk_kinetic_scrolling_stop (GtkKineticScrolling *data) +{ + if (data->phase == GTK_KINETIC_SCROLLING_PHASE_DECELERATING) + { + data->phase = GTK_KINETIC_SCROLLING_PHASE_FINISHED; + data->position = round (data->position); + data->velocity = 0; + } +} diff --git a/gtk/gtkkineticscrollingprivate.h b/gtk/gtkkineticscrollingprivate.h index a531ace476..a519bd7ec0 100644 --- a/gtk/gtkkineticscrollingprivate.h +++ b/gtk/gtkkineticscrollingprivate.h @@ -50,6 +50,8 @@ gboolean gtk_kinetic_scrolling_tick (GtkKineticScrolling *data, double *position, double *velocity); +void gtk_kinetic_scrolling_stop (GtkKineticScrolling *data); + G_END_DECLS #endif /* __GTK_KINETIC_SCROLLING_H__ */ diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index bfab35ad61..aa32930242 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -915,6 +915,7 @@ rewrite_event_for_surface (GdkEvent *event, case GDK_TOUCH_CANCEL: case GDK_TOUCHPAD_SWIPE: case GDK_TOUCHPAD_PINCH: + case GDK_TOUCHPAD_HOLD: gdk_event_get_position (event, &x, &y); gdk_surface_translate_coordinates (gdk_event_get_surface (event), new_surface, &x, &y); break; @@ -981,6 +982,14 @@ rewrite_event_for_surface (GdkEvent *event, dx, dy, gdk_touchpad_event_get_pinch_scale (event), gdk_touchpad_event_get_pinch_angle_delta (event)); + case GDK_TOUCHPAD_HOLD: + return gdk_touchpad_event_new_hold (new_surface, + gdk_event_get_device (event), + gdk_event_get_time (event), + gdk_event_get_modifier_state (event), + gdk_touchpad_event_get_gesture_phase (event), + x, y, + gdk_touchpad_event_get_n_fingers (event)); default: break; } @@ -1020,6 +1029,7 @@ rewrite_event_for_grabs (GdkEvent *event) case GDK_TOUCH_CANCEL: case GDK_TOUCHPAD_SWIPE: case GDK_TOUCHPAD_PINCH: + case GDK_TOUCHPAD_HOLD: display = gdk_event_get_display (event); device = gdk_event_get_device (event); @@ -1270,6 +1280,7 @@ is_pointing_event (GdkEvent *event) case GDK_TOUCH_CANCEL: case GDK_TOUCHPAD_PINCH: case GDK_TOUCHPAD_SWIPE: + case GDK_TOUCHPAD_HOLD: case GDK_DRAG_ENTER: case GDK_DRAG_LEAVE: case GDK_DRAG_MOTION: @@ -1353,7 +1364,8 @@ handle_pointing_event (GdkEvent *event) device = gdk_seat_get_pointer (gdk_event_get_seat (event)); } else if (type == GDK_TOUCHPAD_PINCH || - type == GDK_TOUCHPAD_SWIPE) + type == GDK_TOUCHPAD_SWIPE || + type == GDK_TOUCHPAD_HOLD) { /* Another bit of a kludge, touchpad gesture sequences do not * reflect on the pointer focus lookup. @@ -1488,6 +1500,7 @@ handle_pointing_event (GdkEvent *event) case GDK_SCROLL: case GDK_TOUCHPAD_PINCH: case GDK_TOUCHPAD_SWIPE: + case GDK_TOUCHPAD_HOLD: break; case GDK_GRAB_BROKEN: if (gdk_grab_broken_event_get_implicit (event)) @@ -1662,6 +1675,7 @@ gtk_main_do_event (GdkEvent *event) case GDK_TOUCH_CANCEL: case GDK_TOUCHPAD_SWIPE: case GDK_TOUCHPAD_PINCH: + case GDK_TOUCHPAD_HOLD: case GDK_PAD_BUTTON_PRESS: case GDK_PAD_BUTTON_RELEASE: case GDK_PAD_RING: diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index 372afe4a95..49be97080c 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -1350,6 +1350,19 @@ scroll_controller_scroll_begin (GtkEventControllerScroll *scroll, priv->smooth_scroll = TRUE; } +static void +stop_kinetic_scrolling_cb (GtkEventControllerScroll *scroll, + GtkScrolledWindow *scrolled_window) +{ + GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window); + + if (priv->hscrolling) + gtk_kinetic_scrolling_stop (priv->hscrolling); + + if (priv->vscrolling) + gtk_kinetic_scrolling_stop (priv->vscrolling); +} + static void scrolled_window_scroll (GtkScrolledWindow *scrolled_window, double delta_x, @@ -2115,6 +2128,8 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_KINETIC); gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE); + g_signal_connect (controller, "scroll-begin", + G_CALLBACK (stop_kinetic_scrolling_cb), scrolled_window); g_signal_connect (controller, "scroll", G_CALLBACK (captured_scroll_cb), scrolled_window); g_signal_connect (controller, "decelerate", diff --git a/meson.build b/meson.build index c74ca09284..65bf0b20af 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,7 @@ fribidi_req = '>= 0.19.7' cairo_req = '>= 1.14.0' gdk_pixbuf_req = '>= 2.30.0' introspection_req = '>= 1.39.0' -wayland_proto_req = '>= 1.21' +wayland_proto_req = '>= 1.23' wayland_req = '>= 1.20.0' graphene_req = '>= 1.9.1' epoxy_req = '>= 1.4'