From 71762d3b28b510ca29fd58113264585f7dfc37b9 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 27 Jun 2018 14:18:50 +0200 Subject: [PATCH] gtkscrolledwindow: Use controller for motion capturing Perform scrollbar visibility checks through a motion controller, always based on GtkScrolledView-relative coordinates. The captured event handler remains though, for a tiny bit of GDK_SCROLL event handling. --- gtk/gtkscrolledwindow.c | 165 ++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 93 deletions(-) diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index 2849042466..90d7b2fdfe 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -1052,17 +1052,16 @@ indicator_set_over (Indicator *indicator, } static gboolean -event_close_to_indicator (GtkScrolledWindow *sw, - Indicator *indicator, - GdkEvent *event) +coords_close_to_indicator (GtkScrolledWindow *sw, + Indicator *indicator, + gdouble x, + gdouble y) { GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (sw); graphene_rect_t indicator_bounds; - gdouble x, y; gint distance; gtk_widget_compute_bounds (indicator->scrollbar, GTK_WIDGET (sw), &indicator_bounds); - gdk_event_get_coords (event, &x, &y); if (indicator->over) distance = INDICATOR_FAR_DISTANCE; @@ -1099,25 +1098,18 @@ enable_over_timeout_cb (gpointer user_data) static gboolean check_update_scrollbar_proximity (GtkScrolledWindow *sw, Indicator *indicator, - GdkEvent *event) + GtkWidget *target, + gdouble x, + gdouble y) { GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (sw); gboolean indicator_close, on_scrollbar, on_other_scrollbar; - GtkWidget *event_target; - GtkWidget *event_target_ancestor; - GdkEventType event_type; - event_target = gtk_get_event_target (event); - event_target_ancestor = gtk_widget_get_ancestor (event_target, GTK_TYPE_SCROLLBAR); - event_type = gdk_event_get_event_type (event); - - indicator_close = event_close_to_indicator (sw, indicator, event); - on_scrollbar = (event_target_ancestor == indicator->scrollbar && - event_type != GDK_LEAVE_NOTIFY); + indicator_close = coords_close_to_indicator (sw, indicator, x, y); + on_scrollbar = (target == indicator->scrollbar); on_other_scrollbar = (!on_scrollbar && - event_type != GDK_LEAVE_NOTIFY && - (event_target_ancestor == priv->hindicator.scrollbar || - event_target_ancestor == priv->vindicator.scrollbar)); + (target == priv->hindicator.scrollbar || + target == priv->vindicator.scrollbar)); if (indicator->over_timeout_id) { @@ -1173,85 +1165,66 @@ captured_event_cb (GtkWidget *widget, GdkEvent *event) { GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW (widget); - GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (sw); - GdkInputSource input_source; - GdkDevice *source_device; - GtkWidget *event_target; - GtkWidget *event_target_ancestor; - gboolean on_scrollbar; - GdkEventType event_type; - guint state; - GdkCrossingMode mode; - source_device = gdk_event_get_source_device (event); - event_type = gdk_event_get_event_type (event); - - if (event_type == GDK_SCROLL) - { - gtk_scrolled_window_cancel_deceleration (sw); - return GDK_EVENT_PROPAGATE; - } - - if (!priv->use_indicators) - return GDK_EVENT_PROPAGATE; - - if (event_type != GDK_MOTION_NOTIFY && - event_type != GDK_LEAVE_NOTIFY) - return GDK_EVENT_PROPAGATE; - - input_source = gdk_device_get_source (source_device); - - if (input_source == GDK_SOURCE_KEYBOARD || - input_source == GDK_SOURCE_TOUCHSCREEN) - return GDK_EVENT_PROPAGATE; - - event_target = gtk_get_event_target (event); - event_target_ancestor = gtk_widget_get_ancestor (event_target, GTK_TYPE_SCROLLBAR); - on_scrollbar = (event_target_ancestor == priv->hindicator.scrollbar || - event_target_ancestor == priv->vindicator.scrollbar); - gdk_event_get_crossing_mode (event, &mode); - - if (event_type == GDK_MOTION_NOTIFY) - { - if (priv->hscrollbar_visible) - indicator_start_fade (&priv->hindicator, 1.0); - if (priv->vscrollbar_visible) - indicator_start_fade (&priv->vindicator, 1.0); - - gdk_event_get_state (event, &state); - - if (!on_scrollbar && - (state & - (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) != 0) - { - indicator_set_over (&priv->hindicator, FALSE); - indicator_set_over (&priv->vindicator, FALSE); - } - else if (input_source == GDK_SOURCE_PEN || - input_source == GDK_SOURCE_ERASER || - input_source == GDK_SOURCE_TRACKPOINT) - { - indicator_set_over (&priv->hindicator, TRUE); - indicator_set_over (&priv->vindicator, TRUE); - } - else - { - if (!check_update_scrollbar_proximity (sw, &priv->vindicator, event)) - check_update_scrollbar_proximity (sw, &priv->hindicator, event); - else - indicator_set_over (&priv->hindicator, FALSE); - } - } - else if (event_type == GDK_LEAVE_NOTIFY && on_scrollbar && - mode == GDK_CROSSING_UNGRAB) - { - check_update_scrollbar_proximity (sw, &priv->vindicator, event); - check_update_scrollbar_proximity (sw, &priv->hindicator, event); - } + if (gdk_event_get_event_type (event) == GDK_SCROLL) + gtk_scrolled_window_cancel_deceleration (sw); return GDK_EVENT_PROPAGATE; } +static void +captured_motion (GtkScrolledWindow *sw, + gdouble x, + gdouble y) +{ + GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (sw); + GdkDevice *source_device; + GdkInputSource input_source; + GdkModifierType state; + GdkEvent *event; + + if (!priv->use_indicators) + return; + + event = gtk_get_current_event (); + source_device = gdk_event_get_source_device (event); + input_source = gdk_device_get_source (source_device); + + if (priv->hscrollbar_visible) + indicator_start_fade (&priv->hindicator, 1.0); + if (priv->vscrollbar_visible) + indicator_start_fade (&priv->vindicator, 1.0); + + gdk_event_get_state (event, &state); + + if (!gtk_get_event_target_with_type (event, GTK_TYPE_SCROLLBAR) && + (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) != 0) + { + indicator_set_over (&priv->hindicator, FALSE); + indicator_set_over (&priv->vindicator, FALSE); + } + else if (input_source == GDK_SOURCE_PEN || + input_source == GDK_SOURCE_ERASER || + input_source == GDK_SOURCE_TRACKPOINT) + { + indicator_set_over (&priv->hindicator, TRUE); + indicator_set_over (&priv->vindicator, TRUE); + } + else + { + GtkWidget *target; + + target = gtk_get_event_target_with_type (event, GTK_TYPE_SCROLLBAR); + + if (!check_update_scrollbar_proximity (sw, &priv->vindicator, target, x, y)) + check_update_scrollbar_proximity (sw, &priv->hindicator, target, x, y); + else + indicator_set_over (&priv->hindicator, FALSE); + } + + g_object_unref (event); +} + static gboolean start_scroll_deceleration_cb (gpointer user_data) { @@ -1978,6 +1951,12 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) _gtk_widget_set_captured_event_handler (widget, captured_event_cb); + controller = gtk_event_controller_motion_new (); + gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE); + g_signal_connect_swapped (controller, "motion", + G_CALLBACK (captured_motion), scrolled_window); + gtk_widget_add_controller (widget, controller); + widget_node = gtk_widget_get_css_node (widget); for (i = 0; i < 4; i++) {