[gtksourceview/wip/chergert/fix-262: 1/2] gutter: notify gutter renderers of buffer changes




commit 66d9f2a2b45b48328c9dee92a9342ef225df3699
Author: Christian Hergert <chergert redhat com>
Date:   Wed Apr 6 14:33:44 2022 -0700

    gutter: notify gutter renderers of buffer changes
    
    This adds a vfunc to GtkSourceGutterRenderer to be notified of changes to
    the underlying buffer. Some effort is made to only call this once even
    if a bunch of changes are batched up together in buffer processing by
    handling it from an idle callback.
    
    Fixes #262

 gtksourceview/gtksourcegutter-private.h         |  2 +
 gtksourceview/gtksourcegutter.c                 | 13 ++++++
 gtksourceview/gtksourcegutterrenderer-private.h | 18 +++++----
 gtksourceview/gtksourcegutterrenderer.c         | 13 ++++++
 gtksourceview/gtksourcegutterrenderer.h         | 15 ++++++-
 gtksourceview/gtksourceview.c                   | 53 +++++++++++++++++++++++++
 6 files changed, 105 insertions(+), 9 deletions(-)
---
diff --git a/gtksourceview/gtksourcegutter-private.h b/gtksourceview/gtksourcegutter-private.h
index 030cfffc..2d626c0e 100644
--- a/gtksourceview/gtksourcegutter-private.h
+++ b/gtksourceview/gtksourcegutter-private.h
@@ -33,6 +33,8 @@ GtkSourceGutterLines *_gtk_source_gutter_get_lines      (GtkSourceGutter      *g
 G_GNUC_INTERNAL
 void                  _gtk_source_gutter_queue_draw     (GtkSourceGutter      *gutter);
 G_GNUC_INTERNAL
+void                  _gtk_source_gutter_buffer_changed (GtkSourceGutter      *gutter);
+G_GNUC_INTERNAL
 void                  _gtk_source_gutter_css_changed    (GtkSourceGutter      *gutter,
                                                          GtkCssStyleChange    *change);
 G_GNUC_INTERNAL
diff --git a/gtksourceview/gtksourcegutter.c b/gtksourceview/gtksourcegutter.c
index 4cfc96f2..dcef3bad 100644
--- a/gtksourceview/gtksourcegutter.c
+++ b/gtksourceview/gtksourcegutter.c
@@ -1081,3 +1081,16 @@ _gtk_source_gutter_unapply_scheme (GtkSourceGutter      *gutter,
                _gtk_source_style_scheme_unapply (scheme, GTK_WIDGET (renderer->renderer));
        }
 }
+
+void
+_gtk_source_gutter_buffer_changed (GtkSourceGutter *gutter)
+{
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER (gutter));
+
+       for (const GList *iter = gutter->renderers; iter; iter = iter->next)
+       {
+               Renderer *renderer = iter->data;
+
+               _gtk_source_gutter_renderer_buffer_changed (renderer->renderer);
+       }
+}
diff --git a/gtksourceview/gtksourcegutterrenderer-private.h b/gtksourceview/gtksourcegutterrenderer-private.h
index f6c4c99e..1ebbc4f5 100644
--- a/gtksourceview/gtksourcegutterrenderer-private.h
+++ b/gtksourceview/gtksourcegutterrenderer-private.h
@@ -26,16 +26,18 @@
 G_BEGIN_DECLS
 
 G_GNUC_INTERNAL
-void _gtk_source_gutter_renderer_set_view   (GtkSourceGutterRenderer *renderer,
-                                             GtkSourceView           *view);
+void _gtk_source_gutter_renderer_buffer_changed (GtkSourceGutterRenderer *renderer);
 G_GNUC_INTERNAL
-void _gtk_source_gutter_renderer_begin      (GtkSourceGutterRenderer *renderer,
-                                             GtkSourceGutterLines    *lines);
+void _gtk_source_gutter_renderer_set_view       (GtkSourceGutterRenderer *renderer,
+                                                 GtkSourceView           *view);
 G_GNUC_INTERNAL
-void _gtk_source_gutter_renderer_snapshot   (GtkSourceGutterRenderer *renderer,
-                                             GtkSnapshot             *snapshot,
-                                             GtkSourceGutterLines    *lines);
+void _gtk_source_gutter_renderer_begin          (GtkSourceGutterRenderer *renderer,
+                                                 GtkSourceGutterLines    *lines);
 G_GNUC_INTERNAL
-void _gtk_source_gutter_renderer_end        (GtkSourceGutterRenderer *renderer);
+void _gtk_source_gutter_renderer_snapshot       (GtkSourceGutterRenderer *renderer,
+                                                 GtkSnapshot             *snapshot,
+                                                 GtkSourceGutterLines    *lines);
+G_GNUC_INTERNAL
+void _gtk_source_gutter_renderer_end            (GtkSourceGutterRenderer *renderer);
 
 G_END_DECLS
diff --git a/gtksourceview/gtksourcegutterrenderer.c b/gtksourceview/gtksourcegutterrenderer.c
index a7a253f0..0017b423 100644
--- a/gtksourceview/gtksourcegutterrenderer.c
+++ b/gtksourceview/gtksourcegutterrenderer.c
@@ -1005,3 +1005,16 @@ _gtk_source_gutter_renderer_end (GtkSourceGutterRenderer *renderer)
        GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->end (renderer);
        g_clear_object (&priv->lines);
 }
+
+void
+_gtk_source_gutter_renderer_buffer_changed (GtkSourceGutterRenderer *renderer)
+{
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+
+       if (GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->buffer_changed)
+       {
+               GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->buffer_changed (renderer);
+       }
+}
diff --git a/gtksourceview/gtksourcegutterrenderer.h b/gtksourceview/gtksourcegutterrenderer.h
index e394d794..a0c1f563 100644
--- a/gtksourceview/gtksourcegutterrenderer.h
+++ b/gtksourceview/gtksourcegutterrenderer.h
@@ -90,8 +90,21 @@ struct _GtkSourceGutterRendererClass
                                           GdkModifierType               state,
                                           gint                          n_presses);
 
+  /**
+   * GtkSourceGutterRendererClass.buffer_changed:
+   *
+   * This virtual function is called when the underlying buffer changes
+   * to allow renderer implementations simplified access to invalidate
+   * any state necessary.
+   *
+   * An attempt is made to only call this once per main-loop cycle.
+   *
+   * Since: 5.6
+   */
+  void     (*buffer_changed)        (GtkSourceGutterRenderer      *renderer);
+
        /*< private >*/
-       gpointer _reserved[20];
+       gpointer _reserved[19];
 };
 
 GTK_SOURCE_AVAILABLE_IN_ALL
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index 3d5eaa0b..1893ab11 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -208,6 +208,8 @@ typedef struct
 
        GtkSourceViewSnippets snippets;
 
+       guint propagate_change_source;
+
        guint background_pattern_color_set : 1;
        guint current_line_background_color_set : 1;
        guint current_line_number_bold : 1;
@@ -1683,6 +1685,46 @@ implicit_trailing_newline_changed_cb (GtkSourceBuffer *buffer,
        gtk_source_view_queue_draw (view);
 }
 
+
+static gboolean
+propagate_change_cb (gpointer data)
+{
+       GtkSourceView *view = data;
+       GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
+
+       g_assert (GTK_SOURCE_IS_VIEW (view));
+
+       priv->propagate_change_source = 0;
+
+       if (priv->left_gutter)
+       {
+               _gtk_source_gutter_buffer_changed (priv->left_gutter);
+       }
+
+       if (priv->right_gutter)
+       {
+               _gtk_source_gutter_buffer_changed (priv->right_gutter);
+       }
+
+       return G_SOURCE_REMOVE;
+}
+
+static void
+changed_cb (GtkSourceBuffer *buffer,
+            GtkSourceView   *view)
+{
+       GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
+
+       g_assert (GTK_SOURCE_IS_BUFFER (buffer));
+       g_assert (GTK_SOURCE_IS_VIEW (view));
+
+       if (priv->propagate_change_source == 0 &&
+           (priv->left_gutter != NULL || priv->right_gutter != NULL))
+       {
+               priv->propagate_change_source = g_idle_add (propagate_change_cb, view);
+       }
+}
+
 static void
 remove_source_buffer (GtkSourceView *view)
 {
@@ -1692,6 +1734,12 @@ remove_source_buffer (GtkSourceView *view)
        {
                GtkSourceBufferInternal *buffer_internal;
 
+               g_clear_handle_id (&priv->propagate_change_source, g_source_remove);
+
+               g_signal_handlers_disconnect_by_func (priv->source_buffer,
+                                                     changed_cb,
+                                                     view);
+
                g_signal_handlers_disconnect_by_func (priv->source_buffer,
                                                      highlight_updated_cb,
                                                      view);
@@ -1744,6 +1792,11 @@ set_source_buffer (GtkSourceView *view,
 
                priv->source_buffer = g_object_ref (GTK_SOURCE_BUFFER (buffer));
 
+               g_signal_connect (buffer,
+                                 "changed",
+                                 G_CALLBACK (changed_cb),
+                                 view);
+
                g_signal_connect (buffer,
                                  "highlight-updated",
                                  G_CALLBACK (highlight_updated_cb),


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