Merge branch 'hold-gestures' into 'main'

Add hold gestures

See merge request GNOME/gtk!3454
This commit is contained in:
Carlos Garnacho 2022-01-26 23:37:28 +00:00
commit 9a7750e339
17 changed files with 361 additions and 40 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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;

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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__ */

View File

@ -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:

View File

@ -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",

View File

@ -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'