summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-11-09 17:14:03 +0000
committerMatthias Clasen <mclasen@redhat.com>2020-11-09 17:14:03 +0000
commit7b151c3ef0592840805d91eea42353c4776ea72c (patch)
tree8dcb1b92141c0c503e1445f6b3018d38f644a301
parente093ed7d6745b910077aaf6c60a58536704d8f52 (diff)
parent4b459a99bed8a7deb5d909f2bc5eab64f32283cb (diff)
downloadgtk+-7b151c3ef0592840805d91eea42353c4776ea72c.tar.gz
Merge branch 'kinetic-scroll-velocity-accumulation' into 'master'
scrolledwindow: Accumulate velocity with kinetic scrolling See merge request GNOME/gtk!2768
-rw-r--r--gtk/gtkkineticscrolling.c5
-rw-r--r--gtk/gtkkineticscrollingprivate.h3
-rw-r--r--gtk/gtkscrolledwindow.c95
3 files changed, 65 insertions, 38 deletions
diff --git a/gtk/gtkkineticscrolling.c b/gtk/gtkkineticscrolling.c
index a03f683876..eb9c13bdfd 100644
--- a/gtk/gtkkineticscrolling.c
+++ b/gtk/gtkkineticscrolling.c
@@ -145,7 +145,8 @@ gtk_kinetic_scrolling_init_overshoot (GtkKineticScrolling *data,
gboolean
gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
double time_delta,
- double *position)
+ double *position,
+ double *velocity)
{
switch(data->phase)
{
@@ -213,6 +214,8 @@ gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
if (position)
*position = data->position;
+ if (velocity)
+ *velocity = data->velocity;
return data->phase != GTK_KINETIC_SCROLLING_PHASE_FINISHED;
}
diff --git a/gtk/gtkkineticscrollingprivate.h b/gtk/gtkkineticscrollingprivate.h
index 29f3eae228..b97fac360f 100644
--- a/gtk/gtkkineticscrollingprivate.h
+++ b/gtk/gtkkineticscrollingprivate.h
@@ -36,7 +36,8 @@ void gtk_kinetic_scrolling_free (GtkKineticScrolling *kinet
gboolean gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
double time_delta,
- double *position);
+ double *position,
+ double *velocity);
G_END_DECLS
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 5fcbec1338..85cdacacd5 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -184,6 +184,9 @@
#define MAX_OVERSHOOT_DISTANCE 100
#define DECELERATION_FRICTION 4
#define OVERSHOOT_FRICTION 20
+#define VELOCITY_ACCUMULATION_FLOOR 0.33
+#define VELOCITY_ACCUMULATION_CEIL 1.0
+#define VELOCITY_ACCUMULATION_MAX 6.0
/* Animated scrolling */
#define ANIMATION_DURATION 200
@@ -274,6 +277,9 @@ typedef struct
/* Kinetic scrolling */
GtkGesture *long_press_gesture;
GtkGesture *swipe_gesture;
+ GtkKineticScrolling *hscrolling;
+ GtkKineticScrolling *vscrolling;
+ gint64 last_deceleration_time;
/* These two gestures are mutually exclusive */
GtkGesture *drag_gesture;
@@ -294,15 +300,6 @@ typedef struct
double unclamped_vadj_value;
} GtkScrolledWindowPrivate;
-typedef struct
-{
- GtkScrolledWindow *scrolled_window;
- gint64 last_deceleration_time;
-
- GtkKineticScrolling *hscrolling;
- GtkKineticScrolling *vscrolling;
-} KineticScrollData;
-
enum {
PROP_0,
PROP_HADJUSTMENT,
@@ -2578,6 +2575,9 @@ gtk_scrolled_window_dispose (GObject *object)
priv->deceleration_id = 0;
}
+ g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free);
+ g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free);
+
if (priv->scroll_events_overshoot_id)
{
g_source_remove (priv->scroll_events_overshoot_id);
@@ -3193,41 +3193,40 @@ scrolled_window_deceleration_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
- KineticScrollData *data = user_data;
- GtkScrolledWindow *scrolled_window = data->scrolled_window;
+ GtkScrolledWindow *scrolled_window = user_data;
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkAdjustment *hadjustment, *vadjustment;
gint64 current_time;
double position, elapsed;
current_time = gdk_frame_clock_get_frame_time (frame_clock);
- elapsed = (current_time - data->last_deceleration_time) / 1000000.0;
- data->last_deceleration_time = current_time;
+ elapsed = (current_time - priv->last_deceleration_time) / (double)G_TIME_SPAN_SECOND;
+ priv->last_deceleration_time = current_time;
hadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
vadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
gtk_scrolled_window_invalidate_overshoot (scrolled_window);
- if (data->hscrolling &&
- gtk_kinetic_scrolling_tick (data->hscrolling, elapsed, &position))
+ if (priv->hscrolling &&
+ gtk_kinetic_scrolling_tick (priv->hscrolling, elapsed, &position, NULL))
{
priv->unclamped_hadj_value = position;
gtk_adjustment_set_value (hadjustment, position);
}
- else if (data->hscrolling)
- g_clear_pointer (&data->hscrolling, gtk_kinetic_scrolling_free);
+ else if (priv->hscrolling)
+ g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free);
- if (data->vscrolling &&
- gtk_kinetic_scrolling_tick (data->vscrolling, elapsed, &position))
+ if (priv->vscrolling &&
+ gtk_kinetic_scrolling_tick (priv->vscrolling, elapsed, &position, NULL))
{
priv->unclamped_vadj_value = position;
gtk_adjustment_set_value (vadjustment, position);
}
- else if (data->vscrolling)
- g_clear_pointer (&data->vscrolling, gtk_kinetic_scrolling_free);
+ else if (priv->vscrolling)
+ g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free);
- if (!data->hscrolling && !data->vscrolling)
+ if (!priv->hscrolling && !priv->vscrolling)
{
gtk_scrolled_window_cancel_deceleration (scrolled_window);
return G_SOURCE_REMOVE;
@@ -3252,14 +3251,29 @@ gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window)
}
static void
-kinetic_scroll_data_free (KineticScrollData *data)
+kinetic_scroll_stop_notify (GtkScrolledWindow *scrolled_window)
{
- if (data->hscrolling)
- gtk_kinetic_scrolling_free (data->hscrolling);
- if (data->vscrolling)
- gtk_kinetic_scrolling_free (data->vscrolling);
+ GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
+ priv->deceleration_id = 0;
+}
- g_free (data);
+static void
+gtk_scrolled_window_accumulate_velocity (GtkKineticScrolling **scrolling, double elapsed, double *velocity)
+{
+ if (!*scrolling)
+ return;
+
+ double last_velocity;
+ gtk_kinetic_scrolling_tick (*scrolling, elapsed, NULL, &last_velocity);
+ if (((*velocity >= 0) == (last_velocity >= 0)) &&
+ (fabs (*velocity) >= fabs (last_velocity) * VELOCITY_ACCUMULATION_FLOOR))
+ {
+ double min_velocity = last_velocity * VELOCITY_ACCUMULATION_FLOOR;
+ double max_velocity = last_velocity * VELOCITY_ACCUMULATION_CEIL;
+ double accumulation_multiplier = (*velocity - min_velocity) / (max_velocity - min_velocity);
+ *velocity += last_velocity * fmin (accumulation_multiplier, VELOCITY_ACCUMULATION_MAX);
+ }
+ g_clear_pointer (scrolling, gtk_kinetic_scrolling_free);
}
static void
@@ -3267,26 +3281,29 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GdkFrameClock *frame_clock;
- KineticScrollData *data;
+ gint64 current_time;
+ double elapsed;
g_return_if_fail (priv->deceleration_id == 0);
frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window));
- data = g_new0 (KineticScrollData, 1);
- data->scrolled_window = scrolled_window;
- data->last_deceleration_time = gdk_frame_clock_get_frame_time (frame_clock);
+ current_time = gdk_frame_clock_get_frame_time (frame_clock);
+ elapsed = (current_time - priv->last_deceleration_time) / (double)G_TIME_SPAN_SECOND;
+ priv->last_deceleration_time = current_time;
if (may_hscroll (scrolled_window))
{
double lower,upper;
GtkAdjustment *hadjustment;
+ gtk_scrolled_window_accumulate_velocity (&priv->hscrolling, elapsed, &priv->x_velocity);
+
hadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
lower = gtk_adjustment_get_lower (hadjustment);
upper = gtk_adjustment_get_upper (hadjustment);
upper -= gtk_adjustment_get_page_size (hadjustment);
- data->hscrolling =
+ priv->hscrolling =
gtk_kinetic_scrolling_new (lower,
upper,
MAX_OVERSHOOT_DISTANCE,
@@ -3295,17 +3312,21 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
priv->unclamped_hadj_value,
priv->x_velocity);
}
+ else
+ g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free);
if (may_vscroll (scrolled_window))
{
double lower,upper;
GtkAdjustment *vadjustment;
+ gtk_scrolled_window_accumulate_velocity (&priv->vscrolling, elapsed, &priv->y_velocity);
+
vadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
lower = gtk_adjustment_get_lower(vadjustment);
upper = gtk_adjustment_get_upper(vadjustment);
upper -= gtk_adjustment_get_page_size(vadjustment);
- data->vscrolling =
+ priv->vscrolling =
gtk_kinetic_scrolling_new (lower,
upper,
MAX_OVERSHOOT_DISTANCE,
@@ -3314,10 +3335,12 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
priv->unclamped_vadj_value,
priv->y_velocity);
}
+ else
+ g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free);
priv->deceleration_id = gtk_widget_add_tick_callback (GTK_WIDGET (scrolled_window),
- scrolled_window_deceleration_cb, data,
- (GDestroyNotify) kinetic_scroll_data_free);
+ scrolled_window_deceleration_cb, scrolled_window,
+ (GDestroyNotify) kinetic_scroll_stop_notify);
}
static gboolean