[gtksourceview/wip/improve-gutter-perfs: 2/2] Don't always invalidate the whole gutter



commit c4ef593974a6ba4ddfc31d4fa26d3f13f08c29fa
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Fri Sep 12 14:55:41 2014 +0200

    Don't always invalidate the whole gutter
    
    Instead, invalidate the whole lines gutter renderer only when needed.
    
    This should prevent degenerate cases where the gutter window is being
    continuously invalidated during certain operations, for example search.
    
    This is needed to have decent search performances on Mac OS X (but this
    is not the root cause why the search was really slow on OS X, it is
    probably because text drawing is much slower than on Linux).

 gtksourceview/gtksourcegutter.c              |   37 +--------------------
 gtksourceview/gtksourcegutterrendererlines.c |   47 ++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 36 deletions(-)
---
diff --git a/gtksourceview/gtksourcegutter.c b/gtksourceview/gtksourcegutter.c
index a4988c3..a0456c8 100644
--- a/gtksourceview/gtksourcegutter.c
+++ b/gtksourceview/gtksourcegutter.c
@@ -393,48 +393,13 @@ calculate_gutter_size (GtkSourceGutter  *gutter,
 }
 
 static void
-window_invalidate_handler (GdkWindow      *window,
-                          cairo_region_t *region)
-{
-       cairo_rectangle_int_t rect;
-
-       /* Always invalidate the whole window.
-        * When the text is modified in a GtkTextBuffer, GtkTextView tries to
-        * redraw the smallest required region. But the information displayed in
-        * the gutter may become invalid in a bigger region.
-        * See https://bugzilla.gnome.org/show_bug.cgi?id=732418 for an example
-        * where line numbers are not updated correctly when splitting a wrapped
-        * line.
-        * The performances should not be a big problem here. Correctness is
-        * more important than performances.
-        */
-
-       rect.x = 0;
-       rect.y = 0;
-       rect.width = gdk_window_get_width (window);
-       rect.height = gdk_window_get_height (window);
-
-       cairo_region_union_rectangle (region, &rect);
-}
-
-static void
 update_gutter_size (GtkSourceGutter *gutter)
 {
-       gint width;
-       GdkWindow *window;
-
-       width = calculate_gutter_size (gutter, NULL);
+       gint width = calculate_gutter_size (gutter, NULL);
 
        gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (gutter->priv->view),
                                              gutter->priv->window_type,
                                              width);
-
-       window = get_window (gutter);
-
-       if (window != NULL)
-       {
-               gdk_window_set_invalidate_handler (window, window_invalidate_handler);
-       }
 }
 
 static gboolean
diff --git a/gtksourceview/gtksourcegutterrendererlines.c b/gtksourceview/gtksourcegutterrendererlines.c
index ca65e07..eac9a5f 100644
--- a/gtksourceview/gtksourcegutterrendererlines.c
+++ b/gtksourceview/gtksourcegutterrendererlines.c
@@ -25,6 +25,7 @@
 struct _GtkSourceGutterRendererLinesPrivate
 {
        gint num_line_digits;
+       gint prev_line_count;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceGutterRendererLines, gtk_source_gutter_renderer_lines, 
GTK_SOURCE_TYPE_GUTTER_RENDERER_TEXT)
@@ -117,6 +118,8 @@ gutter_renderer_change_buffer (GtkSourceGutterRenderer *renderer,
 
                recalculate_size (lines);
        }
+
+       lines->priv->prev_line_count = 0;
 }
 
 static void
@@ -189,6 +192,49 @@ gutter_renderer_query_data (GtkSourceGutterRenderer      *renderer,
 }
 
 static void
+gutter_renderer_end (GtkSourceGutterRenderer *renderer)
+{
+       GtkSourceGutterRendererLines *lines = GTK_SOURCE_GUTTER_RENDERER_LINES (renderer);
+       GtkTextBuffer *buffer = get_buffer (lines);
+
+       if (buffer != NULL)
+       {
+               gint line_count = gtk_text_buffer_get_line_count (buffer);
+
+               /* When the text is modified in a GtkTextBuffer, GtkTextView tries to
+                * redraw the smallest required region. But the information displayed in
+                * the gutter may become invalid in a bigger region.
+                * See https://bugzilla.gnome.org/show_bug.cgi?id=732418 for an example
+                * where line numbers are not updated correctly when splitting a wrapped
+                * line.
+                * The performances should not be a big problem here. Correctness is
+                * more important than performances. It just triggers a second
+                * draw.
+                * The queue_draw() is called in gutter_renderer_end(), because
+                * the first draw is anyway needed to avoid flickering (if the
+                * first draw is not done, there will be a white region in the
+                * gutter during one frame).
+                *
+                * FIXME A better solution would be to add a vfunc in the
+                * GutterRenderer so that the Gutter can ask each renderer for
+                * the invalidation region, before drawing. So that only one
+                * draw is needed, and the solution would be more generic (if
+                * other renderers also need a different invalidation region
+                * than the GtkTextView). But the GutterRendererClass doesn't
+                * have padding for future expansion, so it must wait for
+                * GtkSourceView 4.
+                */
+               if (lines->priv->prev_line_count != line_count)
+               {
+                       lines->priv->prev_line_count = line_count;
+                       gtk_source_gutter_renderer_queue_draw (renderer);
+               }
+       }
+
+       GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_lines_parent_class)->end (renderer);
+}
+
+static void
 extend_selection_to_line (GtkSourceGutterRendererLines *renderer,
                           GtkTextIter                  *line_start)
 {
@@ -305,6 +351,7 @@ gtk_source_gutter_renderer_lines_class_init (GtkSourceGutterRendererLinesClass *
        GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass);
 
        renderer_class->query_data = gutter_renderer_query_data;
+       renderer_class->end = gutter_renderer_end;
        renderer_class->query_activatable = gutter_renderer_query_activatable;
        renderer_class->activate = gutter_renderer_activate;
        renderer_class->change_buffer = gutter_renderer_change_buffer;


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