[gtk+] gtkscrolledwindow: Use scroll event controller
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] gtkscrolledwindow: Use scroll event controller
- Date: Tue, 19 Sep 2017 17:20:17 +0000 (UTC)
commit cf6ecc909528fb648c5b8343abe08a5e6bd5ad15
Author: Carlos Garnacho <carlosg gnome org>
Date: Fri Sep 15 13:55:23 2017 +0200
gtkscrolledwindow: Use scroll event controller
All kinetic scrolling initial velocity calculations are now
taken from the scroll controller. The handling of timeouts
to snap back when overshooting has been also made to just
apply on devices that can't emit ::scroll-begin/end.
gtk/gtkscrolledwindow.c | 415 ++++++++++++++++-------------------------------
1 files changed, 143 insertions(+), 272 deletions(-)
---
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index a2bfd6c..52fbd20 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -163,7 +163,6 @@
#define MAX_OVERSHOOT_DISTANCE 100
#define DECELERATION_FRICTION 4
#define OVERSHOOT_FRICTION 20
-#define SCROLL_CAPTURE_THRESHOLD_MS 150
/* Animated scrolling */
#define ANIMATION_DURATION 200
@@ -224,6 +223,7 @@ struct _GtkScrolledWindowPrivate
guint auto_added_viewport : 1;
guint propagate_natural_width : 1;
guint propagate_natural_height : 1;
+ guint smooth_scroll : 1;
gint min_content_width;
gint min_content_height;
@@ -236,13 +236,13 @@ struct _GtkScrolledWindowPrivate
GtkGesture *long_press_gesture;
GtkGesture *swipe_gesture;
- GArray *scroll_history;
- GdkDevice *scroll_device;
-
/* These two gestures are mutually exclusive */
GtkGesture *drag_gesture;
GtkGesture *pan_gesture;
+ /* Scroll event controller */
+ GtkEventController *scroll_controller;
+
gdouble drag_start_x;
gdouble drag_start_y;
@@ -315,8 +315,6 @@ static void gtk_scrolled_window_size_allocate (GtkWidget *wid
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip);
-static gboolean gtk_scrolled_window_scroll_event (GtkWidget *widget,
- GdkEventScroll *event);
static gboolean gtk_scrolled_window_focus (GtkWidget *widget,
GtkDirectionType direction);
static void gtk_scrolled_window_add (GtkContainer *container,
@@ -381,6 +379,8 @@ static void indicator_start_fade (Indicator *indicator,
static void indicator_set_over (Indicator *indicator,
gboolean over);
+static void install_scroll_cursor (GtkScrolledWindow *scrolled_window);
+static void uninstall_scroll_cursor (GtkScrolledWindow *scrolled_window);
static guint signals[LAST_SIGNAL] = {0};
static GParamSpec *properties[NUM_PROPERTIES];
@@ -508,7 +508,6 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
widget_class->destroy = gtk_scrolled_window_destroy;
widget_class->snapshot = gtk_scrolled_window_snapshot;
widget_class->size_allocate = gtk_scrolled_window_size_allocate;
- widget_class->scroll_event = gtk_scrolled_window_scroll_event;
widget_class->focus = gtk_scrolled_window_focus;
widget_class->measure = gtk_scrolled_window_measure;
widget_class->map = gtk_scrolled_window_map;
@@ -1192,92 +1191,6 @@ get_scroll_unit (GtkScrolledWindow *sw,
return scroll_unit;
}
-static void
-scroll_history_push (GtkScrolledWindow *sw,
- GdkEventScroll *event)
-{
- GtkScrolledWindowPrivate *priv = sw->priv;
- ScrollHistoryElem new_item;
- GdkScrollDirection direction;
- guint i;
-
- if (!gdk_event_get_scroll_direction ((GdkEvent *) event, &direction) ||
- direction != GDK_SCROLL_SMOOTH)
- return;
-
- for (i = 0; i < priv->scroll_history->len; i++)
- {
- ScrollHistoryElem *elem;
-
- elem = &g_array_index (priv->scroll_history, ScrollHistoryElem, i);
-
- if (elem->evtime >=
- gdk_event_get_time ((GdkEvent *) event) - SCROLL_CAPTURE_THRESHOLD_MS)
- break;
- }
-
- if (i > 0)
- g_array_remove_range (priv->scroll_history, 0, i);
-
- gdk_event_get_scroll_deltas ((GdkEvent *) event, &new_item.dx, &new_item.dy);
- new_item.evtime = gdk_event_get_time ((GdkEvent *) event);
- g_array_append_val (priv->scroll_history, new_item);
-}
-
-static void
-scroll_history_reset (GtkScrolledWindow *sw)
-{
- GtkScrolledWindowPrivate *priv = sw->priv;
-
- if (priv->scroll_history->len == 0)
- return;
-
- g_array_remove_range (priv->scroll_history, 0,
- priv->scroll_history->len);
-}
-
-static gboolean
-scroll_history_finish (GtkScrolledWindow *sw,
- gdouble *velocity_x,
- gdouble *velocity_y)
-{
- GtkScrolledWindowPrivate *priv = sw->priv;
- gdouble accum_dx = 0, accum_dy = 0;
- guint32 first = 0, last = 0;
- gdouble xunit, yunit;
- guint i;
-
- if (priv->scroll_history->len == 0)
- return FALSE;
-
- for (i = 0; i < priv->scroll_history->len; i++)
- {
- ScrollHistoryElem *elem;
-
- elem = &g_array_index (priv->scroll_history, ScrollHistoryElem, i);
- accum_dx += elem->dx;
- accum_dy += elem->dy;
- last = elem->evtime;
-
- if (i == 0)
- first = elem->evtime;
- }
-
- if (last == first)
- {
- scroll_history_reset (sw);
- return FALSE;
- }
-
- xunit = get_scroll_unit (sw, GTK_ORIENTATION_HORIZONTAL);
- yunit = get_scroll_unit (sw, GTK_ORIENTATION_VERTICAL);
- *velocity_x = (accum_dx * 1000 * xunit) / (last - first);
- *velocity_y = (accum_dy * 1000 * yunit) / (last - first);
- scroll_history_reset (sw);
-
- return TRUE;
-}
-
static gboolean
captured_event_cb (GtkWidget *widget,
GdkEvent *event)
@@ -1364,6 +1277,130 @@ captured_event_cb (GtkWidget *widget,
return GDK_EVENT_PROPAGATE;
}
+static gboolean
+start_scroll_deceleration_cb (gpointer user_data)
+{
+ GtkScrolledWindow *scrolled_window = user_data;
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+
+ priv->scroll_events_overshoot_id = 0;
+
+ if (!priv->deceleration_id)
+ {
+ uninstall_scroll_cursor (scrolled_window);
+ gtk_scrolled_window_start_deceleration (scrolled_window);
+ }
+
+ return FALSE;
+}
+
+static void
+scroll_controller_scroll_begin (GtkEventControllerScroll *scroll,
+ GtkScrolledWindow *scrolled_window)
+{
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+
+ install_scroll_cursor (scrolled_window);
+ priv->smooth_scroll = TRUE;
+}
+
+static void
+scroll_controller_scroll (GtkEventControllerScroll *scroll,
+ gdouble delta_x,
+ gdouble delta_y,
+ GtkScrolledWindow *scrolled_window)
+{
+ GtkScrolledWindowPrivate *priv;
+ gboolean shifted;
+ GdkModifierType state;
+
+ gtk_get_current_event_state (&state);
+ shifted = (state & GDK_SHIFT_MASK) != 0;
+
+ priv = scrolled_window->priv;
+
+ gtk_scrolled_window_invalidate_overshoot (scrolled_window);
+
+ if (shifted)
+ {
+ gdouble delta;
+
+ delta = delta_x;
+ delta_x = delta_y;
+ delta_y = delta;
+ }
+
+ if (delta_x != 0.0 &&
+ may_hscroll (scrolled_window))
+ {
+ GtkAdjustment *adj;
+ gdouble new_value;
+ gdouble scroll_unit;
+
+ adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
+ scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
+
+ new_value = priv->unclamped_hadj_value + delta_x * scroll_unit;
+ _gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
+ new_value);
+ }
+
+ if (delta_y != 0.0 &&
+ may_vscroll (scrolled_window))
+ {
+ GtkAdjustment *adj;
+ gdouble new_value;
+ gdouble scroll_unit;
+
+ adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
+ scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
+
+ new_value = priv->unclamped_vadj_value + delta_y * scroll_unit;
+ _gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
+ new_value);
+ }
+
+ if (priv->scroll_events_overshoot_id)
+ {
+ g_source_remove (priv->scroll_events_overshoot_id);
+ priv->scroll_events_overshoot_id = 0;
+ }
+
+ if (!priv->smooth_scroll &&
+ _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
+ {
+ priv->scroll_events_overshoot_id =
+ gdk_threads_add_timeout (50, start_scroll_deceleration_cb, scrolled_window);
+ g_source_set_name_by_id (priv->scroll_events_overshoot_id,
+ "[gtk+] start_scroll_deceleration_cb");
+ }
+}
+
+static void
+scroll_controller_scroll_end (GtkEventControllerScroll *scroll,
+ GtkScrolledWindow *scrolled_window)
+{
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+
+ priv->smooth_scroll = FALSE;
+ uninstall_scroll_cursor (scrolled_window);
+}
+
+static void
+scroll_controller_decelerate (GtkEventControllerScroll *scroll,
+ gdouble initial_vel_x,
+ gdouble initial_vel_y,
+ GtkScrolledWindow *scrolled_window)
+{
+ gdouble unit_x, unit_y;
+
+ unit_x = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
+ unit_y = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
+ gtk_scrolled_window_decelerate (scrolled_window,
+ initial_vel_x * unit_x,
+ initial_vel_y * unit_y);
+}
+
static void
gtk_scrolled_window_size_allocate (GtkWidget *widget,
const GtkAllocation *allocation,
@@ -1930,8 +1967,6 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
G_CALLBACK (scrolled_window_long_press_cancelled_cb),
scrolled_window);
- priv->scroll_history = g_array_new (FALSE, FALSE, sizeof (ScrollHistoryElem));
-
gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
@@ -1956,6 +1991,19 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
}
gtk_scrolled_window_update_use_indicators (scrolled_window);
+
+ priv->scroll_controller =
+ gtk_event_controller_scroll_new (widget,
+ GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES |
+ GTK_EVENT_CONTROLLER_SCROLL_KINETIC);
+ g_signal_connect (priv->scroll_controller, "scroll-begin",
+ G_CALLBACK (scroll_controller_scroll_begin), scrolled_window);
+ g_signal_connect (priv->scroll_controller, "scroll",
+ G_CALLBACK (scroll_controller_scroll), scrolled_window);
+ g_signal_connect (priv->scroll_controller, "scroll-end",
+ G_CALLBACK (scroll_controller_scroll_end), scrolled_window);
+ g_signal_connect (priv->scroll_controller, "decelerate",
+ G_CALLBACK (scroll_controller_decelerate), scrolled_window);
}
/**
@@ -2594,7 +2642,6 @@ gtk_scrolled_window_finalize (GObject *object)
g_clear_object (&priv->swipe_gesture);
g_clear_object (&priv->long_press_gesture);
g_clear_object (&priv->pan_gesture);
- g_clear_pointer (&priv->scroll_history, (GDestroyNotify) g_array_unref);
G_OBJECT_CLASS (gtk_scrolled_window_parent_class)->finalize (object);
}
@@ -3146,182 +3193,6 @@ uninstall_scroll_cursor (GtkScrolledWindow *scrolled_window)
gtk_widget_set_cursor (GTK_WIDGET (scrolled_window), NULL);
}
-static gboolean
-start_scroll_deceleration_cb (gpointer user_data)
-{
- GtkScrolledWindow *scrolled_window = user_data;
- GtkScrolledWindowPrivate *priv = scrolled_window->priv;
-
- priv->scroll_events_overshoot_id = 0;
-
- if (!priv->deceleration_id)
- {
- uninstall_scroll_cursor (scrolled_window);
- gtk_scrolled_window_start_deceleration (scrolled_window);
- }
-
- return FALSE;
-}
-
-
-static gboolean
-gtk_scrolled_window_scroll_event (GtkWidget *widget,
- GdkEventScroll *event)
-{
- GtkScrolledWindowPrivate *priv;
- GtkScrolledWindow *scrolled_window;
- gboolean handled = FALSE;
- gdouble delta_x;
- gdouble delta_y;
- GdkScrollDirection direction;
- gboolean shifted, start_deceleration = FALSE;
- GdkDevice *source_device;
- GdkInputSource input_source;
- guint state;
-
- if (!gdk_event_get_state ((GdkEvent *) event, &state))
- return GDK_EVENT_PROPAGATE;
-
- shifted = (state & GDK_SHIFT_MASK) != 0;
-
- scrolled_window = GTK_SCROLLED_WINDOW (widget);
- priv = scrolled_window->priv;
-
- gtk_scrolled_window_invalidate_overshoot (scrolled_window);
- source_device = gdk_event_get_source_device ((GdkEvent *) event);
- input_source = gdk_device_get_source (source_device);
-
- if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
- {
- if (priv->scroll_device != source_device)
- {
- priv->scroll_device = source_device;
- scroll_history_reset (scrolled_window);
- }
-
- scroll_history_push (scrolled_window, event);
-
- if (input_source == GDK_SOURCE_TRACKPOINT ||
- input_source == GDK_SOURCE_TOUCHPAD)
- install_scroll_cursor (scrolled_window);
-
- if (shifted)
- {
- gdouble delta;
-
- delta = delta_x;
- delta_x = delta_y;
- delta_y = delta;
- }
-
- if (delta_x != 0.0 &&
- may_hscroll (scrolled_window))
- {
- GtkAdjustment *adj;
- gdouble new_value;
- gdouble scroll_unit;
-
- adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
- scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
-
- new_value = priv->unclamped_hadj_value + delta_x * scroll_unit;
- _gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
- new_value);
- handled = TRUE;
- }
-
- if (delta_y != 0.0 &&
- may_vscroll (scrolled_window))
- {
- GtkAdjustment *adj;
- gdouble new_value;
- gdouble scroll_unit;
-
- adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
- scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
-
- new_value = priv->unclamped_vadj_value + delta_y * scroll_unit;
- _gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
- new_value);
- handled = TRUE;
- }
-
- /* The libinput driver may generate a final event with dx=dy=0
- * after scrolling finished, start kinetic scrolling when this
- * happens.
- */
- if (gdk_event_is_scroll_stop_event ((GdkEvent *) event))
- {
- handled = TRUE;
- start_deceleration = TRUE;
- }
- }
- else if (gdk_event_get_scroll_direction ((GdkEvent *)event, &direction))
- {
- GtkWidget *range;
- gboolean may_scroll;
-
- if ((!shifted && (direction == GDK_SCROLL_UP || direction == GDK_SCROLL_DOWN)) ||
- (shifted && (direction == GDK_SCROLL_LEFT || direction == GDK_SCROLL_RIGHT)))
- {
- range = priv->vscrollbar;
- may_scroll = may_vscroll (scrolled_window);
- }
- else
- {
- range = priv->hscrollbar;
- may_scroll = may_hscroll (scrolled_window);
- }
-
- if (range && may_scroll)
- {
- GtkAdjustment *adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (range));
- gdouble new_value;
- gdouble delta;
-
- delta = gtk_scrollbar_get_wheel_delta (GTK_SCROLLBAR (range), event);
-
- new_value = CLAMP (gtk_adjustment_get_value (adj) + delta,
- gtk_adjustment_get_lower (adj),
- gtk_adjustment_get_upper (adj) -
- gtk_adjustment_get_page_size (adj));
-
- gtk_adjustment_set_value (adj, new_value);
-
- handled = TRUE;
- }
- }
-
- if (handled)
- {
- gdouble vel_x, vel_y;
-
- gtk_scrolled_window_invalidate_overshoot (scrolled_window);
-
- if (priv->scroll_events_overshoot_id)
- {
- g_source_remove (priv->scroll_events_overshoot_id);
- priv->scroll_events_overshoot_id = 0;
- }
-
- if (start_deceleration)
- uninstall_scroll_cursor (scrolled_window);
-
- if (start_deceleration &&
- scroll_history_finish (scrolled_window, &vel_x, &vel_y))
- gtk_scrolled_window_decelerate (scrolled_window, vel_x, vel_y);
- else if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
- {
- priv->scroll_events_overshoot_id =
- gdk_threads_add_timeout (50, start_scroll_deceleration_cb, scrolled_window);
- g_source_set_name_by_id (priv->scroll_events_overshoot_id,
- "[gtk+] start_scroll_deceleration_cb");
- }
- }
-
- return handled;
-}
-
static void
_gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window,
GtkAdjustment *adjustment,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]