[evince] view: avoid getting pointer position from vertical scroll callback



commit b9059582a83c9b9ec180d2ec55898d23d9c0c2d6
Author: Cosimo Cecchi <cosimo endlessm com>
Date:   Thu Apr 26 18:10:57 2018 -0700

    view: avoid getting pointer position from vertical scroll callback
    
    When an EvView is embedded in a ClutterGTK stage, such as when it's used
    in sushi, calling into gdk_window_get_device_position() can result in an
    infinite loop, as it will force an allocation cycle inside Clutter,
    which results in a forced immediate draw event being delivered to the
    scrolled window while it's processing the scroll event.
    
    There may be more general issues with the ClutterGTK implementation, but
    in the meantime it's easy to avoid the issue from Evince:
    - if the adjustment changed value directly because of a scroll event, we
      can get the mouse pointer coordinates directly from the event
    - otherwise (e.g. scrollbar, or keynav), we can defer the update of the
      cursor to an idle handler, which avoids the deadlock
    
    https://bugzilla.gnome.org/show_bug.cgi?id=793401

 libview/ev-view-private.h |    2 +
 libview/ev-view.c         |   48 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 47 insertions(+), 3 deletions(-)
---
diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h
index 7bf9adc..2a387d0 100644
--- a/libview/ev-view-private.h
+++ b/libview/ev-view-private.h
@@ -168,6 +168,8 @@ struct _EvView {
        gint scroll_x;
        gint scroll_y;  
 
+       guint update_cursor_idle_id;
+
        /* Delta sum for emulating normal scrolling */
        gdouble       total_delta;
        PendingScroll pending_scroll;
diff --git a/libview/ev-view.c b/libview/ev-view.c
index d44ad81..f4a28f1 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -6969,6 +6969,11 @@ ev_view_dispose (GObject *object)
 
        ev_view_window_children_free (view);
 
+       if (view->update_cursor_idle_id) {
+               g_source_remove (view->update_cursor_idle_id);
+               view->update_cursor_idle_id = 0;
+       }
+
        if (view->selection_scroll_id) {
            g_source_remove (view->selection_scroll_id);
            view->selection_scroll_id = 0;
@@ -7887,15 +7892,40 @@ ev_view_page_changed_cb (EvDocumentModel *model,
        }
 }
 
+static gboolean
+cursor_scroll_update (gpointer data)
+{
+       EvView *view = data;
+       gint x, y;
+
+       view->update_cursor_idle_id = 0;
+       ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y);
+       ev_view_handle_cursor_over_xy (view, x, y);
+
+       return FALSE;
+}
+
+static void
+schedule_scroll_cursor_update (EvView *view)
+{
+       if (view->update_cursor_idle_id)
+               return;
+
+       view->update_cursor_idle_id =
+               g_idle_add (cursor_scroll_update, view);
+}
+
 static void
 on_adjustment_value_changed (GtkAdjustment *adjustment,
                             EvView        *view)
 {
        GtkWidget *widget = GTK_WIDGET (view);
        int dx = 0, dy = 0;
-       gint x, y;
+       gdouble x, y;
        gint value;
        GList *l;
+       GdkEvent *event;
+       gboolean cursor_updated;
 
        if (!gtk_widget_get_realized (widget))
                return;
@@ -7939,8 +7969,20 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
                gdk_window_scroll (gtk_widget_get_window (widget), dx, dy);
        }
 
-       ev_document_misc_get_pointer_position (widget, &x, &y);
-       ev_view_handle_cursor_over_xy (view, x, y);
+       cursor_updated = FALSE;
+       event = gtk_get_current_event ();
+       if (event) {
+               if (event->type == GDK_SCROLL &&
+                   gdk_event_get_window (event) == gtk_widget_get_window (widget)) {
+                       gdk_event_get_coords (event, &x, &y);
+                       ev_view_handle_cursor_over_xy (view, (gint) x, (gint) y);
+                       cursor_updated = TRUE;
+               }
+               gdk_event_free (event);
+       }
+
+       if (!cursor_updated)
+               schedule_scroll_cursor_update (view);
 
        if (view->document)
                view_update_range_and_current_page (view);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]