[gtksourceview/wip/chergert/gsv-gtk4: 68/84] gutter: port to GTK 4



commit 02f60122b394819b47869286c8426fe31aeb8187
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 15 14:53:52 2020 -0800

    gutter: port to GTK 4
    
     - Use widgets instead of GInitiallyUnowned. This allows for much more
       advanced usage of event controllers, snapshoting, and potentially
       caching of render nodes.
     - GtkSourceGutter is now a container of GtkSourceGutterRenderer
     - Remove use of GdkEvent as much as possible and instead follow patterns
       for events more closely to upstream GTK 4. In particular the query
       and activate signals provide button/state/n_presses which are typically
       what would be needed by renderers anyway.
     - Tooltips can now be handled by renderers directly using the GtkWidget
       infrastructure for that.
     - Use GtkSourceGutterLines to reduce the number of passes we do through
       the textbuffer btree. This helps achieve a few more frames per second
       in the rendering pipeline during heavy kinetic scrolling. Especially
       on HiDPI systems.
     - Use GdkPaintable instead of GdkPixbuf for rendering pixbufs.
     - Add alignment helper for renderers to center on a particular position.
       This caches the positioning so that it can be reused by additional
       cell renderers without the extra floating point math or view area
       location.
     - Renderer state is no longer necessary as that information can be
       retrieved from the GtkSourceGutterLines using the helper functions.
       State is simply a quark in the quarkset like any other status.

 gtksourceview/gtksourcegutter-private.h         |   10 +-
 gtksourceview/gtksourcegutter.c                 | 1630 ++++++++---------------
 gtksourceview/gtksourcegutter.h                 |   27 +-
 gtksourceview/gtksourcegutterrenderer-private.h |   15 +-
 gtksourceview/gtksourcegutterrenderer.c         | 1445 +++++++-------------
 gtksourceview/gtksourcegutterrenderer.h         |  187 +--
 gtksourceview/gtksourcegutterrendererlines.c    |  304 ++---
 gtksourceview/gtksourcegutterrenderermarks.c    |  155 +--
 gtksourceview/gtksourcegutterrendererpixbuf.c   |  278 ++--
 gtksourceview/gtksourcegutterrendererpixbuf.h   |   28 +-
 gtksourceview/gtksourcegutterrenderertext.c     |  242 ++--
 11 files changed, 1600 insertions(+), 2721 deletions(-)
---
diff --git a/gtksourceview/gtksourcegutter-private.h b/gtksourceview/gtksourcegutter-private.h
index e1ebeb8a..a976b541 100644
--- a/gtksourceview/gtksourcegutter-private.h
+++ b/gtksourceview/gtksourcegutter-private.h
@@ -21,16 +21,16 @@
 #pragma once
 
 #include <gtk/gtk.h>
+
 #include "gtksourcetypes.h"
 
 G_BEGIN_DECLS
 
 G_GNUC_INTERNAL
-GtkSourceGutter *_gtk_source_gutter_new  (GtkSourceView     *view,
-                                          GtkTextWindowType  type);
+GtkSourceGutter      *_gtk_source_gutter_new        (GtkTextWindowType  type);
+G_GNUC_INTERNAL
+GtkSourceGutterLines *_gtk_source_gutter_get_lines  (GtkSourceGutter   *gutter);
 G_GNUC_INTERNAL
-void             _gtk_source_gutter_draw (GtkSourceGutter   *gutter,
-                                          GtkSourceView     *view,
-                                          cairo_t           *cr);
+void                  _gtk_source_gutter_queue_draw (GtkSourceGutter   *gutter);
 
 G_END_DECLS
diff --git a/gtksourceview/gtksourcegutter.c b/gtksourceview/gtksourcegutter.c
index 9a988e53..53f48af6 100644
--- a/gtksourceview/gtksourcegutter.c
+++ b/gtksourceview/gtksourcegutter.c
@@ -22,6 +22,8 @@
 
 #include "gtksourcegutter.h"
 #include "gtksourcegutter-private.h"
+#include "gtksourcegutterlines.h"
+#include "gtksourcegutterlines-private.h"
 #include "gtksourceview.h"
 #include "gtksourcegutterrenderer.h"
 #include "gtksourcegutterrenderer-private.h"
@@ -62,134 +64,60 @@ typedef struct
 
        gint prelit;
        gint position;
-
-       gulong queue_draw_handler;
-       gulong size_changed_handler;
-       gulong notify_xpad_handler;
-       gulong notify_ypad_handler;
-       gulong notify_visible_handler;
 } Renderer;
 
 struct _GtkSourceGutter
 {
-       GObject parent_instance;
-
-       GtkSourceView *view;
-       GtkTextWindowType window_type;
-       GtkOrientation orientation;
-
-       GList *renderers;
-
-       guint is_drawing : 1;
-};
+  GtkContainer          parent_instance;
 
-G_DEFINE_TYPE (GtkSourceGutter, gtk_source_gutter, G_TYPE_OBJECT)
-
-static gboolean on_view_motion_notify_event (GtkSourceView    *view,
-                                             GdkEventMotion   *event,
-                                             GtkSourceGutter  *gutter);
-static gboolean on_view_enter_notify_event  (GtkSourceView    *view,
-                                             GdkEventCrossing *event,
-                                             GtkSourceGutter  *gutter);
-static gboolean on_view_leave_notify_event  (GtkSourceView    *view,
-                                             GdkEventCrossing *event,
-                                             GtkSourceGutter  *gutter);
-static gboolean on_view_button_press_event  (GtkSourceView    *view,
-                                             GdkEventButton   *event,
-                                             GtkSourceGutter  *gutter);
-static gboolean on_view_query_tooltip       (GtkSourceView    *view,
-                                             gint              x,
-                                             gint              y,
-                                             gboolean          keyboard_mode,
-                                             GtkTooltip       *tooltip,
-                                             GtkSourceGutter  *gutter);
-static void     on_view_style_updated       (GtkSourceView    *view,
-                                             GtkSourceGutter  *gutter);
-static void     do_redraw                   (GtkSourceGutter  *gutter);
-static void     update_gutter_size          (GtkSourceGutter  *gutter);
-
-static GdkWindow *
-get_window (GtkSourceGutter *gutter)
-{
-       return gtk_text_view_get_window (GTK_TEXT_VIEW (gutter->view),
-                                        gutter->window_type);
-}
+       GtkSourceView        *view;
+       GList                *renderers;
+       GtkSourceGutterLines *lines;
 
-static void
-on_renderer_size_changed (GtkSourceGutterRenderer *renderer,
-                          GParamSpec              *spec,
-                          GtkSourceGutter         *gutter)
-{
-       update_gutter_size (gutter);
-}
+       GtkTextWindowType     window_type;
+       GtkOrientation        orientation;
 
-static void
-on_renderer_queue_draw (GtkSourceGutterRenderer *renderer,
-                        GtkSourceGutter         *gutter)
-{
-       do_redraw (gutter);
-}
+       gulong                adj_changed_handler;
+       gulong                realize_handler;
+       gulong                style_updated_handler;
 
-static void
-on_renderer_notify_padding (GtkSourceGutterRenderer *renderer,
-                            GParamSpec              *spec,
-                            GtkSourceGutter         *gutter)
-{
-       update_gutter_size (gutter);
-}
+       guint                 is_drawing : 1;
+};
 
-static void
-on_renderer_notify_visible (GtkSourceGutterRenderer *renderer,
-                            GParamSpec              *spec,
-                            GtkSourceGutter         *gutter)
-{
-       update_gutter_size (gutter);
-}
+G_DEFINE_TYPE (GtkSourceGutter, gtk_source_gutter, GTK_TYPE_CONTAINER)
+
+static void gtk_source_gutter_add           (GtkContainer             *container,
+                                             GtkWidget                *widget);
+static void gtk_source_gutter_remove        (GtkContainer             *container,
+                                             GtkWidget                *widget);
+static void on_view_style_updated           (GtkSourceView            *view,
+                                             GtkSourceGutter          *gutter);
+static void on_gutter_pressed_cb            (GtkSourceGutter          *gutter,
+                                             gint                      n_presses,
+                                             gdouble                   x,
+                                             gdouble                   y,
+                                             GtkGestureClick          *click);
+static void do_redraw                       (GtkSourceGutter          *gutter);
+static void gtk_source_gutter_snapshot      (GtkWidget                *widget,
+                                             GtkSnapshot              *snapshot);
+static void gtk_source_gutter_size_allocate (GtkWidget                *widget,
+                                             gint                      width,
+                                             gint                      height,
+                                             gint                      baseline);
 
 static Renderer *
 renderer_new (GtkSourceGutter         *gutter,
               GtkSourceGutterRenderer *renderer,
               gint                     position)
 {
-       Renderer *ret = g_slice_new0 (Renderer);
+       Renderer *ret;
 
+       ret = g_slice_new0 (Renderer);
        ret->renderer = g_object_ref_sink (renderer);
        ret->position = position;
        ret->prelit = -1;
 
-       _gtk_source_gutter_renderer_set_view (renderer,
-                                             GTK_TEXT_VIEW (gutter->view),
-                                             gutter->window_type);
-
-       ret->size_changed_handler =
-               g_signal_connect (ret->renderer,
-                                 "notify::size",
-                                 G_CALLBACK (on_renderer_size_changed),
-                                 gutter);
-
-       ret->queue_draw_handler =
-               g_signal_connect (ret->renderer,
-                                 "queue-draw",
-                                 G_CALLBACK (on_renderer_queue_draw),
-                                 gutter);
-
-       ret->notify_xpad_handler =
-               g_signal_connect (ret->renderer,
-                                 "notify::xpad",
-                                 G_CALLBACK (on_renderer_notify_padding),
-                                 gutter);
-
-       ret->notify_ypad_handler =
-               g_signal_connect (ret->renderer,
-                                 "notify::ypad",
-                                 G_CALLBACK (on_renderer_notify_padding),
-                                 gutter);
-
-       ret->notify_visible_handler =
-               g_signal_connect (ret->renderer,
-                                 "notify::visible",
-                                 G_CALLBACK (on_renderer_notify_visible),
-                                 gutter);
+       _gtk_source_gutter_renderer_set_view (renderer, gutter->view);
 
        return ret;
 }
@@ -197,40 +125,48 @@ renderer_new (GtkSourceGutter         *gutter,
 static void
 renderer_free (Renderer *renderer)
 {
-       g_signal_handler_disconnect (renderer->renderer,
-                                    renderer->queue_draw_handler);
-
-       g_signal_handler_disconnect (renderer->renderer,
-                                    renderer->size_changed_handler);
-
-       g_signal_handler_disconnect (renderer->renderer,
-                                    renderer->notify_xpad_handler);
-
-       g_signal_handler_disconnect (renderer->renderer,
-                                    renderer->notify_ypad_handler);
-
-       g_signal_handler_disconnect (renderer->renderer,
-                                    renderer->notify_visible_handler);
-
-       _gtk_source_gutter_renderer_set_view (renderer->renderer,
-                                             NULL,
-                                             GTK_TEXT_WINDOW_PRIVATE);
+       _gtk_source_gutter_renderer_set_view (renderer->renderer, NULL);
 
        g_object_unref (renderer->renderer);
        g_slice_free (Renderer, renderer);
 }
 
 static void
-gtk_source_gutter_dispose (GObject *object)
+get_alignment_modes (GtkSourceGutter *gutter,
+                     gboolean        *needs_wrap_first,
+                     gboolean        *needs_wrap_last)
 {
-       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (object);
+       const GList *list;
+
+       g_assert (GTK_SOURCE_GUTTER (gutter));
+       g_assert (needs_wrap_first != NULL);
+       g_assert (needs_wrap_last != NULL);
+
+       *needs_wrap_first = FALSE;
+       *needs_wrap_last = FALSE;
 
-       g_list_free_full (gutter->renderers, (GDestroyNotify)renderer_free);
-       gutter->renderers = NULL;
+       for (list = gutter->renderers; list; list = list->next)
+       {
+               Renderer *renderer = list->data;
+               GtkSourceGutterRendererAlignmentMode mode;
+
+               mode = gtk_source_gutter_renderer_get_alignment_mode (renderer->renderer);
+
+               switch (mode)
+               {
+                       case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST:
+                               *needs_wrap_first = TRUE;
+                               break;
 
-       gutter->view = NULL;
+                       case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_LAST:
+                               *needs_wrap_last = TRUE;
+                               break;
 
-       G_OBJECT_CLASS (gtk_source_gutter_parent_class)->dispose (object);
+                       case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL:
+                       default:
+                               break;
+               }
+       }
 }
 
 static void
@@ -239,16 +175,18 @@ gtk_source_gutter_get_property (GObject    *object,
                                 GValue     *value,
                                 GParamSpec *pspec)
 {
-       GtkSourceGutter *self = GTK_SOURCE_GUTTER (object);
+       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (object);
 
        switch (prop_id)
        {
                case PROP_VIEW:
-                       g_value_set_object (value, self->view);
+                       g_value_set_object (value, gutter->view);
                        break;
+
                case PROP_WINDOW_TYPE:
-                       g_value_set_enum (value, self->window_type);
+                       g_value_set_enum (value, gutter->window_type);
                        break;
+
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -256,143 +194,233 @@ gtk_source_gutter_get_property (GObject    *object,
 }
 
 static void
-on_view_realize (GtkSourceView   *view,
-                 GtkSourceGutter *gutter)
+on_adjustment_value_changed (GtkAdjustment   *adj,
+                             GtkSourceGutter *gutter)
+{
+       const GList *list;
+
+       for (list = gutter->renderers; list; list = list->next)
+       {
+               Renderer *renderer = list->data;
+
+               gtk_widget_queue_draw (GTK_WIDGET (renderer->renderer));
+       }
+}
+
+static GtkAdjustment *
+get_adjustment (GtkSourceGutter *gutter,
+               GtkSourceView   *view)
+{
+       if (gutter->window_type == GTK_TEXT_WINDOW_LEFT ||
+           gutter->window_type == GTK_TEXT_WINDOW_RIGHT)
+       {
+               return gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (view));
+       }
+       else
+       {
+               return gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (view));
+       }
+}
+
+static void
+connect_view (GtkSourceGutter *gutter,
+              GtkSourceView   *view)
+{
+       g_assert (GTK_SOURCE_IS_GUTTER (gutter));
+       g_assert (GTK_SOURCE_IS_VIEW (view));
+
+       gutter->adj_changed_handler =
+               g_signal_connect (get_adjustment (gutter, view),
+                                 "value-changed",
+                                 G_CALLBACK (on_adjustment_value_changed),
+                                 gutter);
+
+       gutter->style_updated_handler =
+               g_signal_connect (view,
+                                 "style-updated",
+                                 G_CALLBACK (on_view_style_updated),
+                                 gutter);
+}
+
+static void
+disconnect_view (GtkSourceGutter *gutter,
+                 GtkSourceView   *view)
 {
-       update_gutter_size (gutter);
+       g_assert (GTK_SOURCE_IS_GUTTER (gutter));
+       g_assert (GTK_SOURCE_IS_VIEW (view));
+
+       g_clear_signal_handler (&gutter->adj_changed_handler,
+                               get_adjustment (gutter, view));
+       g_clear_signal_handler (&gutter->realize_handler, view);
+       g_clear_signal_handler (&gutter->style_updated_handler, view);
 }
 
 static void
 set_view (GtkSourceGutter *gutter,
           GtkSourceView   *view)
 {
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER (gutter));
+       g_return_if_fail (!view || GTK_SOURCE_IS_VIEW (view));
+
+       if (view == gutter->view)
+       {
+               return;
+       }
+
+       if (gutter->view != NULL)
+       {
+               disconnect_view (gutter, gutter->view);
+       }
+
        gutter->view = view;
 
-       g_signal_connect_object (view,
-                                "motion-notify-event",
-                                G_CALLBACK (on_view_motion_notify_event),
-                                gutter,
-                                0);
-
-       g_signal_connect_object (view,
-                                "enter-notify-event",
-                                G_CALLBACK (on_view_enter_notify_event),
-                                gutter,
-                                0);
-
-       g_signal_connect_object (view,
-                                "leave-notify-event",
-                                G_CALLBACK (on_view_leave_notify_event),
-                                gutter,
-                                0);
-
-       g_signal_connect_object (view,
-                                "button-press-event",
-                                G_CALLBACK (on_view_button_press_event),
-                                gutter,
-                                0);
-
-       g_signal_connect_object (view,
-                                "query-tooltip",
-                                G_CALLBACK (on_view_query_tooltip),
-                                gutter,
-                                0);
-
-       g_signal_connect_object (view,
-                                "realize",
-                                G_CALLBACK (on_view_realize),
-                                gutter,
-                                0);
-
-       g_signal_connect_object (view,
-                                "style-updated",
-                                G_CALLBACK (on_view_style_updated),
-                                gutter,
-                                0);
+       if (view != NULL)
+       {
+               connect_view (gutter, view);
+       }
 }
 
 static void
 do_redraw (GtkSourceGutter *gutter)
 {
-       GdkWindow *window;
-
-       window = gtk_text_view_get_window (GTK_TEXT_VIEW (gutter->view),
-                                          gutter->window_type);
-
-       if (window && !gutter->is_drawing)
+       if (!gutter->is_drawing)
        {
-               gdk_window_invalidate_rect (window, NULL, FALSE);
+               gtk_widget_queue_draw (GTK_WIDGET (gutter));
        }
 }
 
-static gint
-calculate_gutter_size (GtkSourceGutter *gutter,
-                       GArray          *sizes)
+static void
+gtk_source_gutter_map (GtkWidget *widget)
+{
+       gtk_widget_set_cursor_from_name (widget, "arrow");
+       GTK_WIDGET_CLASS (gtk_source_gutter_parent_class)->map (widget);
+}
+
+static void
+gtk_source_gutter_measure (GtkWidget      *widget,
+                           GtkOrientation  orientation,
+                           int             for_size,
+                           int            *minimum,
+                           int            *natural,
+                           int            *minimum_baseline,
+                           int            *natural_baseline)
 {
-       GList *item;
-       gint total_width = 0;
+       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (widget);
+       const GList *item;
 
        /* Calculate size */
-       for (item = gutter->renderers; item; item = g_list_next (item))
+       for (item = gutter->renderers; item; item = item->next)
        {
                Renderer *renderer = item->data;
-               gint width;
+               int r_minimum;
+               int r_natural;
+               int r_minimum_baseline;
+               int r_natural_baseline;
 
-               if (!gtk_source_gutter_renderer_get_visible (renderer->renderer))
+               if (!gtk_widget_get_visible (GTK_WIDGET (renderer->renderer)))
                {
-                       width = 0;
+                       continue;
                }
-               else
-               {
-                       gint xpad;
-                       gint size;
 
-                       size = gtk_source_gutter_renderer_get_size (renderer->renderer);
+               gtk_widget_measure (GTK_WIDGET (renderer->renderer),
+                                   orientation,
+                                   for_size,
+                                   &r_minimum,
+                                   &r_natural,
+                                   &r_minimum_baseline,
+                                   &r_natural_baseline);
 
-                       gtk_source_gutter_renderer_get_padding (renderer->renderer,
-                                                               &xpad,
-                                                               NULL);
+               *minimum += r_minimum;
+               *natural += r_natural;
+       }
 
-                       width = size + 2 * xpad;
-               }
+       *minimum_baseline = -1;
+       *natural_baseline = -1;
+}
 
-               if (sizes)
-               {
-                       g_array_append_val (sizes, width);
-               }
+static void
+apply_style (GtkSourceGutter *gutter,
+            GtkStyleContext *style_context)
+{
+       const gchar *class;
+
+       switch (gutter->window_type)
+       {
+               case GTK_TEXT_WINDOW_TOP:
+                       class = GTK_STYLE_CLASS_TOP;
+                       break;
+
+               case GTK_TEXT_WINDOW_RIGHT:
+                       class = GTK_STYLE_CLASS_RIGHT;
+                       break;
+
+               case GTK_TEXT_WINDOW_BOTTOM:
+                       class = GTK_STYLE_CLASS_BOTTOM;
+                       break;
+
+               case GTK_TEXT_WINDOW_LEFT:
+                       class = GTK_STYLE_CLASS_LEFT;
+                       break;
 
-               total_width += width;
+               case GTK_TEXT_WINDOW_WIDGET:
+               case GTK_TEXT_WINDOW_TEXT:
+               default:
+                       g_return_if_reached ();
        }
 
-       return total_width;
+       gtk_style_context_add_class (style_context, class);
+}
+
+static void
+gtk_source_gutter_root (GtkWidget *widget)
+{
+       GtkWidget *view;
+
+       GTK_WIDGET_CLASS (gtk_source_gutter_parent_class)->root (widget);
+
+       view = gtk_widget_get_ancestor (widget, GTK_SOURCE_TYPE_VIEW);
+       set_view (GTK_SOURCE_GUTTER (widget), GTK_SOURCE_VIEW (view));
+}
+
+static void
+gtk_source_gutter_unroot (GtkWidget *widget)
+{
+       GTK_WIDGET_CLASS (gtk_source_gutter_parent_class)->unroot (widget);
+       set_view (GTK_SOURCE_GUTTER (widget), NULL);
 }
 
 static void
-update_gutter_size (GtkSourceGutter *gutter)
+gtk_source_gutter_forall (GtkContainer *container,
+                          GtkCallback   callback,
+                          gpointer      callback_data)
 {
-       gint width = calculate_gutter_size (gutter, NULL);
+       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (container);
+       const GList *list = gutter->renderers;
+
+       while (list != NULL)
+       {
+               Renderer *renderer = list->data;
+
+               list = list->next;
 
-       gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (gutter->view),
-                                             gutter->window_type,
-                                             width);
+               callback (GTK_WIDGET (renderer->renderer), callback_data);
+       }
 }
 
 static void
-gtk_source_gutter_set_property (GObject      *object,
-                                guint         prop_id,
-                                const GValue *value,
-                                GParamSpec   *pspec)
+gtk_source_gutter_set_property (GObject       *object,
+                                guint          prop_id,
+                                const GValue  *value,
+                                GParamSpec    *pspec)
 {
-       GtkSourceGutter *self = GTK_SOURCE_GUTTER (object);
+       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (object);
 
        switch (prop_id)
        {
-               case PROP_VIEW:
-                       set_view (self, GTK_SOURCE_VIEW (g_value_get_object (value)));
-                       break;
                case PROP_WINDOW_TYPE:
-                       self->window_type = g_value_get_enum (value);
+                       gutter->window_type = g_value_get_enum (value);
                        break;
+
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -402,33 +430,48 @@ gtk_source_gutter_set_property (GObject      *object,
 static void
 gtk_source_gutter_constructed (GObject *object)
 {
-       GtkSourceGutter *gutter;
-
-       gutter = GTK_SOURCE_GUTTER (object);
+       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (object);
+       GtkStyleContext *context;
 
        if (gutter->window_type == GTK_TEXT_WINDOW_LEFT ||
            gutter->window_type == GTK_TEXT_WINDOW_RIGHT)
        {
                gutter->orientation = GTK_ORIENTATION_HORIZONTAL;
+               gtk_widget_set_vexpand (GTK_WIDGET (gutter), TRUE);
        }
        else
        {
                gutter->orientation = GTK_ORIENTATION_VERTICAL;
+               gtk_widget_set_hexpand (GTK_WIDGET (gutter), TRUE);
        }
 
        G_OBJECT_CLASS (gtk_source_gutter_parent_class)->constructed (object);
+
+       context = gtk_widget_get_style_context (GTK_WIDGET (gutter));
+       apply_style (gutter, context);
 }
 
 static void
 gtk_source_gutter_class_init (GtkSourceGutterClass *klass)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+       GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
 
-       object_class->set_property = gtk_source_gutter_set_property;
+       object_class->constructed = gtk_source_gutter_constructed;
        object_class->get_property = gtk_source_gutter_get_property;
+       object_class->set_property = gtk_source_gutter_set_property;
 
-       object_class->dispose = gtk_source_gutter_dispose;
-       object_class->constructed = gtk_source_gutter_constructed;
+       widget_class->map = gtk_source_gutter_map;
+       widget_class->measure = gtk_source_gutter_measure;
+       widget_class->root = gtk_source_gutter_root;
+       widget_class->size_allocate = gtk_source_gutter_size_allocate;
+       widget_class->snapshot = gtk_source_gutter_snapshot;
+       widget_class->unroot = gtk_source_gutter_unroot;
+
+       container_class->forall = gtk_source_gutter_forall;
+       container_class->add = gtk_source_gutter_add;
+       container_class->remove = gtk_source_gutter_remove;
 
        /**
         * GtkSourceGutter:view:
@@ -441,7 +484,7 @@ gtk_source_gutter_class_init (GtkSourceGutterClass *klass)
                                                              "View",
                                                              "",
                                                              GTK_SOURCE_TYPE_VIEW,
-                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+                                                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
        /**
         * GtkSourceGutter:window-type:
@@ -454,14 +497,43 @@ gtk_source_gutter_class_init (GtkSourceGutterClass *klass)
                                                            "Window Type",
                                                            "The gutters' text window type",
                                                            GTK_TYPE_TEXT_WINDOW_TYPE,
-                                                           0,
+                                                           GTK_TEXT_WINDOW_LEFT,
                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+       gtk_widget_class_set_css_name (widget_class, "gutter");
 }
 
 static void
-gtk_source_gutter_init (GtkSourceGutter *self)
+gtk_source_gutter_init (GtkSourceGutter *gutter)
 {
-       self = gtk_source_gutter_get_instance_private (self);
+       GtkGesture *click;
+       GtkEventController *motion;
+
+  gutter->window_type = GTK_TEXT_WINDOW_LEFT;
+
+       /* Setup fallback click handling */
+       click = gtk_gesture_click_new ();
+       g_signal_connect_swapped (click,
+                                 "pressed",
+                                 G_CALLBACK (on_gutter_pressed_cb),
+                                gutter);
+       gtk_widget_add_controller (GTK_WIDGET (gutter), GTK_EVENT_CONTROLLER (click));
+
+       /* Track motion enter/leave for prelit status */
+       motion = gtk_event_controller_motion_new ();
+       g_signal_connect_swapped (motion,
+                                 "enter",
+                                 G_CALLBACK (gtk_widget_queue_draw),
+                                 gutter);
+       g_signal_connect_swapped (motion,
+                                 "leave",
+                                 G_CALLBACK (gtk_widget_queue_draw),
+                                 gutter);
+       g_signal_connect_swapped (motion,
+                                 "motion",
+                                 G_CALLBACK (gtk_widget_queue_draw),
+                                 gutter);
+       gtk_widget_add_controller (GTK_WIDGET (gutter), motion);
 }
 
 static gint
@@ -487,32 +559,26 @@ static void
 append_renderer (GtkSourceGutter *gutter,
                  Renderer        *renderer)
 {
-       gutter->renderers =
-               g_list_insert_sorted_with_data (gutter->renderers,
-                                               renderer,
-                                               (GCompareDataFunc)sort_by_position,
-                                               NULL);
-
-       update_gutter_size (gutter);
+       gutter->renderers = g_list_insert_sorted_with_data (gutter->renderers,
+                                                         renderer,
+                                                         (GCompareDataFunc)sort_by_position,
+                                                         NULL);
 }
 
 GtkSourceGutter *
-_gtk_source_gutter_new (GtkSourceView     *view,
-                        GtkTextWindowType  type)
+_gtk_source_gutter_new (GtkTextWindowType type)
 {
        return g_object_new (GTK_SOURCE_TYPE_GUTTER,
-                            "view", view,
                             "window_type", type,
                             NULL);
 }
 
-/* Public API */
-
 /**
  * gtk_source_gutter_get_view:
  * @gutter: a #GtkSourceGutter.
  *
  * Returns: (transfer none): the associated #GtkSourceView.
+ *
  * Since: 3.24
  */
 GtkSourceView *
@@ -523,21 +589,6 @@ gtk_source_gutter_get_view (GtkSourceGutter *gutter)
        return gutter->view;
 }
 
-/**
- * gtk_source_gutter_get_window_type:
- * @gutter: a #GtkSourceGutter.
- *
- * Returns: the #GtkTextWindowType of @gutter.
- * Since: 3.24
- */
-GtkTextWindowType
-gtk_source_gutter_get_window_type (GtkSourceGutter *gutter)
-{
-       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER (gutter), GTK_TEXT_WINDOW_PRIVATE);
-
-       return gutter->window_type;
-}
-
 /**
  * gtk_source_gutter_insert:
  * @gutter: a #GtkSourceGutter.
@@ -563,10 +614,11 @@ gtk_source_gutter_insert (GtkSourceGutter         *gutter,
        g_return_val_if_fail (GTK_SOURCE_IS_GUTTER (gutter), FALSE);
        g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), FALSE);
        g_return_val_if_fail (gtk_source_gutter_renderer_get_view (renderer) == NULL, FALSE);
-       g_return_val_if_fail (gtk_source_gutter_renderer_get_window_type (renderer) == 
GTK_TEXT_WINDOW_PRIVATE, FALSE);
 
        internal_renderer = renderer_new (gutter, renderer, position);
        append_renderer (gutter, internal_renderer);
+       gtk_widget_set_parent (GTK_WIDGET (renderer), GTK_WIDGET (gutter));
+       gtk_widget_queue_resize (GTK_WIDGET (gutter));
 
        return TRUE;
 }
@@ -579,7 +631,7 @@ renderer_find (GtkSourceGutter          *gutter,
 {
        GList *list;
 
-       for (list = gutter->renderers; list; list = g_list_next (list))
+       for (list = gutter->renderers; list; list = list->next)
        {
                *ret = list->data;
 
@@ -597,6 +649,55 @@ renderer_find (GtkSourceGutter          *gutter,
        return FALSE;
 }
 
+static void
+gtk_source_gutter_add (GtkContainer *container,
+                      GtkWidget    *widget)
+{
+       if (!GTK_SOURCE_IS_GUTTER_RENDERER (widget))
+       {
+               g_warning ("Cannot add %s to %s as it is not a GtkSourceGutterRenderer",
+                          G_OBJECT_TYPE_NAME (widget),
+                          G_OBJECT_TYPE_NAME (container));
+       }
+       else
+       {
+               gtk_source_gutter_insert (GTK_SOURCE_GUTTER (container),
+                                         GTK_SOURCE_GUTTER_RENDERER (widget),
+                                         0);
+       }
+}
+
+static void
+gtk_source_gutter_remove (GtkContainer *container,
+                          GtkWidget    *widget)
+{
+       GtkSourceGutterRenderer *renderer;
+       GtkSourceGutter *gutter;
+       Renderer *ret;
+       GList *retlist;
+
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER (container));
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (widget));
+
+       gutter = GTK_SOURCE_GUTTER (container);
+       renderer = GTK_SOURCE_GUTTER_RENDERER (widget);
+
+       if (renderer_find (gutter, renderer, &ret, &retlist))
+       {
+               gutter->renderers =
+                       g_list_delete_link (gutter->renderers, retlist);
+               gtk_widget_unparent (GTK_WIDGET (renderer));
+               renderer_free (ret);
+               gtk_widget_queue_resize (GTK_WIDGET (gutter));
+       }
+       else
+       {
+               g_warning ("Failed to locate %s within %s",
+                          G_OBJECT_TYPE_NAME (widget),
+                          G_OBJECT_TYPE_NAME (gutter));
+       }
+}
+
 /**
  * gtk_source_gutter_reorder:
  * @gutter: a #GtkSourceGutterRenderer.
@@ -621,629 +722,201 @@ gtk_source_gutter_reorder (GtkSourceGutter         *gutter,
        if (renderer_find (gutter, renderer, &ret, &retlist))
        {
                gutter->renderers =
-                       g_list_delete_link (gutter->renderers,
-                                           retlist);
-
+                       g_list_delete_link (gutter->renderers, retlist);
                ret->position = position;
                append_renderer (gutter, ret);
+               gtk_widget_queue_allocate (GTK_WIDGET (gutter));
        }
 }
 
-/**
- * gtk_source_gutter_remove:
- * @gutter: a #GtkSourceGutter.
- * @renderer: a #GtkSourceGutterRenderer.
- *
- * Removes @renderer from @gutter.
- *
- * Since: 2.8
- */
-void
-gtk_source_gutter_remove (GtkSourceGutter         *gutter,
-                          GtkSourceGutterRenderer *renderer)
+static void
+gtk_source_gutter_size_allocate (GtkWidget *widget,
+                                 gint       width,
+                                 gint       height,
+                                 gint       baseline)
 {
-       Renderer *ret;
-       GList *retlist;
+       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (widget);
+       const GList *list;
+       gint x = 0;
 
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER (gutter));
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       GTK_WIDGET_CLASS (gtk_source_gutter_parent_class)->size_allocate (widget,
+                                                                         width,
+                                                                         height,
+                                                                         baseline);
 
-       if (renderer_find (gutter, renderer, &ret, &retlist))
+       for (list = gutter->renderers; list; list = list->next)
        {
-               gutter->renderers =
-                       g_list_delete_link (gutter->renderers,
-                                           retlist);
+               Renderer *renderer = list->data;
+               GtkRequisition child_req;
+               GtkAllocation alloc;
 
-               update_gutter_size (gutter);
-               renderer_free (ret);
-       }
-}
+               gtk_widget_get_preferred_size (GTK_WIDGET (renderer->renderer),
+                                              &child_req, NULL);
 
-/**
- * gtk_source_gutter_queue_draw:
- * @gutter: a #GtkSourceGutter.
- *
- * Invalidates the drawable area of the gutter. You can use this to force a
- * redraw of the gutter if something has changed and needs to be redrawn.
- *
- * Since: 2.8
- */
-void
-gtk_source_gutter_queue_draw (GtkSourceGutter *gutter)
-{
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER (gutter));
+               alloc.x = x;
+               alloc.y = 0;
+               alloc.width = child_req.width;
+               alloc.height = height;
 
-       do_redraw (gutter);
+               gtk_widget_size_allocate (GTK_WIDGET (renderer->renderer),
+                                         &alloc,
+                                         -1);
+
+               x += alloc.width;
+       }
+
+       gtk_widget_queue_draw (widget);
 }
 
-typedef struct
+static void
+gtk_source_gutter_snapshot (GtkWidget   *widget,
+                            GtkSnapshot *snapshot)
 {
-       gint total_height;
-       gint lines_count;
-       GArray *buffer_coords;
-       GArray *line_heights;
-       GArray *line_numbers;
-       GtkTextIter start;
+       GtkSourceGutter *gutter = GTK_SOURCE_GUTTER (widget);
+       GtkTextView *text_view = GTK_TEXT_VIEW (gutter->view);
+       GtkStyleContext *view_context;
+       const GList *list;
+       GdkRectangle visible_rect;
+       GtkTextIter begin;
        GtkTextIter end;
-} LinesInfo;
+       gboolean needs_wrap_first = FALSE;
+       gboolean needs_wrap_last = FALSE;
 
-static LinesInfo *
-lines_info_new (void)
-{
-       LinesInfo *info;
+       g_clear_object (&gutter->lines);
 
-       info = g_slice_new0 (LinesInfo);
+       if (text_view == NULL || gtk_widget_get_width (widget) == 0)
+       {
+               return;
+       }
 
-       info->buffer_coords = g_array_new (FALSE, FALSE, sizeof (gint));
-       info->line_heights = g_array_new (FALSE, FALSE, sizeof (gint));
-       info->line_numbers = g_array_new (FALSE, FALSE, sizeof (gint));
+       /* We need the style from the view itself for highlight lines */
+       view_context = gtk_widget_get_style_context (GTK_WIDGET (gutter->view));
 
-       return info;
-}
+       gtk_text_view_get_visible_rect (text_view, &visible_rect);
+       gtk_text_view_get_iter_at_location (text_view, &begin,
+                                           visible_rect.x, visible_rect.y);
+       gtk_text_view_get_iter_at_location (text_view, &end,
+                                           visible_rect.x,
+                                           visible_rect.y + visible_rect.height);
 
-static void
-lines_info_free (LinesInfo *info)
-{
-       if (info != NULL)
+       /* The first step is to get line information about all the visible
+        * lines. We do this up front so that we can do it once to reduce many
+        * times the renderers need to walk through the buffer contents as that
+        * can be expensive.
+        */
+       get_alignment_modes (gutter, &needs_wrap_first, &needs_wrap_last);
+       gutter->lines = _gtk_source_gutter_lines_new (text_view,
+                                                     &begin,
+                                                     &end,
+                                                     needs_wrap_first,
+                                                     needs_wrap_last);
+
+       /* Draw the current-line highlight if necessary */
+       if (gtk_source_view_get_highlight_current_line (gutter->view))
        {
-               g_array_free (info->buffer_coords, TRUE);
-               g_array_free (info->line_heights, TRUE);
-               g_array_free (info->line_numbers, TRUE);
+               guint cursor_line;
 
-               g_slice_free (LinesInfo, info);
-       }
-}
+               cursor_line = _gtk_source_gutter_lines_get_cursor_line (gutter->lines);
 
-/* This function is taken and adapted from gtk+/tests/testtext.c */
-static LinesInfo *
-get_lines_info (GtkTextView *text_view,
-                gint         first_y_buffer_coord,
-                gint         last_y_buffer_coord)
-{
-       LinesInfo *info;
-       GtkTextIter iter;
-       gint last_line_num = -1;
+               if (cursor_line >= gtk_source_gutter_lines_get_first (gutter->lines) &&
+                   cursor_line <= gtk_source_gutter_lines_get_last (gutter->lines))
+               {
+                       gint y;
+                       gint height;
+
+                       gtk_source_gutter_lines_get_line_yrange (gutter->lines,
+                                                                cursor_line,
+                                                                
GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL,
+                                                                &y,
+                                                                &height);
+
+                       gtk_style_context_save (view_context);
+                       gtk_style_context_add_class (view_context, "current-line-number");
+
+                       gtk_snapshot_render_background (snapshot,
+                                                       view_context,
+                                                       0,
+                                                       y,
+                                                       gtk_widget_get_width (widget),
+                                                       height);
+
+                       gtk_style_context_restore (view_context);
+               }
+       }
 
-       info = lines_info_new ();
+       gutter->is_drawing = TRUE;
 
-       /* Get iter at first y */
-       gtk_text_view_get_line_at_y (text_view, &iter, first_y_buffer_coord, NULL);
+       /* Now let the renderers populate information about the lines that are
+        * to be rendered. They may need to go through line by line and add
+        * classes (GQuark) to the lines to be used when snapshoting. Since
+        * we've already calculated line information, this is relatively fast.
+        *
+        * We also only emit the ::query-data signal in the case that the
+        * renderer has not override then (*query_data) vfunc which saves quite
+        * a bit of signal overhead.
+        */
+       for (list = gutter->renderers; list; list = list->next)
+       {
+               Renderer *renderer = list->data;
 
-       info->start = iter;
+               _gtk_source_gutter_renderer_begin (renderer->renderer,
+                                                  gutter->lines);
+       }
 
-       /* For each iter, get its location and add it to the arrays.
-        * Stop when we pass last_y_buffer_coord.
+       gtk_snapshot_push_clip (snapshot,
+                               &GRAPHENE_RECT_INIT (0,
+                                                    0,
+                                                    gtk_widget_get_width (widget),
+                                                    gtk_widget_get_height (widget)));
+
+       /* Now let the renderers draw the content for each line. Because
+        * iterating a Linked-List is slower than iterating a series of line
+        * numbers, we make the renderer list the outter loop, and the
+        * snapshotting of lines (within the renderer) the inner loop as part
+        * of snapshot.
         */
-       while (!gtk_text_iter_is_end (&iter))
+       for (list = gutter->renderers; list; list = list->next)
        {
-               gint y;
-               gint height;
-               gint line_num;
+               Renderer *renderer = list->data;
 
-               gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
-
-               g_array_append_val (info->buffer_coords, y);
-               g_array_append_val (info->line_heights, height);
+               gtk_widget_snapshot_child (widget,
+                                          GTK_WIDGET (renderer->renderer),
+                                          snapshot);
+       }
 
-               info->total_height += height;
+       gtk_snapshot_pop (snapshot);
 
-               line_num = gtk_text_iter_get_line (&iter);
-               g_array_append_val (info->line_numbers, line_num);
+       /* Allow to call queue_redraw() in end. */
+       gutter->is_drawing = FALSE;
 
-               last_line_num = line_num;
+       /* Now notify the renderers of completion */
+       for (list = gutter->renderers; list; list = list->next)
+       {
+               Renderer *renderer = list->data;
 
-               info->lines_count++;
-
-               if (last_y_buffer_coord <= (y + height))
-               {
-                       break;
-               }
-
-               gtk_text_iter_forward_line (&iter);
-       }
-
-       if (gtk_text_iter_is_end (&iter))
-       {
-               gint y;
-               gint height;
-               gint line_num;
-
-               gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
-
-               line_num = gtk_text_iter_get_line (&iter);
-
-               if (line_num != last_line_num)
-               {
-                       g_array_append_val (info->buffer_coords, y);
-                       g_array_append_val (info->line_heights, height);
-
-                       info->total_height += height;
-
-                       g_array_append_val (info->line_numbers, line_num);
-                       info->lines_count++;
-               }
-       }
-
-       if (info->lines_count == 0)
-       {
-               gint y = 0;
-               gint n = 0;
-               gint height;
-
-               info->lines_count = 1;
-
-               g_array_append_val (info->buffer_coords, y);
-               g_array_append_val (info->line_numbers, n);
-
-               gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
-               g_array_append_val (info->line_heights, height);
-
-               info->total_height += height;
-       }
-
-       info->end = iter;
-
-       return info;
-}
-
-/* Returns %TRUE if @clip is set. @clip contains the area that should be drawn. */
-static gboolean
-get_clip_rectangle (GtkSourceGutter *gutter,
-                    GtkSourceView   *view,
-                    cairo_t         *cr,
-                    GdkRectangle    *clip)
-{
-       GdkWindow *window = get_window (gutter);
-
-       if (window == NULL || !gtk_cairo_should_draw_window (cr, window))
-       {
-               return FALSE;
-       }
-
-       gtk_cairo_transform_to_window (cr, GTK_WIDGET (view), window);
-
-       return gdk_cairo_get_clip_rectangle (cr, clip);
-}
-
-static void
-apply_style (GtkSourceGutter *gutter,
-             GtkSourceView   *view,
-             GtkStyleContext *style_context,
-             cairo_t         *cr)
-{
-       const gchar *class;
-       GdkRGBA fg_color;
-
-       switch (gutter->window_type)
-       {
-               case GTK_TEXT_WINDOW_TOP:
-                       class = GTK_STYLE_CLASS_TOP;
-                       break;
-
-               case GTK_TEXT_WINDOW_RIGHT:
-                       class = GTK_STYLE_CLASS_RIGHT;
-                       break;
-
-               case GTK_TEXT_WINDOW_BOTTOM:
-                       class = GTK_STYLE_CLASS_BOTTOM;
-                       break;
-
-               case GTK_TEXT_WINDOW_LEFT:
-                       class = GTK_STYLE_CLASS_LEFT;
-                       break;
-
-               case GTK_TEXT_WINDOW_PRIVATE:
-               case GTK_TEXT_WINDOW_WIDGET:
-               case GTK_TEXT_WINDOW_TEXT:
-               default:
-                       g_return_if_reached ();
-       }
-
-       /* Apply classes ourselves, since we are in connect_after and so they
-        * are not set by gtk.
-        */
-       gtk_style_context_add_class (style_context, class);
-       gtk_style_context_get_color (style_context,
-                                    gtk_style_context_get_state (style_context),
-                                    &fg_color);
-
-       gdk_cairo_set_source_rgba (cr, &fg_color);
-}
-
-/* Call gtk_source_gutter_renderer_begin() on each renderer. */
-static void
-begin_draw (GtkSourceGutter *gutter,
-            GtkTextView     *view,
-            GArray          *renderer_widths,
-            LinesInfo       *info,
-            cairo_t         *cr)
-{
-       GdkRectangle background_area = { 0 };
-       GdkRectangle cell_area;
-       GList *l;
-       gint renderer_num;
-
-       background_area.x = 0;
-       background_area.height = info->total_height;
-
-       gtk_text_view_buffer_to_window_coords (view,
-                                              gutter->window_type,
-                                              0,
-                                              g_array_index (info->buffer_coords, gint, 0),
-                                              NULL,
-                                              &background_area.y);
-
-       cell_area = background_area;
-
-       for (l = gutter->renderers, renderer_num = 0;
-            l != NULL;
-            l = l->next, renderer_num++)
-       {
-               Renderer *renderer = l->data;
-               gint width;
-               gint xpad;
-
-               width = g_array_index (renderer_widths, gint, renderer_num);
-
-               if (!gtk_source_gutter_renderer_get_visible (renderer->renderer))
-               {
-                       g_assert_cmpint (width, ==, 0);
-                       continue;
-               }
-
-               gtk_source_gutter_renderer_get_padding (renderer->renderer,
-                                                       &xpad,
-                                                       NULL);
-
-               background_area.width = width;
-
-               cell_area.width = background_area.width - 2 * xpad;
-               cell_area.x = background_area.x + xpad;
-
-               cairo_save (cr);
-
-               gdk_cairo_rectangle (cr, &background_area);
-               cairo_clip (cr);
-
-               gtk_source_gutter_renderer_begin (renderer->renderer,
-                                                 cr,
-                                                 &background_area,
-                                                 &cell_area,
-                                                 &info->start,
-                                                 &info->end);
-
-               cairo_restore (cr);
-
-               background_area.x += background_area.width;
-       }
-}
-
-static void
-draw_cells (GtkSourceGutter *gutter,
-            GtkTextView     *view,
-            GArray          *renderer_widths,
-            LinesInfo       *info,
-            cairo_t         *cr)
-{
-       GtkTextBuffer *buffer;
-       GtkTextIter insert_iter;
-       gint cur_line;
-       GtkTextIter selection_start;
-       GtkTextIter selection_end;
-       gint selection_start_line = 0;
-       gint selection_end_line = 0;
-       gboolean has_selection;
-       GtkTextIter start;
-       gint i;
-
-       buffer = gtk_text_view_get_buffer (view);
-
-       gtk_text_buffer_get_iter_at_mark (buffer,
-                                         &insert_iter,
-                                         gtk_text_buffer_get_insert (buffer));
-
-       cur_line = gtk_text_iter_get_line (&insert_iter);
-
-       has_selection = gtk_text_buffer_get_selection_bounds (buffer,
-                                                             &selection_start,
-                                                             &selection_end);
-
-       if (has_selection)
-       {
-               selection_start_line = gtk_text_iter_get_line (&selection_start);
-               selection_end_line = gtk_text_iter_get_line (&selection_end);
-       }
-
-       start = info->start;
-       i = 0;
-
-       while (i < info->lines_count)
-       {
-               GtkTextIter end;
-               GdkRectangle background_area;
-               GtkSourceGutterRendererState state;
-               gint pos;
-               gint line_to_paint;
-               gint renderer_num;
-               GList *l;
-
-               end = start;
-
-               if (!gtk_text_iter_ends_line (&end))
-               {
-                       /*
-                        * It turns out that gtk_text_iter_forward_to_line_end
-                        * is slower than jumping to the next line in the
-                        * btree index and then moving backwards a character.
-                        * We don't really care that we might be after the
-                        * newline breaking characters, since those are part
-                        * of the same line (rather than the next line).
-                        */
-                       if (gtk_text_iter_forward_line (&end))
-                       {
-                               gtk_text_iter_backward_char (&end);
-                       }
-               }
-
-               /* Possible improvement: if buffer and window coords have the
-                * same unit, there are probably some possible performance
-                * improvements by avoiding some buffer <-> window coords
-                * conversions.
-                */
-               gtk_text_view_buffer_to_window_coords (view,
-                                                      gutter->window_type,
-                                                      0,
-                                                      g_array_index (info->buffer_coords, gint, i),
-                                                      NULL,
-                                                      &pos);
-
-               line_to_paint = g_array_index (info->line_numbers, gint, i);
-
-               background_area.y = pos;
-               background_area.height = g_array_index (info->line_heights, gint, i);
-               background_area.x = 0;
-
-               state = GTK_SOURCE_GUTTER_RENDERER_STATE_NORMAL;
-
-               if (line_to_paint == cur_line)
-               {
-                       state |= GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR;
-               }
-
-               if (has_selection &&
-                   selection_start_line <= line_to_paint && line_to_paint <= selection_end_line)
-               {
-                       state |= GTK_SOURCE_GUTTER_RENDERER_STATE_SELECTED;
-               }
-
-               for (l = gutter->renderers, renderer_num = 0;
-                    l != NULL;
-                    l = l->next, renderer_num++)
-               {
-                       Renderer *renderer;
-                       GdkRectangle cell_area;
-                       gint width;
-                       gint xpad;
-                       gint ypad;
-
-                       renderer = l->data;
-                       width = g_array_index (renderer_widths, gint, renderer_num);
-
-                       if (!gtk_source_gutter_renderer_get_visible (renderer->renderer))
-                       {
-                               g_assert_cmpint (width, ==, 0);
-                               continue;
-                       }
-
-                       gtk_source_gutter_renderer_get_padding (renderer->renderer,
-                                                               &xpad,
-                                                               &ypad);
-
-                       background_area.width = width;
-
-                       cell_area.y = background_area.y + ypad;
-                       cell_area.height = background_area.height - 2 * ypad;
-
-                       cell_area.x = background_area.x + xpad;
-                       cell_area.width = background_area.width - 2 * xpad;
-
-                       if (renderer->prelit >= 0 &&
-                           cell_area.y <= renderer->prelit && renderer->prelit <= cell_area.y + 
cell_area.height)
-                       {
-                               state |= GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT;
-                       }
-
-                       gtk_source_gutter_renderer_query_data (renderer->renderer,
-                                                              &start,
-                                                              &end,
-                                                              state);
-
-                       cairo_save (cr);
-
-                       gdk_cairo_rectangle (cr, &background_area);
-
-                       cairo_clip (cr);
-
-                       /* Call render with correct area */
-                       gtk_source_gutter_renderer_draw (renderer->renderer,
-                                                        cr,
-                                                        &background_area,
-                                                        &cell_area,
-                                                        &start,
-                                                        &end,
-                                                        state);
-
-                       cairo_restore (cr);
-
-                       background_area.x += background_area.width;
-                       state &= ~GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT;
-               }
-
-               i++;
-               gtk_text_iter_forward_line (&start);
-       }
-}
-
-static void
-end_draw (GtkSourceGutter *gutter)
-{
-       GList *l;
-
-       for (l = gutter->renderers; l != NULL; l = l->next)
-       {
-               Renderer *renderer = l->data;
-
-               if (gtk_source_gutter_renderer_get_visible (renderer->renderer))
-               {
-                       gtk_source_gutter_renderer_end (renderer->renderer);
-               }
+               _gtk_source_gutter_renderer_end (renderer->renderer);
        }
 }
 
-void
-_gtk_source_gutter_draw (GtkSourceGutter *gutter,
-                         GtkSourceView   *view,
-                         cairo_t         *cr)
-{
-       GdkRectangle clip;
-       GtkTextView *text_view;
-       gint first_y_window_coord;
-       gint last_y_window_coord;
-       gint first_y_buffer_coord;
-       gint last_y_buffer_coord;
-       GArray *renderer_widths;
-       LinesInfo *info;
-       GtkStyleContext *style_context;
-
-       if (!get_clip_rectangle (gutter, view, cr, &clip))
-       {
-               return;
-       }
-
-       gutter->is_drawing = TRUE;
-
-       renderer_widths = g_array_new (FALSE, FALSE, sizeof (gint));
-       calculate_gutter_size (gutter, renderer_widths);
-
-       text_view = GTK_TEXT_VIEW (view);
-
-       first_y_window_coord = clip.y;
-       last_y_window_coord = first_y_window_coord + clip.height;
-
-       /* get the extents of the line printing */
-       gtk_text_view_window_to_buffer_coords (text_view,
-                                              gutter->window_type,
-                                              0,
-                                              first_y_window_coord,
-                                              NULL,
-                                              &first_y_buffer_coord);
-
-       gtk_text_view_window_to_buffer_coords (text_view,
-                                              gutter->window_type,
-                                              0,
-                                              last_y_window_coord,
-                                              NULL,
-                                              &last_y_buffer_coord);
-
-       info = get_lines_info (text_view,
-                              first_y_buffer_coord,
-                              last_y_buffer_coord);
-
-       style_context = gtk_widget_get_style_context (GTK_WIDGET (view));
-       gtk_style_context_save (style_context);
-       apply_style (gutter, view, style_context, cr);
-
-       begin_draw (gutter,
-                   text_view,
-                   renderer_widths,
-                   info,
-                   cr);
-
-       draw_cells (gutter,
-                   text_view,
-                   renderer_widths,
-                   info,
-                   cr);
-
-       /* Allow to call queue_redraw() in ::end. */
-       gutter->is_drawing = FALSE;
-
-       end_draw (gutter);
-
-       gtk_style_context_restore (style_context);
-
-       g_array_free (renderer_widths, TRUE);
-       lines_info_free (info);
-}
-
 static Renderer *
 renderer_at_x (GtkSourceGutter *gutter,
                gint             x,
-               gint            *start,
                gint            *width)
 {
-       GList *item;
-       gint s;
-       gint w;
-
-       update_gutter_size (gutter);
-
-       s = 0;
+       const GList *item;
 
        for (item = gutter->renderers; item; item = g_list_next (item))
        {
                Renderer *renderer = item->data;
-               gint xpad;
+               GtkAllocation alloc;
 
-               if (!gtk_source_gutter_renderer_get_visible (renderer->renderer))
-               {
-                       continue;
-               }
+               gtk_widget_get_allocation (GTK_WIDGET (renderer->renderer),
+                                          &alloc);
 
-               w = gtk_source_gutter_renderer_get_size (renderer->renderer);
-
-               gtk_source_gutter_renderer_get_padding (renderer->renderer,
-                                                       &xpad,
-                                                       NULL);
-
-               s += xpad;
-
-               if (w > 0 && x >= s && x < s + w)
+               if (x >= alloc.x && x <= alloc.x + alloc.width)
                {
-                       if (width)
-                       {
-                               *width = w;
-                       }
-
-                       if (start)
-                       {
-                               *start = s;
-                       }
-
                        return renderer;
                }
-
-               s += w + xpad;
        }
 
        return NULL;
@@ -1254,21 +927,18 @@ get_renderer_rect (GtkSourceGutter *gutter,
                    Renderer        *renderer,
                    GtkTextIter     *iter,
                    gint             line,
-                   GdkRectangle    *rectangle,
-                   gint             start)
+                   GdkRectangle    *rectangle)
 {
        gint y;
        gint ypad;
 
-       rectangle->x = start;
+       gtk_widget_get_allocation (GTK_WIDGET (renderer->renderer), rectangle);
 
        gtk_text_view_get_line_yrange (GTK_TEXT_VIEW (gutter->view),
                                       iter,
                                       &y,
                                       &rectangle->height);
 
-       rectangle->width = gtk_source_gutter_renderer_get_size (renderer->renderer);
-
        gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (gutter->view),
                                               gutter->window_type,
                                               0,
@@ -1276,9 +946,7 @@ get_renderer_rect (GtkSourceGutter *gutter,
                                               NULL,
                                               &rectangle->y);
 
-       gtk_source_gutter_renderer_get_padding (renderer->renderer,
-                                               NULL,
-                                               &ypad);
+       ypad = gtk_source_gutter_renderer_get_ypad (renderer->renderer);
 
        rectangle->y += ypad;
        rectangle->height -= 2 * ypad;
@@ -1287,27 +955,25 @@ get_renderer_rect (GtkSourceGutter *gutter,
 static gboolean
 renderer_query_activatable (GtkSourceGutter *gutter,
                             Renderer        *renderer,
-                            GdkEvent        *event,
-                            gint             x,
-                            gint             y,
+                            gdouble          x,
+                            gdouble          y,
                             GtkTextIter     *line_iter,
-                            GdkRectangle    *rect,
-                            gint             start)
+                            GdkRectangle    *rect)
 {
        gint y_buf;
        gint yline;
        GtkTextIter iter;
-       GdkRectangle r;
+       GdkRectangle r = {0};
 
-       if (!renderer)
+       if (renderer == NULL)
        {
                return FALSE;
        }
 
        gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (gutter->view),
-                                              gutter->window_type,
-                                              x,
-                                              y,
+                                              GTK_TEXT_WINDOW_WIDGET,
+                                              (gint)x,
+                                              (gint)y,
                                               NULL,
                                               &y_buf);
 
@@ -1321,7 +987,7 @@ renderer_query_activatable (GtkSourceGutter *gutter,
                return FALSE;
        }
 
-       get_renderer_rect (gutter, renderer, &iter, yline, &r, start);
+       get_renderer_rect (gutter, renderer, &iter, yline, &r);
 
        if (line_iter)
        {
@@ -1338,259 +1004,81 @@ renderer_query_activatable (GtkSourceGutter *gutter,
                return FALSE;
        }
 
-       return gtk_source_gutter_renderer_query_activatable (renderer->renderer,
-                                                            &iter,
-                                                            &r,
-                                                            event);
+       return gtk_source_gutter_renderer_query_activatable (renderer->renderer, &iter, &r);
 }
 
-static gboolean
-redraw_for_window (GtkSourceGutter *gutter,
-                   GdkEvent        *event,
-                   gboolean         act_on_window,
-                   gint             x,
-                   gint             y)
-{
-       Renderer *at_x = NULL;
-       gint start = 0;
-       GList *item;
-       gboolean redraw;
-
-       if (event->any.window != get_window (gutter) && act_on_window)
-       {
-               return FALSE;
-       }
-
-       if (act_on_window)
-       {
-               at_x = renderer_at_x (gutter, x, &start, NULL);
-       }
-
-       redraw = FALSE;
-
-       for (item = gutter->renderers; item; item = g_list_next (item))
-       {
-               Renderer *renderer = item->data;
-               gint prelit = renderer->prelit;
-
-               if (!gtk_source_gutter_renderer_get_visible (renderer->renderer))
-               {
-                       renderer->prelit = -1;
-               }
-               else
-               {
-                       if (renderer != at_x || !act_on_window)
-                       {
-                               renderer->prelit = -1;
-                       }
-                       else if (renderer_query_activatable (gutter,
-                                                            renderer,
-                                                            event,
-                                                            x,
-                                                            y,
-                                                            NULL,
-                                                            NULL,
-                                                            start))
-                       {
-                               renderer->prelit = y;
-                       }
-                       else
-                       {
-                               renderer->prelit = -1;
-                       }
-               }
-
-               redraw |= (renderer->prelit != prelit);
-       }
-
-       if (redraw)
-       {
-               do_redraw (gutter);
-       }
-
-       return FALSE;
-}
-
-static gboolean
-on_view_motion_notify_event (GtkSourceView   *view,
-                             GdkEventMotion  *event,
-                             GtkSourceGutter *gutter)
-{
-       return redraw_for_window (gutter,
-                                 (GdkEvent *)event,
-                                 TRUE,
-                                 (gint)event->x,
-                                 (gint)event->y);
-}
-
-static gboolean
-on_view_enter_notify_event (GtkSourceView    *view,
-                            GdkEventCrossing *event,
-                            GtkSourceGutter  *gutter)
-{
-       return redraw_for_window (gutter,
-                                 (GdkEvent *)event,
-                                 TRUE,
-                                 (gint)event->x,
-                                 (gint)event->y);
-}
-
-static gboolean
-on_view_leave_notify_event (GtkSourceView    *view,
-                            GdkEventCrossing *event,
-                            GtkSourceGutter  *gutter)
-{
-       return redraw_for_window (gutter,
-                                 (GdkEvent *)event,
-                                 FALSE,
-                                 (gint)event->x,
-                                 (gint)event->y);
-}
-
-static gboolean
-on_view_button_press_event (GtkSourceView   *view,
-                            GdkEventButton  *event,
-                            GtkSourceGutter *gutter)
+static void
+on_gutter_pressed_cb (GtkSourceGutter *gutter,
+                      gint             n_presses,
+                      gdouble          x,
+                      gdouble          y,
+                      GtkGestureClick *click)
 {
+       const GdkEvent *last_event;
        Renderer *renderer;
        GtkTextIter line_iter;
-       gint start = -1;
        GdkRectangle rect;
+       GdkModifierType state;
+       guint button;
 
-       if (event->window != get_window (gutter))
-       {
-               return FALSE;
-       }
+       g_assert (GTK_SOURCE_IS_GUTTER (gutter));
+       g_assert (GTK_IS_GESTURE_CLICK (click));
+
+       last_event = gtk_gesture_get_last_event (GTK_GESTURE (click), NULL);
 
-       if (event->type != GDK_BUTTON_PRESS)
+       if (last_event == NULL ||
+           !gdk_event_get_state (last_event, &state) ||
+           !gdk_event_get_button (last_event, &button))
        {
-               return FALSE;
+               return;
        }
 
        /* Check cell renderer */
-       renderer = renderer_at_x (gutter, event->x, &start, NULL);
+       renderer = renderer_at_x (gutter, x, NULL);
 
        if (renderer_query_activatable (gutter,
                                        renderer,
-                                       (GdkEvent *)event,
-                                       (gint)event->x,
-                                       (gint)event->y,
+                                       x,
+                                       y,
                                        &line_iter,
-                                       &rect,
-                                       start))
+                                       &rect))
        {
                gtk_source_gutter_renderer_activate (renderer->renderer,
                                                     &line_iter,
                                                     &rect,
-                                                    (GdkEvent *)event);
+                                                    button,
+                                                    state,
+                                                    n_presses);
 
                do_redraw (gutter);
 
-               return TRUE;
+               gtk_gesture_set_state (GTK_GESTURE (click),
+                                      GTK_EVENT_SEQUENCE_CLAIMED);
        }
-
-       return FALSE;
-}
-
-static gboolean
-on_view_query_tooltip (GtkSourceView   *view,
-                       gint             x,
-                       gint             y,
-                       gboolean         keyboard_mode,
-                       GtkTooltip      *tooltip,
-                       GtkSourceGutter *gutter)
-{
-       GtkTextView *text_view = GTK_TEXT_VIEW (view);
-       Renderer *renderer;
-       gint start = 0;
-       gint width = 0;
-       gint y_buf;
-       gint yline;
-       GtkTextIter line_iter;
-       GdkRectangle rect;
-
-       if (keyboard_mode)
-       {
-               return FALSE;
-       }
-
-       /* Check cell renderer */
-       renderer = renderer_at_x (gutter, x, &start, &width);
-
-       if (!renderer)
-       {
-               return FALSE;
-       }
-
-       gtk_text_view_window_to_buffer_coords (text_view,
-                                              gutter->window_type,
-                                              x, y,
-                                              NULL, &y_buf);
-
-       gtk_text_view_get_line_at_y (GTK_TEXT_VIEW (view),
-                                    &line_iter,
-                                    y_buf,
-                                    &yline);
-
-       if (yline > y_buf)
-       {
-               return FALSE;
-       }
-
-       get_renderer_rect (gutter,
-                          renderer,
-                          &line_iter,
-                          yline,
-                          &rect,
-                          start);
-
-       return gtk_source_gutter_renderer_query_tooltip (renderer->renderer,
-                                                        &line_iter,
-                                                        &rect,
-                                                        x,
-                                                        y,
-                                                        tooltip);
 }
 
 static void
 on_view_style_updated (GtkSourceView   *view,
                        GtkSourceGutter *gutter)
 {
-       gtk_source_gutter_queue_draw (gutter);
+       do_redraw (gutter);
 }
 
-/**
- * gtk_source_gutter_get_renderer_at_pos:
- * @gutter: A #GtkSourceGutter.
- * @x: The x position to get identified.
- * @y: The y position to get identified.
- *
- * Finds the #GtkSourceGutterRenderer at (x, y).
- *
- * Returns: (nullable) (transfer none): the renderer at (x, y) or %NULL.
- */
-/* TODO: better document this function. The (x,y) position is different from
- * the position passed to gtk_source_gutter_insert() and
- * gtk_source_gutter_reorder(). The (x,y) coordinate can come from a click
- * event, for example? Is the (x,y) a coordinate of the Gutter's GdkWindow?
- * Where is the (0,0)? And so on.
- * Also, this function doesn't seem to be used.
- */
-GtkSourceGutterRenderer *
-gtk_source_gutter_get_renderer_at_pos (GtkSourceGutter *gutter,
-                                       gint             x,
-                                       gint             y)
+GtkSourceGutterLines *
+_gtk_source_gutter_get_lines (GtkSourceGutter *gutter)
 {
-       Renderer *renderer;
-
        g_return_val_if_fail (GTK_SOURCE_IS_GUTTER (gutter), NULL);
 
-       renderer = renderer_at_x (gutter, x, NULL, NULL);
+       return gutter->lines;
+}
 
-       if (renderer == NULL)
+void
+_gtk_source_gutter_queue_draw (GtkSourceGutter *gutter)
+{
+       for (const GList *iter = gutter->renderers; iter; iter = iter->next)
        {
-               return NULL;
-       }
+               Renderer *renderer = iter->data;
 
-       return renderer->renderer;
+               gtk_widget_queue_allocate (GTK_WIDGET (renderer->renderer));
+       }
 }
diff --git a/gtksourceview/gtksourcegutter.h b/gtksourceview/gtksourcegutter.h
index 3fdf5b44..d25a1769 100644
--- a/gtksourceview/gtksourcegutter.h
+++ b/gtksourceview/gtksourcegutter.h
@@ -33,28 +33,17 @@ G_BEGIN_DECLS
 #define GTK_SOURCE_TYPE_GUTTER (gtk_source_gutter_get_type())
 
 GTK_SOURCE_AVAILABLE_IN_ALL
-G_DECLARE_FINAL_TYPE (GtkSourceGutter, gtk_source_gutter, GTK_SOURCE, GUTTER, GObject)
+G_DECLARE_FINAL_TYPE (GtkSourceGutter, gtk_source_gutter, GTK_SOURCE, GUTTER, GtkContainer)
 
 GTK_SOURCE_AVAILABLE_IN_3_24
-GtkSourceView           *gtk_source_gutter_get_view            (GtkSourceGutter         *gutter);
-GTK_SOURCE_AVAILABLE_IN_3_24
-GtkTextWindowType        gtk_source_gutter_get_window_type     (GtkSourceGutter         *gutter);
-GTK_SOURCE_AVAILABLE_IN_ALL
-gboolean                 gtk_source_gutter_insert              (GtkSourceGutter         *gutter,
-                                                                GtkSourceGutterRenderer *renderer,
-                                                                gint                     position);
-GTK_SOURCE_AVAILABLE_IN_ALL
-void                     gtk_source_gutter_reorder             (GtkSourceGutter         *gutter,
-                                                                GtkSourceGutterRenderer *renderer,
-                                                                gint                     position);
-GTK_SOURCE_AVAILABLE_IN_ALL
-void                     gtk_source_gutter_remove              (GtkSourceGutter         *gutter,
-                                                                GtkSourceGutterRenderer *renderer);
+GtkSourceView     *gtk_source_gutter_get_view        (GtkSourceGutter         *gutter);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                     gtk_source_gutter_queue_draw          (GtkSourceGutter         *gutter);
+gboolean           gtk_source_gutter_insert          (GtkSourceGutter         *gutter,
+                                                      GtkSourceGutterRenderer *renderer,
+                                                      gint                     position);
 GTK_SOURCE_AVAILABLE_IN_ALL
-GtkSourceGutterRenderer *gtk_source_gutter_get_renderer_at_pos (GtkSourceGutter         *gutter,
-                                                                gint                     x,
-                                                                gint                     y);
+void               gtk_source_gutter_reorder         (GtkSourceGutter         *gutter,
+                                                      GtkSourceGutterRenderer *renderer,
+                                                      gint                     position);
 
 G_END_DECLS
diff --git a/gtksourceview/gtksourcegutterrenderer-private.h b/gtksourceview/gtksourcegutterrenderer-private.h
index 790fa6df..44f085a6 100644
--- a/gtksourceview/gtksourcegutterrenderer-private.h
+++ b/gtksourceview/gtksourcegutterrenderer-private.h
@@ -21,13 +21,22 @@
 #pragma once
 
 #include <gtk/gtk.h>
+
 #include "gtksourcetypes.h"
 
 G_BEGIN_DECLS
 
 G_GNUC_INTERNAL
-void _gtk_source_gutter_renderer_set_view (GtkSourceGutterRenderer *renderer,
-                                           GtkTextView             *view,
-                                           GtkTextWindowType        window_type);
+void _gtk_source_gutter_renderer_set_view   (GtkSourceGutterRenderer *renderer,
+                                             GtkSourceView           *view);
+G_GNUC_INTERNAL
+void _gtk_source_gutter_renderer_begin      (GtkSourceGutterRenderer *renderer,
+                                             GtkSourceGutterLines    *lines);
+G_GNUC_INTERNAL
+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 bcc6e5dc..6cb113a0 100644
--- a/gtksourceview/gtksourcegutterrenderer.c
+++ b/gtksourceview/gtksourcegutterrenderer.c
@@ -20,8 +20,12 @@
 
 #include "config.h"
 
+#include "gtksourcebuffer.h"
+#include "gtksourcegutter.h"
+#include "gtksourcegutter-private.h"
 #include "gtksourcegutterrenderer.h"
 #include "gtksourcegutterrenderer-private.h"
+#include "gtksourcegutterlines.h"
 #include "gtksourcestylescheme.h"
 #include "gtksourceview.h"
 #include "gtksource-enumtypes.h"
@@ -39,9 +43,11 @@
  * this case, #GtkSourceGutterRendererAlignmentMode controls the alignment of
  * the cell.
  *
- * The gutter renderer must announce its #GtkSourceGutterRenderer:size. The
- * height is determined by the text view height. The width must be determined by
- * the gutter renderer. The width generally takes into account the entire text
+ * The gutter renderer is a #GtkWidget and is measured using the normal widget
+ * measurement facilities. The width of the gutter will be determined by the
+ * measurements of the gutter renderers.
+ *
+ * The width of a gutter renderer generally takes into account the entire text
  * buffer. For instance, to display the line numbers, if the buffer contains 100
  * lines, the gutter renderer will always set its width such as three digits can
  * be printed, even if only the first 20 lines are shown. Another strategy is to
@@ -51,122 +57,84 @@
  * into account the text buffer to announce its width. It only depends on the
  * icons size displayed in the gutter column.
  *
- * An horizontal and vertical padding can be added with
- * gtk_source_gutter_renderer_set_padding().  The total width of a gutter
- * renderer is its size (#GtkSourceGutterRenderer:size) plus two times the
- * horizontal padding (#GtkSourceGutterRenderer:xpad).
- *
  * When the available size to render a cell is greater than the required size to
  * render the cell contents, the cell contents can be aligned horizontally and
  * vertically with gtk_source_gutter_renderer_set_alignment().
  *
- * The cells rendering occurs in three phases:
- * - begin: the gtk_source_gutter_renderer_begin() function is called when some
- *   cells need to be redrawn. It provides the associated region of the
- *   #GtkTextBuffer. The cells need to be redrawn when the #GtkTextView is
- *   scrolled, or when the state of the cells change (see
- *   #GtkSourceGutterRendererState).
- * - draw: gtk_source_gutter_renderer_draw() is called for each cell that needs
- *   to be drawn.
- * - end: finally, gtk_source_gutter_renderer_end() is called.
+ * The cells rendering occurs using gtk_widget_snapshot(). Implementations
+ * should use gtk_source_gutter_renderer_get_lines() to retrieve information
+ * about the lines to be rendered. To help with aligning content which takes
+ * into account the padding and alignment of a cell, implementations may call
+ * gtk_source_gutter_renderer_align_cell() for a given line number with the
+ * width and height measurement of the content they width to render.
  */
 
-enum
-{
-       ACTIVATE,
-       QUEUE_DRAW,
-       QUERY_TOOLTIP,
-       QUERY_DATA,
-       QUERY_ACTIVATABLE,
-       N_SIGNALS
-};
-
 typedef struct
 {
-       GtkTextView *view;
-       GtkTextBuffer *buffer;
-       GtkTextWindowType window_type;
-
-       gint xpad;
-       gint ypad;
+       GtkSourceGutter *gutter;
+       GtkSourceView *view;
+       GtkSourceBuffer *buffer;
+       GtkSourceGutterLines *lines;
 
        gfloat xalign;
        gfloat yalign;
 
-       gint size;
+       gint xpad;
+       gint ypad;
 
        GtkSourceGutterRendererAlignmentMode alignment_mode;
 
-       GdkRGBA background_color;
-
-       guint background_set : 1;
        guint visible : 1;
 } GtkSourceGutterRendererPrivate;
 
-static guint signals[N_SIGNALS];
-
-G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkSourceGutterRenderer, gtk_source_gutter_renderer, 
G_TYPE_INITIALLY_UNOWNED)
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkSourceGutterRenderer, gtk_source_gutter_renderer, GTK_TYPE_WIDGET)
 
 enum
 {
        PROP_0,
-       PROP_VISIBLE,
-       PROP_XPAD,
-       PROP_YPAD,
+       PROP_ALIGNMENT_MODE,
+       PROP_LINES,
+       PROP_VIEW,
        PROP_XALIGN,
+       PROP_XPAD,
        PROP_YALIGN,
-       PROP_VIEW,
-       PROP_ALIGNMENT_MODE,
-       PROP_WINDOW_TYPE,
-       PROP_SIZE,
-       PROP_BACKGROUND_RGBA,
-       PROP_BACKGROUND_SET
+       PROP_YPAD,
+       N_PROPS
 };
 
-static void
-set_buffer (GtkSourceGutterRenderer *renderer,
-            GtkTextBuffer           *buffer)
+enum
 {
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-
-       if (priv->buffer != NULL)
-       {
-               g_object_remove_weak_pointer (G_OBJECT (priv->buffer),
-                                             (gpointer) &priv->buffer);
-       }
-
-       if (buffer != NULL)
-       {
-               g_object_add_weak_pointer (G_OBJECT (buffer),
-                                          (gpointer) &priv->buffer);
-       }
+       ACTIVATE,
+       QUERY_ACTIVATABLE,
+       QUERY_DATA,
+       N_SIGNALS
+};
 
-       priv->buffer = buffer;
-}
+static GParamSpec *properties[N_PROPS];
+static guint       signals[N_SIGNALS];
 
 static void
-emit_buffer_changed (GtkTextView             *view,
+emit_buffer_changed (GtkSourceView           *view,
                      GtkSourceGutterRenderer *renderer)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-       GtkTextBuffer* buffer;
+       GtkSourceBuffer *buffer;
+       GtkSourceBuffer *old_buffer;
 
-       buffer = gtk_text_view_get_buffer (view);
+       old_buffer = priv->buffer;
+       buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
 
-       if (buffer != priv->buffer)
+       if (buffer == old_buffer)
        {
-               if (GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->change_buffer)
-               {
-                       GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->change_buffer (renderer,
-                                                                                       priv->buffer);
-               }
-
-               set_buffer (renderer, buffer);
+               return;
        }
+
+       g_set_weak_pointer (&priv->buffer, buffer);
+       GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->change_buffer (renderer, old_buffer);
 }
 
 static void
-on_buffer_changed (GtkTextView             *view,
+on_buffer_changed (GtkSourceView           *view,
                    GParamSpec              *spec,
                    GtkSourceGutterRenderer *renderer)
 {
@@ -174,19 +142,25 @@ on_buffer_changed (GtkTextView             *view,
 }
 
 static void
-renderer_change_view_impl (GtkSourceGutterRenderer *renderer,
-                           GtkTextView             *old_view)
+gtk_source_gutter_renderer_change_buffer (GtkSourceGutterRenderer *renderer,
+                                          GtkSourceBuffer         *buffer)
+{
+}
+
+static void
+gtk_source_gutter_renderer_change_view (GtkSourceGutterRenderer *renderer,
+                                        GtkSourceView           *old_view)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       if (old_view)
+       if (old_view != NULL)
        {
                g_signal_handlers_disconnect_by_func (old_view,
                                                      G_CALLBACK (on_buffer_changed),
                                                      renderer);
        }
 
-       if (priv->view)
+       if (priv->view != NULL)
        {
                emit_buffer_changed (priv->view, renderer);
 
@@ -198,196 +172,98 @@ renderer_change_view_impl (GtkSourceGutterRenderer *renderer,
 }
 
 static void
-gtk_source_gutter_renderer_dispose (GObject *object)
+gtk_source_gutter_renderer_snapshot (GtkWidget   *widget,
+                                     GtkSnapshot *snapshot)
 {
-       GtkSourceGutterRenderer *renderer = GTK_SOURCE_GUTTER_RENDERER (object);
+       GtkSourceGutterRenderer *renderer = GTK_SOURCE_GUTTER_RENDERER (widget);
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+       GtkSourceGutterRendererClass *klass = GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (widget);
+       GtkSourceGutterRendererAlignmentMode mode = priv->alignment_mode;
+       GtkSourceGutterLines *lines = priv->lines;
+       guint first;
+       guint last;
+       guint line;
+       gint y;
+       gint h;
 
-       set_buffer (renderer, NULL);
-
-       if (priv->view)
+       if (lines == NULL || klass->snapshot_line == NULL)
        {
-               _gtk_source_gutter_renderer_set_view (renderer,
-                                                     NULL,
-                                                     GTK_TEXT_WINDOW_PRIVATE);
+               return;
        }
 
-       G_OBJECT_CLASS (gtk_source_gutter_renderer_parent_class)->dispose (object);
-}
+       first = gtk_source_gutter_lines_get_first (lines);
+       last = gtk_source_gutter_lines_get_last (lines);
 
-static void
-set_visible (GtkSourceGutterRenderer *renderer,
-             gboolean                 visible)
-{
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-
-       visible = visible != FALSE;
-
-       if (priv->visible != visible)
+       for (line = first; line <= last; line++)
        {
-               priv->visible = visible;
-               g_object_notify (G_OBJECT (renderer), "visible");
+               gtk_source_gutter_lines_get_line_yrange (lines, line, mode, &y, &h);
 
-               gtk_source_gutter_renderer_queue_draw (renderer);
+               klass->query_data (renderer, lines, line);
+               klass->snapshot_line (renderer, snapshot, lines, line);
        }
 }
 
-static gboolean
-set_padding (GtkSourceGutterRenderer *renderer,
-             gint                    *field,
-             gint                     padding,
-             const gchar             *name)
-{
-       if (*field == padding || padding < 0)
-       {
-               return FALSE;
-       }
-
-       *field = padding;
-       g_object_notify (G_OBJECT (renderer), name);
-
-       return TRUE;
-}
-
-static gboolean
-set_xpad (GtkSourceGutterRenderer *renderer,
-          gint                     xpad)
-{
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-
-       return set_padding (renderer,
-                           &priv->xpad,
-                           xpad,
-                           "xpad");
-}
-
-static gboolean
-set_ypad (GtkSourceGutterRenderer *renderer,
-          gint                     ypad)
+static void
+gtk_source_gutter_renderer_dispose (GObject *object)
 {
+       GtkSourceGutterRenderer *renderer = GTK_SOURCE_GUTTER_RENDERER (object);
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       return set_padding (renderer,
-                           &priv->ypad,
-                           ypad,
-                           "ypad");
-}
-
-static gboolean
-set_alignment (GtkSourceGutterRenderer *renderer,
-               gfloat                  *field,
-               gfloat                   align,
-               const gchar             *name,
-               gboolean                 emit)
-{
-       if (*field == align || align < 0)
-       {
-               return FALSE;
-       }
-
-       *field = align;
-       g_object_notify (G_OBJECT (renderer), name);
+       g_clear_weak_pointer (&priv->buffer);
 
-       if (emit)
+       if (priv->view != NULL)
        {
-               gtk_source_gutter_renderer_queue_draw (renderer);
+               _gtk_source_gutter_renderer_set_view (renderer, NULL);
        }
 
-       return TRUE;
+       G_OBJECT_CLASS (gtk_source_gutter_renderer_parent_class)->dispose (object);
 }
 
-static gboolean
-set_xalign (GtkSourceGutterRenderer *renderer,
-            gfloat                   xalign,
-            gboolean                 emit)
+static void
+gtk_source_gutter_renderer_root (GtkWidget *widget)
 {
+       GtkSourceGutterRenderer *renderer = GTK_SOURCE_GUTTER_RENDERER (widget);
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+       GtkWidget *gutter;
 
-       return set_alignment (renderer,
-                             &priv->xalign,
-                             xalign,
-                             "xalign",
-                             emit);
-}
+       GTK_WIDGET_CLASS (gtk_source_gutter_renderer_parent_class)->root (widget);
 
-static gboolean
-set_yalign (GtkSourceGutterRenderer *renderer,
-            gfloat                   yalign,
-            gboolean                 emit)
-{
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+       gutter = gtk_widget_get_ancestor (widget, GTK_SOURCE_TYPE_GUTTER);
 
-       return set_alignment (renderer,
-                             &priv->yalign,
-                             yalign,
-                             "yalign",
-                             emit);
+       if (GTK_SOURCE_IS_GUTTER (gutter))
+       {
+               priv->gutter = GTK_SOURCE_GUTTER (gutter);
+       }
 }
 
 static void
-set_alignment_mode (GtkSourceGutterRenderer              *renderer,
-                    GtkSourceGutterRendererAlignmentMode  mode)
+gtk_source_gutter_renderer_unroot (GtkWidget *widget)
 {
+       GtkSourceGutterRenderer *renderer = GTK_SOURCE_GUTTER_RENDERER (widget);
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       if (priv->alignment_mode == mode)
-       {
-               return;
-       }
-
-       priv->alignment_mode = mode;
-       g_object_notify (G_OBJECT (renderer), "alignment-mode");
+       priv->gutter = NULL;
 
-       gtk_source_gutter_renderer_queue_draw (renderer);
+       GTK_WIDGET_CLASS (gtk_source_gutter_renderer_parent_class)->unroot (widget);
 }
 
 static void
-set_size (GtkSourceGutterRenderer *renderer,
-          gint                     value)
+gtk_source_gutter_renderer_real_begin (GtkSourceGutterRenderer *renderer,
+                                       GtkSourceGutterLines    *lines)
 {
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-
-       if (priv->size == value)
-       {
-               return;
-       }
-
-       priv->size = value;
-       g_object_notify (G_OBJECT (renderer), "size");
 }
 
 static void
-set_background_color_set (GtkSourceGutterRenderer *renderer,
-                          gboolean                 isset)
+gtk_source_gutter_renderer_real_end (GtkSourceGutterRenderer *renderer)
 {
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-
-       isset = (isset != FALSE);
-
-       if (isset != priv->background_set)
-       {
-               priv->background_set = isset;
-               gtk_source_gutter_renderer_queue_draw (renderer);
-       }
 }
 
 static void
-set_background_color (GtkSourceGutterRenderer *renderer,
-                      const GdkRGBA          *color)
+gtk_source_gutter_renderer_query_data (GtkSourceGutterRenderer *renderer,
+                                       GtkSourceGutterLines    *lines,
+                                       guint                    line)
 {
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-
-       if (!color)
-       {
-               set_background_color_set (renderer, FALSE);
-       }
-       else
-       {
-               priv->background_color = *color;
-               priv->background_set = TRUE;
-
-               gtk_source_gutter_renderer_queue_draw (renderer);
-       }
+       g_signal_emit (renderer, signals[QUERY_DATA], 0, lines, line);
 }
 
 static void
@@ -397,45 +273,29 @@ gtk_source_gutter_renderer_set_property (GObject      *object,
                                          GParamSpec   *pspec)
 {
        GtkSourceGutterRenderer *self = GTK_SOURCE_GUTTER_RENDERER (object);
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (self);
 
        switch (prop_id)
        {
-               case PROP_VISIBLE:
-                       set_visible (self, g_value_get_boolean (value));
-                       break;
                case PROP_XPAD:
-                       set_xpad (self, g_value_get_int (value));
+                       gtk_source_gutter_renderer_set_xpad (self, g_value_get_int (value));
                        break;
+
                case PROP_YPAD:
-                       set_ypad (self, g_value_get_int (value));
+                       gtk_source_gutter_renderer_set_ypad (self, g_value_get_int (value));
                        break;
+
                case PROP_XALIGN:
-                       set_xalign (self, g_value_get_float (value), TRUE);
+                       gtk_source_gutter_renderer_set_xalign (self, g_value_get_float (value));
                        break;
+
                case PROP_YALIGN:
-                       set_yalign (self, g_value_get_float (value), TRUE);
+                       gtk_source_gutter_renderer_set_yalign (self, g_value_get_float (value));
                        break;
+
                case PROP_ALIGNMENT_MODE:
-                       set_alignment_mode (self, g_value_get_enum (value));
-                       break;
-               case PROP_VIEW:
-                       priv->view = g_value_get_object (value);
-                       break;
-               case PROP_WINDOW_TYPE:
-                       priv->window_type = g_value_get_enum (value);
-                       break;
-               case PROP_SIZE:
-                       set_size (self, g_value_get_int (value));
-                       break;
-               case PROP_BACKGROUND_RGBA:
-                       set_background_color (self,
-                                             g_value_get_boxed (value));
-                       break;
-               case PROP_BACKGROUND_SET:
-                       set_background_color_set (self,
-                                                 g_value_get_boolean (value));
+                       gtk_source_gutter_renderer_set_alignment_mode (self, g_value_get_enum (value));
                        break;
+
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -453,142 +313,101 @@ gtk_source_gutter_renderer_get_property (GObject    *object,
 
        switch (prop_id)
        {
-               case PROP_VISIBLE:
-                       g_value_set_boolean (value, priv->visible);
-                       break;
-               case PROP_XPAD:
-                       g_value_set_int (value, priv->xpad);
-                       break;
-               case PROP_YPAD:
-                       g_value_set_int (value, priv->ypad);
+               case PROP_LINES:
+                       g_value_set_object (value, priv->lines);
                        break;
+
                case PROP_XALIGN:
                        g_value_set_float (value, priv->xalign);
                        break;
+
+               case PROP_XPAD:
+                       g_value_set_int (value, priv->xpad);
+                       break;
+
                case PROP_YALIGN:
                        g_value_set_float (value, priv->yalign);
                        break;
+
+               case PROP_YPAD:
+                       g_value_set_int (value, priv->ypad);
+                       break;
+
                case PROP_VIEW:
                        g_value_set_object (value, priv->view);
                        break;
+
                case PROP_ALIGNMENT_MODE:
                        g_value_set_enum (value, priv->alignment_mode);
                        break;
-               case PROP_WINDOW_TYPE:
-                       g_value_set_enum (value, priv->window_type);
-                       break;
-               case PROP_SIZE:
-                       g_value_set_int (value, priv->size);
-                       break;
-               case PROP_BACKGROUND_RGBA:
-                       g_value_set_boxed (value, &priv->background_color);
-                       break;
-               case PROP_BACKGROUND_SET:
-                       g_value_set_boolean (value, priv->background_set);
-                       break;
+
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
        }
 }
 
-static void
-renderer_draw_impl (GtkSourceGutterRenderer      *renderer,
-                    cairo_t                      *cr,
-                    GdkRectangle                 *background_area,
-                    GdkRectangle                 *cell_area,
-                    GtkTextIter                  *start,
-                    GtkTextIter                  *end,
-                    GtkSourceGutterRendererState  state)
-{
-       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
-
-       if (priv->background_set)
-       {
-               cairo_save (cr);
-               gdk_cairo_rectangle (cr, background_area);
-               gdk_cairo_set_source_rgba (cr, &priv->background_color);
-               cairo_fill (cr);
-               cairo_restore (cr);
-       }
-       else if ((state & GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR) != 0 &&
-                GTK_SOURCE_IS_VIEW (priv->view) &&
-                gtk_source_view_get_highlight_current_line (GTK_SOURCE_VIEW (priv->view)))
-       {
-               GtkStyleContext *context;
-
-               context = gtk_widget_get_style_context (GTK_WIDGET (priv->view));
-
-               gtk_style_context_save (context);
-               gtk_style_context_add_class (context, "current-line-number");
-
-               gtk_render_background (context,
-                                      cr,
-                                      background_area->x,
-                                      background_area->y,
-                                      background_area->width,
-                                      background_area->height);
-
-               gtk_style_context_restore (context);
-       }
-}
-
 static void
 gtk_source_gutter_renderer_class_init (GtkSourceGutterRendererClass *klass)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
        object_class->dispose = gtk_source_gutter_renderer_dispose;
-
        object_class->get_property = gtk_source_gutter_renderer_get_property;
        object_class->set_property = gtk_source_gutter_renderer_set_property;
 
-       klass->draw = renderer_draw_impl;
-       klass->change_view = renderer_change_view_impl;
+       widget_class->root = gtk_source_gutter_renderer_root;
+       widget_class->unroot = gtk_source_gutter_renderer_unroot;
+       widget_class->snapshot = gtk_source_gutter_renderer_snapshot;
+
+       klass->begin = gtk_source_gutter_renderer_real_begin;
+       klass->end = gtk_source_gutter_renderer_real_end;
+        klass->change_buffer = gtk_source_gutter_renderer_change_buffer;
+       klass->change_view = gtk_source_gutter_renderer_change_view;
+       klass->query_data = gtk_source_gutter_renderer_query_data;
 
        /**
-        * GtkSourceGutterRenderer:visible:
+        * GtkSourceGutterRenderer:lines:
         *
-        * The visibility of the renderer.
-        *
-        **/
-       g_object_class_install_property (object_class,
-                                        PROP_VISIBLE,
-                                        g_param_spec_boolean ("visible",
-                                                              "Visible",
-                                                              "Visible",
-                                                              TRUE,
-                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        * The "lines" property contains information about the lines to be
+        * rendered. It should be used by #GtkSourceGutterRenderer
+        * implementations from gtk_widget_snapshot().
+        */
+       properties[PROP_LINES] =
+               g_param_spec_object ("lines",
+                                    "Lines",
+                                    "Information about the lines to render",
+                                    GTK_SOURCE_TYPE_GUTTER_LINES,
+                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
        /**
         * GtkSourceGutterRenderer:xpad:
         *
         * The left and right padding of the renderer.
         */
-       g_object_class_install_property (object_class,
-                                        PROP_XPAD,
-                                        g_param_spec_int ("xpad",
-                                                          "X Padding",
-                                                          "The x-padding",
-                                                          -1,
-                                                          G_MAXINT,
-                                                          0,
-                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+       properties[PROP_XPAD] =
+               g_param_spec_int ("xpad",
+                                 "X Padding",
+                                 "The x-padding",
+                                 0,
+                                 G_MAXINT,
+                                 0,
+                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
        /**
         * GtkSourceGutterRenderer:ypad:
         *
         * The top and bottom padding of the renderer.
         */
-       g_object_class_install_property (object_class,
-                                        PROP_YPAD,
-                                        g_param_spec_int ("ypad",
-                                                          "Y Padding",
-                                                          "The y-padding",
-                                                          -1,
-                                                          G_MAXINT,
-                                                          0,
-                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+       properties[PROP_YPAD] =
+               g_param_spec_int ("ypad",
+                                 "Y Padding",
+                                 "The y-padding",
+                                 0,
+                                 G_MAXINT,
+                                 0,
+                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
        /**
         * GtkSourceGutterRenderer:xalign:
@@ -597,15 +416,14 @@ gtk_source_gutter_renderer_class_init (GtkSourceGutterRendererClass *klass)
         * alignment. 1 for a right alignment. And 0.5 for centering the cells.
         * A value lower than 0 doesn't modify the alignment.
         */
-       g_object_class_install_property (object_class,
-                                        PROP_XALIGN,
-                                        g_param_spec_float ("xalign",
-                                                            "X Alignment",
-                                                            "The x-alignment",
-                                                            -1,
-                                                            1,
-                                                            0,
-                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+       properties[PROP_XALIGN] =
+               g_param_spec_float ("xalign",
+                                   "X Alignment",
+                                   "The x-alignment",
+                                   0.0,
+                                   1.0,
+                                   0.0,
+                                   G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
        /**
         * GtkSourceGutterRenderer:yalign:
@@ -614,124 +432,75 @@ gtk_source_gutter_renderer_class_init (GtkSourceGutterRendererClass *klass)
         * alignment. 1 for a bottom alignment. And 0.5 for centering the cells.
         * A value lower than 0 doesn't modify the alignment.
         */
-       g_object_class_install_property (object_class,
-                                        PROP_YALIGN,
-                                        g_param_spec_float ("yalign",
-                                                            "Y Alignment",
-                                                            "The y-alignment",
-                                                            -1,
-                                                            1,
-                                                            0,
-                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+       properties[PROP_YALIGN] =
+               g_param_spec_float ("yalign",
+                                   "Y Alignment",
+                                   "The y-alignment",
+                                   0.0,
+                                   1.0,
+                                   0.0,
+                                   G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
-       /**
-        * GtkSourceGutterRenderer::activate:
-        * @renderer: the #GtkSourceGutterRenderer who emits the signal
-        * @iter: a #GtkTextIter
-        * @area: a #GdkRectangle
-        * @event: the event that caused the activation
-        *
-        * The ::activate signal is emitted when the renderer is
-        * activated.
-        *
-        */
-       signals[ACTIVATE] =
-               g_signal_new ("activate",
-                             G_TYPE_FROM_CLASS (object_class),
-                             G_SIGNAL_RUN_LAST,
-                             G_STRUCT_OFFSET (GtkSourceGutterRendererClass, activate),
-                             NULL, NULL,
-                             _gtk_source_marshal_VOID__BOXED_BOXED_BOXED,
-                             G_TYPE_NONE,
-                             3,
-                             GTK_TYPE_TEXT_ITER,
-                             GDK_TYPE_RECTANGLE,
-                             GDK_TYPE_EVENT);
-       g_signal_set_va_marshaller (signals[ACTIVATE],
-                                   G_TYPE_FROM_CLASS (klass),
-                                   _gtk_source_marshal_VOID__BOXED_BOXED_BOXEDv);
 
        /**
-        * GtkSourceGutterRenderer::queue-draw:
-        * @renderer: the #GtkSourceGutterRenderer who emits the signal
+        * GtkSourceGutterRenderer:view:
         *
-        * The ::queue-draw signal is emitted when the renderer needs
-        * to be redrawn. Use gtk_source_gutter_renderer_queue_draw()
-        * to emit this signal from an implementation of the
-        * #GtkSourceGutterRenderer interface.
-        */
-       signals[QUEUE_DRAW] =
-               g_signal_new ("queue-draw",
-                             G_TYPE_FROM_CLASS (object_class),
-                             G_SIGNAL_RUN_LAST,
-                             G_STRUCT_OFFSET (GtkSourceGutterRendererClass, queue_draw),
-                             NULL, NULL,
-                             g_cclosure_marshal_VOID__VOID,
-                             G_TYPE_NONE, 0);
-       g_signal_set_va_marshaller (signals[QUEUE_DRAW],
-                                   G_TYPE_FROM_CLASS (klass),
-                                   g_cclosure_marshal_VOID__VOIDv);
+        * The view on which the renderer is placed.
+        **/
+       properties[PROP_VIEW] =
+               g_param_spec_object ("view",
+                                    "The View",
+                                    "The view",
+                                    GTK_TYPE_TEXT_VIEW,
+                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
        /**
-        * GtkSourceGutterRenderer::query-tooltip:
-        * @renderer: the #GtkSourceGutterRenderer who emits the signal
-        * @iter: a #GtkTextIter
-        * @area: a #GdkRectangle
-        * @x: the x position (in window coordinates)
-        * @y: the y position (in window coordinates)
-        * @tooltip: a #GtkTooltip
+        * GtkSourceGutterRenderer:alignment-mode:
         *
-        * The ::query-tooltip signal is emitted when the renderer can
-        * show a tooltip.
+        * The alignment mode of the renderer. This can be used to indicate
+        * that in the case a cell spans multiple lines (due to text wrapping)
+        * the alignment should work on either the full cell, the first line
+        * or the last line.
         *
-        */
-       signals[QUERY_TOOLTIP] =
-               g_signal_new ("query-tooltip",
-                             G_TYPE_FROM_CLASS (object_class),
-                             G_SIGNAL_RUN_LAST,
-                             G_STRUCT_OFFSET (GtkSourceGutterRendererClass, query_tooltip),
-                             g_signal_accumulator_true_handled,
-                             NULL,
-                             _gtk_source_marshal_BOOLEAN__BOXED_BOXED_INT_INT_OBJECT,
-                             G_TYPE_BOOLEAN,
-                             5,
-                             GTK_TYPE_TEXT_ITER,
-                             GDK_TYPE_RECTANGLE,
-                             G_TYPE_INT,
-                             G_TYPE_INT,
-                             GTK_TYPE_TOOLTIP);
-       g_signal_set_va_marshaller (signals[QUERY_TOOLTIP],
-                                   G_TYPE_FROM_CLASS (klass),
-                                   _gtk_source_marshal_BOOLEAN__BOXED_BOXED_INT_INT_OBJECTv);
+        **/
+       properties[PROP_ALIGNMENT_MODE] =
+               g_param_spec_enum ("alignment-mode",
+                                  "Alignment Mode",
+                                  "The alignment mode",
+                                  GTK_SOURCE_TYPE_GUTTER_RENDERER_ALIGNMENT_MODE,
+                                  GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL,
+                                  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+       g_object_class_install_properties (object_class, N_PROPS, properties);
 
        /**
-        * GtkSourceGutterRenderer::query-data:
+        * GtkSourceGutterRenderer::activate:
         * @renderer: the #GtkSourceGutterRenderer who emits the signal
-        * @start: a #GtkTextIter
-        * @end: a #GtkTextIter
-        * @state: the renderer state
-        *
-        * The ::query-data signal is emitted when the renderer needs
-        * to be filled with data just before a cell is drawn. This can
-        * be used by general renderer implementations to allow render
-        * data to be filled in externally.
+        * @iter: a #GtkTextIter
+        * @area: a #GdkRectangle
+        * @button: the button that was pressed
+        * @state: a #GdkModifierType of state
+        * @n_presses: the number of button presses
         *
+        * The ::activate signal is emitted when the renderer is activated.
         */
-       signals[QUERY_DATA] =
-               g_signal_new ("query-data",
-                             G_TYPE_FROM_CLASS (object_class),
+       signals[ACTIVATE] =
+               g_signal_new ("activate",
+                             G_TYPE_FROM_CLASS (klass),
                              G_SIGNAL_RUN_LAST,
-                             G_STRUCT_OFFSET (GtkSourceGutterRendererClass, query_data),
+                             G_STRUCT_OFFSET (GtkSourceGutterRendererClass, activate),
                              NULL, NULL,
-                             _gtk_source_marshal_VOID__BOXED_BOXED_FLAGS,
+                             _gtk_source_marshal_VOID__BOXED_BOXED_UINT_FLAGS_INT,
                              G_TYPE_NONE,
-                             3,
-                             GTK_TYPE_TEXT_ITER,
-                             GTK_TYPE_TEXT_ITER,
-                             GTK_SOURCE_TYPE_GUTTER_RENDERER_STATE);
-       g_signal_set_va_marshaller (signals[QUERY_DATA],
+                             5,
+                             GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
+                             GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE,
+                             G_TYPE_UINT,
+                             GDK_TYPE_MODIFIER_TYPE,
+                             G_TYPE_INT);
+       g_signal_set_va_marshaller (signals[ACTIVATE],
                                    G_TYPE_FROM_CLASS (klass),
-                                   _gtk_source_marshal_VOID__BOXED_BOXED_FLAGSv);
+                                   _gtk_source_marshal_VOID__BOXED_BOXED_UINT_FLAGS_INTv);
 
        /**
         * GtkSourceGutterRenderer::query-activatable:
@@ -742,98 +511,39 @@ gtk_source_gutter_renderer_class_init (GtkSourceGutterRendererClass *klass)
         *
         * The ::query-activatable signal is emitted when the renderer
         * can possibly be activated.
-        *
         */
        signals[QUERY_ACTIVATABLE] =
                g_signal_new ("query-activatable",
-                             G_TYPE_FROM_CLASS (object_class),
+                             G_TYPE_FROM_CLASS (klass),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GtkSourceGutterRendererClass, query_activatable),
                              g_signal_accumulator_true_handled,
                              NULL,
-                             _gtk_source_marshal_BOOLEAN__BOXED_BOXED_BOXED,
+                             _gtk_source_marshal_BOOLEAN__BOXED_BOXED,
                              G_TYPE_BOOLEAN,
-                             3,
-                             GTK_TYPE_TEXT_ITER,
-                             GDK_TYPE_RECTANGLE,
-                             GDK_TYPE_EVENT);
+                             2,
+                             GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
+                             GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
        g_signal_set_va_marshaller (signals[QUERY_ACTIVATABLE],
                                    G_TYPE_FROM_CLASS (klass),
-                                   _gtk_source_marshal_BOOLEAN__BOXED_BOXED_BOXEDv);
+                                   _gtk_source_marshal_BOOLEAN__BOXED_BOXEDv);
 
-       /**
-        * GtkSourceGutterRenderer:view:
-        *
-        * The view on which the renderer is placed.
-        *
-        **/
-       g_object_class_install_property (object_class,
-                                        PROP_VIEW,
-                                        g_param_spec_object ("view",
-                                                             "The View",
-                                                             "The view",
-                                                             GTK_TYPE_TEXT_VIEW,
-                                                             G_PARAM_READABLE));
-
-       /**
-        * GtkSourceGutterRenderer:alignment-mode:
-        *
-        * The alignment mode of the renderer. This can be used to indicate
-        * that in the case a cell spans multiple lines (due to text wrapping)
-        * the alignment should work on either the full cell, the first line
-        * or the last line.
-        *
-        **/
-       g_object_class_install_property (object_class,
-                                        PROP_ALIGNMENT_MODE,
-                                        g_param_spec_enum ("alignment-mode",
-                                                           "Alignment Mode",
-                                                           "The alignment mode",
-                                                           GTK_SOURCE_TYPE_GUTTER_RENDERER_ALIGNMENT_MODE,
-                                                           GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL,
-                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+       signals[QUERY_DATA] =
+               g_signal_new ("query-data",
+                             G_TYPE_FROM_CLASS (klass),
+                             G_SIGNAL_RUN_LAST,
+                             0,
+                             NULL, NULL,
+                             _gtk_source_marshal_VOID__OBJECT_UINT,
+                             G_TYPE_NONE,
+                             2,
+                             G_TYPE_OBJECT,
+                             G_TYPE_UINT);
+       g_signal_set_va_marshaller (signals[QUERY_DATA],
+                                   G_TYPE_FROM_CLASS (klass),
+                                   _gtk_source_marshal_VOID__OBJECT_UINTv);
 
-       /**
-        * GtkSourceGutterRenderer:window-type:
-        *
-        * The window type of the view on which the renderer is placed (left,
-        * or right).
-        *
-        **/
-       g_object_class_install_property (object_class,
-                                        PROP_WINDOW_TYPE,
-                                        g_param_spec_enum ("window-type",
-                                                           "Window Type",
-                                                           "The window type",
-                                                           GTK_TYPE_TEXT_WINDOW_TYPE,
-                                                           GTK_TEXT_WINDOW_PRIVATE,
-                                                           G_PARAM_READABLE));
-
-       g_object_class_install_property (object_class,
-                                        PROP_SIZE,
-                                        g_param_spec_int ("size",
-                                                          "Size",
-                                                          "The size",
-                                                          0,
-                                                          G_MAXINT,
-                                                          0,
-                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-       g_object_class_install_property (object_class,
-                                        PROP_BACKGROUND_RGBA,
-                                        g_param_spec_boxed ("background-rgba",
-                                                            "Background Color",
-                                                            "The background color",
-                                                            GDK_TYPE_RGBA,
-                                                            G_PARAM_READWRITE));
-
-       g_object_class_install_property (object_class,
-                                        PROP_BACKGROUND_SET,
-                                        g_param_spec_boolean ("background-set",
-                                                              "Background Set",
-                                                              "Whether the background color is set",
-                                                              FALSE,
-                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+  gtk_widget_class_set_css_name (widget_class, "gutterrenderer");
 }
 
 static void
@@ -841,125 +551,13 @@ gtk_source_gutter_renderer_init (GtkSourceGutterRenderer *self)
 {
 }
 
-/**
- * gtk_source_gutter_renderer_begin:
- * @renderer: a #GtkSourceGutterRenderer
- * @cr: a #cairo_t
- * @background_area: a #GdkRectangle
- * @cell_area: a #GdkRectangle
- * @start: a #GtkTextIter
- * @end: a #GtkTextIter
- *
- * Called when drawing a region begins. The region to be drawn is indicated
- * by @start and @end. The purpose is to allow the implementation to precompute
- * some state before the draw method is called for each cell.
- */
-void
-gtk_source_gutter_renderer_begin (GtkSourceGutterRenderer *renderer,
-                                  cairo_t                 *cr,
-                                  GdkRectangle            *background_area,
-                                  GdkRectangle            *cell_area,
-                                  GtkTextIter             *start,
-                                  GtkTextIter             *end)
-{
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-       g_return_if_fail (cr != NULL);
-       g_return_if_fail (background_area != NULL);
-       g_return_if_fail (cell_area != NULL);
-       g_return_if_fail (start != NULL);
-       g_return_if_fail (end != NULL);
-
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (G_OBJECT_GET_CLASS (renderer))->begin)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (
-                       G_OBJECT_GET_CLASS (renderer))->begin (renderer,
-                                                              cr,
-                                                              background_area,
-                                                              cell_area,
-                                                              start,
-                                                              end);
-       }
-}
-
-/**
- * gtk_source_gutter_renderer_draw:
- * @renderer: a #GtkSourceGutterRenderer
- * @cr: the cairo render context
- * @background_area: a #GdkRectangle indicating the total area to be drawn
- * @cell_area: a #GdkRectangle indicating the area to draw content
- * @start: a #GtkTextIter
- * @end: a #GtkTextIter
- * @state: a #GtkSourceGutterRendererState
- *
- * Main renderering method. Implementations should implement this method to draw
- * onto the cairo context. The @background_area indicates the total area of the
- * cell to be drawn. The @cell_area indicates the area where content can be
- * drawn (text, images, etc).
- *
- * The @background_area is the @cell_area plus the padding on each side (two
- * times the #GtkSourceGutterRenderer:xpad horizontally and two times the
- * #GtkSourceGutterRenderer:ypad vertically, so that the @cell_area is centered
- * inside @background_area).
- *
- * The @state argument indicates the current state of the renderer and should
- * be taken into account to properly draw the different possible states
- * (cursor, prelit, selected) if appropriate.
- */
-void
-gtk_source_gutter_renderer_draw (GtkSourceGutterRenderer      *renderer,
-                                 cairo_t                      *cr,
-                                 GdkRectangle                 *background_area,
-                                 GdkRectangle                 *cell_area,
-                                 GtkTextIter                  *start,
-                                 GtkTextIter                  *end,
-                                 GtkSourceGutterRendererState  state)
-{
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-       g_return_if_fail (cr != NULL);
-       g_return_if_fail (background_area != NULL);
-       g_return_if_fail (cell_area != NULL);
-       g_return_if_fail (start != NULL);
-       g_return_if_fail (end != NULL);
-
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (G_OBJECT_GET_CLASS (renderer))->draw)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (
-                       G_OBJECT_GET_CLASS (renderer))->draw (renderer,
-                                                             cr,
-                                                             background_area,
-                                                             cell_area,
-                                                             start,
-                                                             end,
-                                                             state);
-       }
-}
-
-/**
- * gtk_source_gutter_renderer_end:
- * @renderer: a #GtkSourceGutterRenderer
- *
- * Called when drawing a region of lines has ended.
- *
- **/
-void
-gtk_source_gutter_renderer_end (GtkSourceGutterRenderer *renderer)
-{
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (G_OBJECT_GET_CLASS (renderer))->end)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (G_OBJECT_GET_CLASS (renderer))->end (renderer);
-       }
-}
-
 /**
  * gtk_source_gutter_renderer_query_activatable:
  * @renderer: a #GtkSourceGutterRenderer
  * @iter: a #GtkTextIter at the start of the line to be activated
  * @area: a #GdkRectangle of the cell area to be activated
- * @event: the event that triggered the query
  *
- * Get whether the renderer is activatable at the location in @event. This is
+ * Get whether the renderer is activatable at the location provided. This is
  * called from #GtkSourceGutter to determine whether a renderer is activatable
  * using the mouse pointer.
  *
@@ -968,16 +566,14 @@ gtk_source_gutter_renderer_end (GtkSourceGutterRenderer *renderer)
  **/
 gboolean
 gtk_source_gutter_renderer_query_activatable (GtkSourceGutterRenderer *renderer,
-                                              GtkTextIter             *iter,
-                                              GdkRectangle            *area,
-                                              GdkEvent                *event)
+                                              const GtkTextIter       *iter,
+                                              const GdkRectangle      *area)
 {
        gboolean ret;
 
        g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), FALSE);
        g_return_val_if_fail (iter != NULL, FALSE);
        g_return_val_if_fail (area != NULL, FALSE);
-       g_return_val_if_fail (event != NULL, FALSE);
 
        ret = FALSE;
 
@@ -986,7 +582,6 @@ gtk_source_gutter_renderer_query_activatable (GtkSourceGutterRenderer *renderer,
                       0,
                       iter,
                       area,
-                      event,
                       &ret);
 
        return ret;
@@ -997,463 +592,427 @@ gtk_source_gutter_renderer_query_activatable (GtkSourceGutterRenderer *renderer,
  * @renderer: a #GtkSourceGutterRenderer
  * @iter: a #GtkTextIter at the start of the line where the renderer is activated
  * @area: a #GdkRectangle of the cell area where the renderer is activated
- * @event: the event that triggered the activation
+ * @button: the button that was pressed
+ * @state: a #GdkModifierType
+ * @n_presses: the number of button presses
  *
  * Emits the #GtkSourceGutterRenderer::activate signal of the renderer. This is
  * called from #GtkSourceGutter and should never have to be called manually.
  */
 void
 gtk_source_gutter_renderer_activate (GtkSourceGutterRenderer *renderer,
-                                     GtkTextIter             *iter,
-                                     GdkRectangle            *area,
-                                     GdkEvent                *event)
+                                     const GtkTextIter       *iter,
+                                     const GdkRectangle      *area,
+                                     guint                    button,
+                                     GdkModifierType          state,
+                                     gint                     n_presses)
 {
        g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
        g_return_if_fail (iter != NULL);
        g_return_if_fail (area != NULL);
-       g_return_if_fail (event != NULL);
 
-       g_signal_emit (renderer, signals[ACTIVATE], 0, iter, area, event);
+       g_signal_emit (renderer, signals[ACTIVATE], 0, iter, area, button, state, n_presses);
 }
 
 /**
- * gtk_source_gutter_renderer_queue_draw:
+ * gtk_source_gutter_renderer_set_alignment_mode:
  * @renderer: a #GtkSourceGutterRenderer
+ * @mode: a #GtkSourceGutterRendererAlignmentMode
  *
- * Emits the #GtkSourceGutterRenderer::queue-draw signal of the renderer. Call
- * this from an implementation to inform that the renderer has changed such that
- * it needs to redraw.
- */
-void
-gtk_source_gutter_renderer_queue_draw (GtkSourceGutterRenderer *renderer)
-{
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-
-       g_signal_emit (renderer, signals[QUEUE_DRAW], 0);
-}
-
-/**
- * gtk_source_gutter_renderer_query_tooltip:
- * @renderer: a #GtkSourceGutterRenderer.
- * @iter: a #GtkTextIter.
- * @area: a #GdkRectangle.
- * @x: The x position of the tooltip.
- * @y: The y position of the tooltip.
- * @tooltip: a #GtkTooltip.
- *
- * Emits the #GtkSourceGutterRenderer::query-tooltip signal. This function is
- * called from #GtkSourceGutter. Implementations can override the default signal
- * handler or can connect to the signal externally.
- *
- * Returns: %TRUE if the tooltip has been set, %FALSE otherwise
- */
-gboolean
-gtk_source_gutter_renderer_query_tooltip (GtkSourceGutterRenderer *renderer,
-                                          GtkTextIter             *iter,
-                                          GdkRectangle            *area,
-                                          gint                     x,
-                                          gint                     y,
-                                          GtkTooltip              *tooltip)
-{
-       gboolean ret;
-
-       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), FALSE);
-       g_return_val_if_fail (iter != NULL, FALSE);
-       g_return_val_if_fail (area != NULL, FALSE);
-       g_return_val_if_fail (GTK_IS_TOOLTIP (tooltip), FALSE);
-
-       ret = FALSE;
-
-       g_signal_emit (renderer,
-                      signals[QUERY_TOOLTIP],
-                      0,
-                      iter,
-                      area,
-                      x,
-                      y,
-                      tooltip,
-                      &ret);
-
-       return ret;
-}
-
-/**
- * gtk_source_gutter_renderer_query_data:
- * @renderer: a #GtkSourceGutterRenderer.
- * @start: a #GtkTextIter.
- * @end: a #GtkTextIter.
- * @state: a #GtkSourceGutterRendererState.
- *
- * Emit the #GtkSourceGutterRenderer::query-data signal. This function is called
- * to query for data just before rendering a cell. This is called from the
- * #GtkSourceGutter.  Implementations can override the default signal handler or
- * can connect a signal handler externally to the
- * #GtkSourceGutterRenderer::query-data signal.
- */
+ * Set the alignment mode. The alignment mode describes the manner in which the
+ * renderer is aligned (see #GtkSourceGutterRenderer:xalign and
+ * #GtkSourceGutterRenderer:yalign).
+ **/
 void
-gtk_source_gutter_renderer_query_data (GtkSourceGutterRenderer      *renderer,
-                                       GtkTextIter                  *start,
-                                       GtkTextIter                  *end,
-                                       GtkSourceGutterRendererState  state)
+gtk_source_gutter_renderer_set_alignment_mode (GtkSourceGutterRenderer              *renderer,
+                                               GtkSourceGutterRendererAlignmentMode  mode)
 {
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-       g_return_if_fail (start != NULL);
-       g_return_if_fail (end != NULL);
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
+       g_return_if_fail (GTK_SOURCE_GUTTER_RENDERER (renderer));
+       g_return_if_fail (mode == GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL ||
+                         mode == GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST ||
+                         mode == GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_LAST);
 
-       /* Signal emission is relatively expensive and this code path is
-        * frequent enough to optimize the common case where we only have the
-        * override and no connected handlers.
-        *
-        * This is the same trick used by gtk_widget_draw().
-        */
-       if (G_UNLIKELY (g_signal_has_handler_pending (renderer, signals[QUERY_DATA], 0, FALSE)))
-       {
-               g_signal_emit (renderer, signals[QUERY_DATA], 0, start, end, state);
-       }
-       else if (GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->query_data)
+       if (priv->alignment_mode != mode)
        {
-               GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->query_data (renderer, start, end, state);
+               priv->alignment_mode = mode;
+               g_object_notify_by_pspec (G_OBJECT (renderer),
+                                         properties[PROP_ALIGNMENT_MODE]);
+               gtk_widget_queue_draw (GTK_WIDGET (renderer));
        }
 }
 
 /**
- * gtk_source_gutter_renderer_set_visible:
+ * gtk_source_gutter_renderer_get_alignment_mode:
  * @renderer: a #GtkSourceGutterRenderer
- * @visible: the visibility
  *
- * Set whether the gutter renderer is visible.
+ * Get the alignment mode. The alignment mode describes the manner in which the
+ * renderer is aligned (see :xalign and :yalign).
  *
+ * Returns: a #GtkSourceGutterRendererAlignmentMode
  **/
-void
-gtk_source_gutter_renderer_set_visible (GtkSourceGutterRenderer *renderer,
-                                        gboolean                 visible)
+GtkSourceGutterRendererAlignmentMode
+gtk_source_gutter_renderer_get_alignment_mode (GtkSourceGutterRenderer *renderer)
 {
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       set_visible (renderer, visible);
+       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), 0);
+
+       return priv->alignment_mode;
 }
 
 /**
- * gtk_source_gutter_renderer_get_visible:
+ * gtk_source_gutter_renderer_get_view:
  * @renderer: a #GtkSourceGutterRenderer
  *
- * Get whether the gutter renderer is visible.
- *
- * Returns: %TRUE if the renderer is visible, %FALSE otherwise
+ * Get the view associated to the gutter renderer
  *
+ * Returns: (transfer none): a #GtkSourceView
  **/
-gboolean
-gtk_source_gutter_renderer_get_visible (GtkSourceGutterRenderer *renderer)
+GtkSourceView *
+gtk_source_gutter_renderer_get_view (GtkSourceGutterRenderer *renderer)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), FALSE);
+       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), NULL);
 
-       return priv->visible;
+       return GTK_SOURCE_VIEW (priv->view);
 }
 
-/**
- * gtk_source_gutter_renderer_set_padding:
- * @renderer: a #GtkSourceGutterRenderer
- * @xpad: the x-padding
- * @ypad: the y-padding
- *
- * Set the padding of the gutter renderer. Both @xpad and @ypad can be
- * -1, which means the values will not be changed (this allows changing only
- * one of the values).
- *
- * @xpad is the left and right padding. @ypad is the top and bottom padding.
- */
 void
-gtk_source_gutter_renderer_set_padding (GtkSourceGutterRenderer *renderer,
-                                        gint                     xpad,
-                                        gint                     ypad)
+_gtk_source_gutter_renderer_set_view (GtkSourceGutterRenderer *renderer,
+                                      GtkSourceView           *view)
 {
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+       GtkSourceView *old_view;
+
        g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       g_return_if_fail (view == NULL || GTK_SOURCE_IS_VIEW (view));
+
+       if (view == priv->view)
+       {
+               return;
+       }
+
+       old_view = g_steal_pointer (&priv->view);
+       g_set_object (&priv->view, view);
+
+       GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->change_view (renderer, old_view);
+
+       g_clear_object (&old_view);
 
-       set_xpad (renderer, xpad);
-       set_ypad (renderer, ypad);
+       g_object_notify_by_pspec (G_OBJECT (renderer), properties[PROP_VIEW]);
 }
 
-/**
- * gtk_source_gutter_renderer_get_padding:
- * @renderer: a #GtkSourceGutterRenderer
- * @xpad: (out caller-allocates) (optional): return location for the x-padding,
- *   or %NULL to ignore.
- * @ypad: (out caller-allocates) (optional): return location for the y-padding,
- *   or %NULL to ignore.
- *
- * Get the x-padding and y-padding of the gutter renderer.
- */
-void
-gtk_source_gutter_renderer_get_padding (GtkSourceGutterRenderer *renderer,
-                                        gint                    *xpad,
-                                        gint                    *ypad)
+static void
+get_line_rect (GtkSourceGutterRenderer *renderer,
+               guint                    line,
+               GdkRectangle            *rect)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+       GtkSourceGutterLines *lines = NULL;
 
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-
-       if (xpad)
+       if (priv->gutter != NULL)
        {
-               *xpad = priv->xpad;
+               lines = _gtk_source_gutter_get_lines (priv->gutter);
        }
 
-       if (ypad)
+       if (lines != NULL)
+       {
+               gint y;
+               gint height;
+
+               gtk_source_gutter_lines_get_line_yrange (lines,
+                                                        line,
+                                                        priv->alignment_mode,
+                                                        &y,
+                                                        &height);
+
+               rect->x = priv->xpad;
+               rect->y = y + priv->ypad;
+               rect->width = gtk_widget_get_width (GTK_WIDGET (renderer));
+               rect->height = height;
+
+               rect->width -= 2 * priv->xpad;
+               rect->height -= 2 * priv->ypad;
+       }
+       else
        {
-               *ypad = priv->ypad;
+               rect->x = 0;
+               rect->y = 0;
+               rect->width = 0;
+               rect->height = 0;
        }
 }
 
 /**
- * gtk_source_gutter_renderer_set_alignment:
- * @renderer: a #GtkSourceGutterRenderer
- * @xalign: the x-alignment
- * @yalign: the y-alignment
+ * gtk_source_gutter_renderer_align_cell:
+ * @renderer: the #GtkSourceGutterRenderer
+ * @line: the line number for content
+ * @width: the width of the content to draw
+ * @height: the height of the content to draw
+ * @x: (out): the X position to render the content
+ * @y: (out): the Y position to render the content
  *
- * Set the alignment of the gutter renderer. Both @xalign and @yalign can be
- * -1, which means the values will not be changed (this allows changing only
- * one of the values).
+ * Locates where to render content that is @width x @height based on
+ * the renderers alignment and padding.
  *
- * @xalign is the horizontal alignment. Set to 0 for a left alignment. 1 for a
- * right alignment. And 0.5 for centering the cells. @yalign is the vertical
- * alignment. Set to 0 for a top alignment. 1 for a bottom alignment.
+ * The location will be placed into @x and @y and is relative to the
+ * renderer's coordinates.
+ *
+ * It is encouraged that renderers use this function when snappshotting
+ * to ensure consistent placement of their contents.
+ *
+ * Since: 5.0
  */
 void
-gtk_source_gutter_renderer_set_alignment (GtkSourceGutterRenderer *renderer,
-                                          gfloat                   xalign,
-                                          gfloat                   yalign)
+gtk_source_gutter_renderer_align_cell (GtkSourceGutterRenderer *renderer,
+                                       guint                    line,
+                                       gfloat                   width,
+                                       gfloat                   height,
+                                       gfloat                  *x,
+                                       gfloat                  *y)
 {
-       gboolean changed_x;
-       gboolean changed_y;
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+       GdkRectangle rect;
 
        g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
 
-       changed_x = set_xalign (renderer, xalign, FALSE);
-       changed_y = set_yalign (renderer, yalign, FALSE);
+       get_line_rect (renderer, line, &rect);
 
-       if (changed_x || changed_y)
-       {
-               gtk_source_gutter_renderer_queue_draw (renderer);
-       }
+       *x = rect.x + (rect.width - width) * priv->xalign;
+       *y = rect.y + (rect.height - height) * priv->yalign;
 }
 
 /**
- * gtk_source_gutter_renderer_get_alignment:
+ * gtk_source_gutter_renderer_get_xpad:
  * @renderer: a #GtkSourceGutterRenderer
- * @xalign: (out caller-allocates) (optional): return location for the x-alignment,
- *   or %NULL to ignore.
- * @yalign: (out caller-allocates) (optional): return location for the y-alignment,
- *   or %NULL to ignore.
  *
- * Get the x-alignment and y-alignment of the gutter renderer.
+ * Gets the "xpad" property of the #GtkSourceGutterRenderer. This may be used
+ * to adjust the cell rectangle that the renderer will use to draw.
+ *
+ * Since: 5.0
  */
-void
-gtk_source_gutter_renderer_get_alignment (GtkSourceGutterRenderer *renderer,
-                                          gfloat                  *xalign,
-                                          gfloat                  *yalign)
+gint
+gtk_source_gutter_renderer_get_xpad (GtkSourceGutterRenderer *renderer)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-
-       if (xalign)
-       {
-               *xalign = priv->xalign;
-       }
+       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), 0);
 
-       if (yalign)
-       {
-               *yalign = priv->yalign;
-       }
+       return priv->xpad;
 }
 
 /**
- * gtk_source_gutter_renderer_set_alignment_mode:
+ * gtk_source_gutter_renderer_set_xpad:
  * @renderer: a #GtkSourceGutterRenderer
- * @mode: a #GtkSourceGutterRendererAlignmentMode
+ * @xpad: the Y padding for the drawing cell
  *
- * Set the alignment mode. The alignment mode describes the manner in which the
- * renderer is aligned (see :xalign and :yalign).
+ * Adjusts the "xpad" property of the #GtkSourceGutterRenderer. This may be
+ * used to adjust the cell rectangle that the renderer will use to draw.
  *
- **/
+ * Since: 5.0
+ */
 void
-gtk_source_gutter_renderer_set_alignment_mode (GtkSourceGutterRenderer              *renderer,
-                                               GtkSourceGutterRendererAlignmentMode  mode)
+gtk_source_gutter_renderer_set_xpad (GtkSourceGutterRenderer *renderer,
+                                     gint                     xpad)
 {
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+
        g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       g_return_if_fail (xpad >= 0);
 
-       set_alignment_mode (renderer, mode);
+       if (priv->xpad != xpad)
+       {
+               priv->xpad = xpad;
+               g_object_notify_by_pspec (G_OBJECT (renderer),
+                                         properties[PROP_XPAD]);
+               gtk_widget_queue_draw (GTK_WIDGET (renderer));
+       }
 }
 
 /**
- * gtk_source_gutter_renderer_get_alignment_mode:
+ * gtk_source_gutter_renderer_get_ypad:
  * @renderer: a #GtkSourceGutterRenderer
  *
- * Get the alignment mode. The alignment mode describes the manner in which the
- * renderer is aligned (see :xalign and :yalign).
- *
- * Returns: a #GtkSourceGutterRendererAlignmentMode
+ * Gets the "ypad" property of the #GtkSourceGutterRenderer. This may be used
+ * to adjust the cell rectangle that the renderer will use to draw.
  *
- **/
-GtkSourceGutterRendererAlignmentMode
-gtk_source_gutter_renderer_get_alignment_mode (GtkSourceGutterRenderer *renderer)
+ * Since: 5.0
+ */
+gint
+gtk_source_gutter_renderer_get_ypad (GtkSourceGutterRenderer *renderer)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
        g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), 0);
 
-       return priv->alignment_mode;
+       return priv->ypad;
 }
 
 /**
- * gtk_source_gutter_renderer_get_window_type:
+ * gtk_source_gutter_renderer_set_ypad:
  * @renderer: a #GtkSourceGutterRenderer
+ * @ypad: the Y padding for the drawing cell
  *
- * Get the #GtkTextWindowType associated with the gutter renderer.
+ * Adjusts the "ypad" property of the #GtkSourceGutterRenderer. This may be
+ * used to adjust the cell rectangle that the renderer will use to draw.
  *
- * Returns: a #GtkTextWindowType
- *
- **/
-GtkTextWindowType
-gtk_source_gutter_renderer_get_window_type (GtkSourceGutterRenderer *renderer)
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_renderer_set_ypad (GtkSourceGutterRenderer *renderer,
+                                     gint                     ypad)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), GTK_TEXT_WINDOW_PRIVATE);
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       g_return_if_fail (ypad >= 0);
 
-       return priv->window_type;
+       if (priv->ypad != ypad)
+       {
+               priv->ypad = ypad;
+               g_object_notify_by_pspec (G_OBJECT (renderer),
+                                         properties[PROP_YPAD]);
+               gtk_widget_queue_draw (GTK_WIDGET (renderer));
+       }
 }
 
 /**
- * gtk_source_gutter_renderer_get_view:
+ * gtk_source_gutter_renderer_get_xalign:
  * @renderer: a #GtkSourceGutterRenderer
  *
- * Get the view associated to the gutter renderer
- *
- * Returns: (transfer none): a #GtkTextView
+ * Gets the "xalign" property of the #GtkSourceGutterRenderer. This may be used
+ * to adjust where within the cell rectangle the renderer will draw.
  *
- **/
-GtkTextView *
-gtk_source_gutter_renderer_get_view (GtkSourceGutterRenderer *renderer)
+ * Since: 5.0
+ */
+gfloat
+gtk_source_gutter_renderer_get_xalign (GtkSourceGutterRenderer *renderer)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), NULL);
+       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), 0);
 
-       return priv->view;
+       return priv->xalign;
 }
 
 /**
- * gtk_source_gutter_renderer_get_size:
+ * gtk_source_gutter_renderer_set_xalign:
  * @renderer: a #GtkSourceGutterRenderer
+ * @xalign: the Y padding for the drawing cell
  *
- * Get the size of the renderer.
+ * Adjusts the "xalign" property of the #GtkSourceGutterRenderer. This may be
+ * used to adjust where within the cell rectangle the renderer will draw.
  *
- * Returns: the size of the renderer.
- *
- **/
-gint
-gtk_source_gutter_renderer_get_size (GtkSourceGutterRenderer *renderer)
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_renderer_set_xalign (GtkSourceGutterRenderer *renderer,
+                                       gfloat                   xalign)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), 0);
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       g_return_if_fail (xalign >= 0);
 
-       return priv->size;
+       if (priv->xalign != xalign)
+       {
+               priv->xalign = xalign;
+               g_object_notify_by_pspec (G_OBJECT (renderer),
+                                         properties[PROP_XALIGN]);
+               gtk_widget_queue_draw (GTK_WIDGET (renderer));
+       }
 }
 
 /**
- * gtk_source_gutter_renderer_set_size:
+ * gtk_source_gutter_renderer_get_yalign:
  * @renderer: a #GtkSourceGutterRenderer
- * @size: the size
  *
- * Sets the size of the renderer. A value of -1 specifies that the size
- * is to be determined dynamically.
+ * Gets the "yalign" property of the #GtkSourceGutterRenderer. This may be used
+ * to adjust where within the cell rectangle the renderer will draw.
  *
- **/
-void
-gtk_source_gutter_renderer_set_size (GtkSourceGutterRenderer *renderer,
-                                     gint                     size)
+ * Since: 5.0
+ */
+gfloat
+gtk_source_gutter_renderer_get_yalign (GtkSourceGutterRenderer *renderer)
 {
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
+
+       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), 0);
 
-       set_size (renderer, size);
+       return priv->yalign;
 }
 
 /**
- * gtk_source_gutter_renderer_get_background:
+ * gtk_source_gutter_renderer_set_yalign:
  * @renderer: a #GtkSourceGutterRenderer
- * @color: (out caller-allocates) (optional): return value for a #GdkRGBA
- *
- * Get the background color of the renderer.
+ * @yalign: the Y padding for the drawing cell
  *
- * Returns: %TRUE if the background color is set, %FALSE otherwise
+ * Adjusts the "yalign" property of the #GtkSourceGutterRenderer. This may be
+ * used to adjust where within the cell rectangle the renderer will draw.
  *
- **/
-gboolean
-gtk_source_gutter_renderer_get_background (GtkSourceGutterRenderer *renderer,
-                                           GdkRGBA                 *color)
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_renderer_set_yalign (GtkSourceGutterRenderer *renderer,
+                                       gfloat                   yalign)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), FALSE);
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       g_return_if_fail (yalign >= 0);
 
-       if (color)
+       if (priv->yalign != yalign)
        {
-               *color = priv->background_color;
+               priv->yalign = yalign;
+               g_object_notify_by_pspec (G_OBJECT (renderer),
+                                         properties[PROP_YALIGN]);
+               gtk_widget_queue_draw (GTK_WIDGET (renderer));
        }
-
-       return priv->background_set;
 }
 
 /**
- * gtk_source_gutter_renderer_set_background:
+ * gtk_source_gutter_renderer_get_buffer:
  * @renderer: a #GtkSourceGutterRenderer
- * @color: (nullable): a #GdkRGBA or %NULL
  *
- * Set the background color of the renderer. If @color is set to %NULL, the
- * renderer will not have a background color.
+ * Gets the #GtkSourceBuffer for which the gutter renderer is drawing.
+ *
+ * Returns: (transfer none) (nullable): a #GtkTextBuffer or %NULL
  *
+ * Since: 5.0
  */
-void
-gtk_source_gutter_renderer_set_background (GtkSourceGutterRenderer *renderer,
-                                           const GdkRGBA           *color)
+GtkSourceBuffer *
+gtk_source_gutter_renderer_get_buffer (GtkSourceGutterRenderer *renderer)
 {
-       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       set_background_color (renderer, color);
+       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer), NULL);
+
+       return priv->buffer;
 }
 
 void
-_gtk_source_gutter_renderer_set_view (GtkSourceGutterRenderer *renderer,
-                                      GtkTextView             *view,
-                                      GtkTextWindowType        window_type)
+_gtk_source_gutter_renderer_begin (GtkSourceGutterRenderer *renderer,
+                                   GtkSourceGutterLines    *lines)
 {
        GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       GtkTextView *old_view;
-
        g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
-       g_return_if_fail (view == NULL || GTK_IS_TEXT_VIEW (view));
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines));
 
-       old_view = priv->view;
-
-       priv->window_type = window_type;
-       priv->view = view != NULL ? g_object_ref (view) : NULL;
+       g_set_object (&priv->lines, lines);
+       GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->begin (renderer, lines);
+}
 
-       if (GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->change_view)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->change_view (renderer,
-                                                                             old_view);
-       }
+void
+_gtk_source_gutter_renderer_end (GtkSourceGutterRenderer *renderer)
+{
+       GtkSourceGutterRendererPrivate *priv = gtk_source_gutter_renderer_get_instance_private (renderer);
 
-       if (old_view)
-       {
-               g_object_unref (old_view);
-       }
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER (renderer));
 
-       g_object_notify (G_OBJECT (renderer), "view");
-       g_object_notify (G_OBJECT (renderer), "window_type");
+       GTK_SOURCE_GUTTER_RENDERER_GET_CLASS (renderer)->end (renderer);
+       g_clear_object (&priv->lines);
 }
diff --git a/gtksourceview/gtksourcegutterrenderer.h b/gtksourceview/gtksourcegutterrenderer.h
index baa413d5..fb38cc22 100644
--- a/gtksourceview/gtksourcegutterrenderer.h
+++ b/gtksourceview/gtksourcegutterrenderer.h
@@ -32,24 +32,6 @@ G_BEGIN_DECLS
 
 #define GTK_SOURCE_TYPE_GUTTER_RENDERER (gtk_source_gutter_renderer_get_type())
 
-/**
- * GtkSourceGutterRendererState:
- * @GTK_SOURCE_GUTTER_RENDERER_STATE_NORMAL: normal state
- * @GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR: area in the renderer represents the
- * line on which the insert cursor is currently positioned
- * @GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT: the mouse pointer is currently
- * over the activatable area of the renderer
- * @GTK_SOURCE_GUTTER_RENDERER_STATE_SELECTED: area in the renderer represents
- * a line in the buffer which contains part of the selection
- **/
-typedef enum _GtkSourceGutterRendererState
-{
-       GTK_SOURCE_GUTTER_RENDERER_STATE_NORMAL   = 0,
-       GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR   = 1 << 0,
-       GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT   = 1 << 1,
-       GTK_SOURCE_GUTTER_RENDERER_STATE_SELECTED = 1 << 2
-} GtkSourceGutterRendererState;
-
 /**
  * GtkSourceGutterRendererAlignmentMode:
  * @GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL: The full cell.
@@ -63,31 +45,23 @@ typedef enum _GtkSourceGutterRendererAlignmentMode
 {
        GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL,
        GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST,
-       GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_LAST
+       GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_LAST,
 } GtkSourceGutterRendererAlignmentMode;
 
 struct _GtkSourceGutterRendererClass
 {
-       GInitiallyUnownedClass parent_class;
-
-       /*< public >*/
-       void     (*begin)             (GtkSourceGutterRenderer     *renderer,
-                                      cairo_t                     *cr,
-                                      GdkRectangle                *background_area,
-                                      GdkRectangle                *cell_area,
-                                      GtkTextIter                 *start,
-                                      GtkTextIter                 *end);
-
-       void     (*draw)              (GtkSourceGutterRenderer      *renderer,
-                                      cairo_t                      *cr,
-                                      GdkRectangle                 *background_area,
-                                      GdkRectangle                 *cell_area,
-                                      GtkTextIter                  *start,
-                                      GtkTextIter                  *end,
-                                      GtkSourceGutterRendererState  state);
-
-       void     (*end)               (GtkSourceGutterRenderer      *renderer);
-
+       GtkWidgetClass parent_class;
+
+       void     (*query_data)            (GtkSourceGutterRenderer      *renderer,
+                                          GtkSourceGutterLines         *lines,
+                                          guint                         line);
+       void     (*begin)                 (GtkSourceGutterRenderer      *renderer,
+                                          GtkSourceGutterLines         *lines);
+       void     (*snapshot_line)         (GtkSourceGutterRenderer      *renderer,
+                                          GtkSnapshot                  *snapshot,
+                                          GtkSourceGutterLines         *lines,
+                                          guint                         line);
+       void     (*end)                   (GtkSourceGutterRenderer      *renderer);
        /**
         * GtkSourceGutterRendererClass::change_view:
         * @renderer: a #GtkSourceGutterRenderer.
@@ -95,9 +69,8 @@ struct _GtkSourceGutterRendererClass
         *
         * This is called when the text view changes for @renderer.
         */
-       void     (*change_view)       (GtkSourceGutterRenderer      *renderer,
-                                      GtkTextView                  *old_view);
-
+       void     (*change_view)           (GtkSourceGutterRenderer      *renderer,
+                                          GtkSourceView                *old_view);
        /**
         * GtkSourceGutterRendererClass::change_buffer:
         * @renderer: a #GtkSourceGutterRenderer.
@@ -105,122 +78,72 @@ struct _GtkSourceGutterRendererClass
         *
         * This is called when the text buffer changes for @renderer.
         */
-       void     (*change_buffer)     (GtkSourceGutterRenderer      *renderer,
-                                      GtkTextBuffer                *old_buffer);
-
+       void     (*change_buffer)         (GtkSourceGutterRenderer      *renderer,
+                                          GtkSourceBuffer              *old_buffer);
        /* Signal handlers */
-       gboolean (*query_activatable) (GtkSourceGutterRenderer      *renderer,
-                                      GtkTextIter                  *iter,
-                                      GdkRectangle                 *area,
-                                      GdkEvent                     *event);
-
-       void     (*activate)          (GtkSourceGutterRenderer      *renderer,
-                                      GtkTextIter                  *iter,
-                                      GdkRectangle                 *area,
-                                      GdkEvent                     *event);
-
-       void     (*queue_draw)        (GtkSourceGutterRenderer      *renderer);
-
-       gboolean (*query_tooltip)     (GtkSourceGutterRenderer      *renderer,
-                                      GtkTextIter                  *iter,
-                                      GdkRectangle                 *area,
-                                      gint                          x,
-                                      gint                          y,
-                                      GtkTooltip                   *tooltip);
-
-       void     (*query_data)        (GtkSourceGutterRenderer      *renderer,
-                                      GtkTextIter                  *start,
-                                      GtkTextIter                  *end,
-                                      GtkSourceGutterRendererState  state);
+       gboolean (*query_activatable)     (GtkSourceGutterRenderer      *renderer,
+                                          GtkTextIter                  *iter,
+                                          GdkRectangle                 *area);
+       void     (*activate)              (GtkSourceGutterRenderer      *renderer,
+                                          GtkTextIter                  *iter,
+                                          GdkRectangle                 *area,
+                                          guint                         button,
+                                          GdkModifierType               state,
+                                          gint                          n_presses);
 
        /*< private >*/
        gpointer _reserved[20];
 };
 
 GTK_SOURCE_AVAILABLE_IN_ALL
-G_DECLARE_DERIVABLE_TYPE (GtkSourceGutterRenderer, gtk_source_gutter_renderer, GTK_SOURCE, GUTTER_RENDERER, 
GInitiallyUnowned)
+G_DECLARE_DERIVABLE_TYPE (GtkSourceGutterRenderer, gtk_source_gutter_renderer, GTK_SOURCE, GUTTER_RENDERER, 
GtkWidget)
 
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_begin              (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     cairo_t                 
             *cr,
-                                                                                     GdkRectangle            
             *background_area,
-                                                                                     GdkRectangle            
             *cell_area,
-                                                                                     GtkTextIter             
             *start,
-                                                                                     GtkTextIter             
             *end);
-GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_draw               (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     cairo_t                 
             *cr,
-                                                                                     GdkRectangle            
             *background_area,
-                                                                                     GdkRectangle            
             *cell_area,
-                                                                                     GtkTextIter             
             *start,
-                                                                                     GtkTextIter             
             *end,
-                                                                                     
GtkSourceGutterRendererState          state);
+gfloat                                gtk_source_gutter_renderer_get_xalign         (GtkSourceGutterRenderer 
             *renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_end                (GtkSourceGutterRenderer 
             *renderer);
+void                                  gtk_source_gutter_renderer_set_xalign         (GtkSourceGutterRenderer 
             *renderer,
+                                                                                     gfloat                  
              xalign);
 GTK_SOURCE_AVAILABLE_IN_ALL
-gint                                  gtk_source_gutter_renderer_get_size           (GtkSourceGutterRenderer 
             *renderer);
+gfloat                                gtk_source_gutter_renderer_get_yalign         (GtkSourceGutterRenderer 
             *renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_set_size           (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     gint                    
              size);
+void                                  gtk_source_gutter_renderer_set_yalign         (GtkSourceGutterRenderer 
             *renderer,
+                                                                                     gfloat                  
              yalign);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_set_visible        (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     gboolean                
              visible);
+gint                                  gtk_source_gutter_renderer_get_xpad           (GtkSourceGutterRenderer 
             *renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
-gboolean                              gtk_source_gutter_renderer_get_visible        (GtkSourceGutterRenderer 
             *renderer);
+void                                  gtk_source_gutter_renderer_set_xpad           (GtkSourceGutterRenderer 
             *renderer,
+                                                                                     gint                    
              xpad);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_get_padding        (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     gint                    
             *xpad,
-                                                                                     gint                    
             *ypad);
+gint                                  gtk_source_gutter_renderer_get_ypad           (GtkSourceGutterRenderer 
             *renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_set_padding        (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     gint                    
              xpad,
+void                                  gtk_source_gutter_renderer_set_ypad           (GtkSourceGutterRenderer 
             *renderer,
                                                                                      gint                    
              ypad);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_get_alignment      (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     gfloat                  
             *xalign,
-                                                                                     gfloat                  
             *yalign);
-GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_set_alignment      (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     gfloat                  
              xalign,
-                                                                                     gfloat                  
              yalign);
+GtkSourceGutterRendererAlignmentMode  gtk_source_gutter_renderer_get_alignment_mode (GtkSourceGutterRenderer 
             *renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
 void                                  gtk_source_gutter_renderer_set_alignment_mode (GtkSourceGutterRenderer 
             *renderer,
                                                                                      
GtkSourceGutterRendererAlignmentMode  mode);
 GTK_SOURCE_AVAILABLE_IN_ALL
-GtkTextWindowType                     gtk_source_gutter_renderer_get_window_type    (GtkSourceGutterRenderer 
             *renderer);
-GTK_SOURCE_AVAILABLE_IN_ALL
-GtkTextView                          *gtk_source_gutter_renderer_get_view           (GtkSourceGutterRenderer 
             *renderer);
-GTK_SOURCE_AVAILABLE_IN_ALL
-GtkSourceGutterRendererAlignmentMode  gtk_source_gutter_renderer_get_alignment_mode (GtkSourceGutterRenderer 
             *renderer);
-GTK_SOURCE_AVAILABLE_IN_ALL
-gboolean                              gtk_source_gutter_renderer_get_background     (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     GdkRGBA                 
             *color);
+GtkSourceBuffer                      *gtk_source_gutter_renderer_get_buffer         (GtkSourceGutterRenderer 
             *renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_set_background     (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     const GdkRGBA           
             *color);
+GtkSourceView                        *gtk_source_gutter_renderer_get_view           (GtkSourceGutterRenderer 
             *renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
 void                                  gtk_source_gutter_renderer_activate           (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     GtkTextIter             
             *iter,
-                                                                                     GdkRectangle            
             *area,
-                                                                                     GdkEvent                
             *event);
+                                                                                     const GtkTextIter       
             *iter,
+                                                                                     const GdkRectangle      
             *area,
+                                                                                     guint                   
              button,
+                                                                                     GdkModifierType         
              state,
+                                                                                     gint                    
              n_presses);
 GTK_SOURCE_AVAILABLE_IN_ALL
 gboolean                              gtk_source_gutter_renderer_query_activatable  (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     GtkTextIter             
             *iter,
-                                                                                     GdkRectangle            
             *area,
-                                                                                     GdkEvent                
             *event);
-GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_queue_draw         (GtkSourceGutterRenderer 
             *renderer);
-GTK_SOURCE_AVAILABLE_IN_ALL
-gboolean                              gtk_source_gutter_renderer_query_tooltip      (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     GtkTextIter             
             *iter,
-                                                                                     GdkRectangle            
             *area,
-                                                                                     gint                    
              x,
-                                                                                     gint                    
              y,
-                                                                                     GtkTooltip              
             *tooltip);
-GTK_SOURCE_AVAILABLE_IN_ALL
-void                                  gtk_source_gutter_renderer_query_data         (GtkSourceGutterRenderer 
             *renderer,
-                                                                                     GtkTextIter             
             *start,
-                                                                                     GtkTextIter             
             *end,
-                                                                                     
GtkSourceGutterRendererState          state);
+                                                                                     const GtkTextIter       
             *iter,
+                                                                                     const GdkRectangle      
             *area);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void                                  gtk_source_gutter_renderer_align_cell         (GtkSourceGutterRenderer 
             *renderer,
+                                                                                     guint                   
              line,
+                                                                                     gfloat                  
              width,
+                                                                                     gfloat                  
              height,
+                                                                                     gfloat                  
             *x,
+                                                                                     gfloat                  
             *y);
 
 G_END_DECLS
diff --git a/gtksourceview/gtksourcegutterrendererlines.c b/gtksourceview/gtksourcegutterrendererlines.c
index 6f508ce1..07e06423 100644
--- a/gtksourceview/gtksourcegutterrendererlines.c
+++ b/gtksourceview/gtksourcegutterrendererlines.c
@@ -21,6 +21,7 @@
 #include "config.h"
 
 #include "gtksourcegutterrendererlines-private.h"
+#include "gtksourcegutterlines.h"
 #include "gtksourceutils-private.h"
 #include "gtksourceview.h"
 
@@ -34,16 +35,6 @@ struct _GtkSourceGutterRendererLines
 
 G_DEFINE_TYPE (GtkSourceGutterRendererLines, _gtk_source_gutter_renderer_lines, 
GTK_SOURCE_TYPE_GUTTER_RENDERER_TEXT)
 
-static GtkTextBuffer *
-get_buffer (GtkSourceGutterRendererLines *renderer)
-{
-       GtkTextView *view;
-
-       view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (renderer));
-
-       return view != NULL ? gtk_text_view_get_buffer (view) : NULL;
-}
-
 static inline gint
 count_num_digits (gint num_lines)
 {
@@ -76,33 +67,18 @@ count_num_digits (gint num_lines)
 static void
 recalculate_size (GtkSourceGutterRendererLines *renderer)
 {
+       GtkSourceBuffer *buffer;
        gint num_lines;
-       gint num_digits = 0;
-       GtkTextBuffer *buffer;
-
-       buffer = get_buffer (renderer);
-
-       num_lines = gtk_text_buffer_get_line_count (buffer);
+       gint num_digits;
 
+       buffer = gtk_source_gutter_renderer_get_buffer (GTK_SOURCE_GUTTER_RENDERER (renderer));
+       num_lines = gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (buffer));
        num_digits = count_num_digits (num_lines);
 
        if (num_digits != renderer->num_line_digits)
        {
-               gchar markup[24];
-               gint size;
-
                renderer->num_line_digits = num_digits;
-
-               num_lines = MAX (num_lines, 99);
-
-               g_snprintf (markup, sizeof markup, "<b>%d</b>", num_lines);
-               gtk_source_gutter_renderer_text_measure_markup (GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer),
-                                                               markup,
-                                                               &size,
-                                                               NULL);
-
-               gtk_source_gutter_renderer_set_size (GTK_SOURCE_GUTTER_RENDERER (renderer),
-                                                    size);
+               gtk_widget_queue_resize (GTK_WIDGET (renderer));
        }
 }
 
@@ -113,21 +89,37 @@ on_buffer_changed (GtkSourceBuffer              *buffer,
        recalculate_size (renderer);
 }
 
+static void
+on_buffer_cursor_moved (GtkSourceBuffer              *buffer,
+                        GtkSourceGutterRendererLines *renderer)
+{
+       if (renderer->cursor_visible)
+       {
+               /* Redraw if the current-line needs updating */
+               gtk_widget_queue_draw (GTK_WIDGET (renderer));
+       }
+}
+
 static void
 gutter_renderer_change_buffer (GtkSourceGutterRenderer *renderer,
-                               GtkTextBuffer           *old_buffer)
+                               GtkSourceBuffer         *old_buffer)
 {
        GtkSourceGutterRendererLines *lines = GTK_SOURCE_GUTTER_RENDERER_LINES (renderer);
-       GtkTextBuffer *buffer;
+       GtkSourceBuffer *buffer;
 
        if (old_buffer != NULL)
        {
                g_signal_handlers_disconnect_by_func (old_buffer,
                                                      on_buffer_changed,
                                                      lines);
+               g_signal_handlers_disconnect_by_func (old_buffer,
+                                                     on_buffer_cursor_moved,
+                                                     lines);
        }
 
-       buffer = get_buffer (lines);
+       buffer = gtk_source_gutter_renderer_get_buffer (renderer);
+
+       lines->prev_line_num = 0;
 
        if (buffer != NULL)
        {
@@ -137,20 +129,21 @@ gutter_renderer_change_buffer (GtkSourceGutterRenderer *renderer,
                                         lines,
                                         0);
 
+               g_signal_connect_object (buffer,
+                                        "cursor-moved",
+                                        G_CALLBACK (on_buffer_cursor_moved),
+                                        lines,
+                                        0);
+
                recalculate_size (lines);
        }
 
-       lines->prev_line_num = 0;
-
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (_gtk_source_gutter_renderer_lines_parent_class)->change_buffer 
!= NULL)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS 
(_gtk_source_gutter_renderer_lines_parent_class)->change_buffer (renderer, old_buffer);
-       }
+       GTK_SOURCE_GUTTER_RENDERER_CLASS (_gtk_source_gutter_renderer_lines_parent_class)->change_buffer 
(renderer, old_buffer);
 }
 
 static void
 on_view_style_updated (GtkTextView                  *view,
-                      GtkSourceGutterRendererLines *renderer)
+                       GtkSourceGutterRendererLines *renderer)
 {
        /* Force to recalculate the size. */
        renderer->num_line_digits = -1;
@@ -167,9 +160,9 @@ on_view_notify_cursor_visible (GtkTextView                  *view,
 
 static void
 gutter_renderer_change_view (GtkSourceGutterRenderer *renderer,
-                            GtkTextView             *old_view)
+                            GtkSourceView             *old_view)
 {
-       GtkTextView *new_view;
+       GtkSourceView *new_view;
 
        if (old_view != NULL)
        {
@@ -197,116 +190,10 @@ gutter_renderer_change_view (GtkSourceGutterRenderer *renderer,
                                         renderer,
                                         0);
 
-               GTK_SOURCE_GUTTER_RENDERER_LINES (renderer)->cursor_visible = 
gtk_text_view_get_cursor_visible (new_view);
-       }
-
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (_gtk_source_gutter_renderer_lines_parent_class)->change_view != 
NULL)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS 
(_gtk_source_gutter_renderer_lines_parent_class)->change_view (renderer, old_view);
-       }
-}
-
-static void
-gutter_renderer_query_data (GtkSourceGutterRenderer      *renderer,
-                            GtkTextIter                  *start,
-                            GtkTextIter                  *end,
-                            GtkSourceGutterRendererState  state)
-{
-       GtkSourceGutterRendererLines *lines = GTK_SOURCE_GUTTER_RENDERER_LINES (renderer);
-       gchar text[24];
-       const gchar *textptr = text;
-       gint line;
-       gint len;
-       gboolean current_line;
-
-       line = gtk_text_iter_get_line (start) + 1;
-
-       current_line = (state & GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR) &&
-                      lines->cursor_visible;
-
-       if G_LIKELY (!current_line)
-       {
-               len = _gtk_source_utils_int_to_string (line, &textptr);
-       }
-       else
-       {
-               len = g_snprintf (text, sizeof text, "<b>%d</b>", line);
-       }
-
-       gtk_source_gutter_renderer_text_set_markup (GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer),
-                                                   textptr,
-                                                   len);
-}
-
-static gint
-get_last_visible_line_number (GtkSourceGutterRendererLines *lines)
-{
-       GtkTextView *view;
-       GdkRectangle visible_rect;
-       GtkTextIter iter;
-
-       view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (lines));
-
-       gtk_text_view_get_visible_rect (view, &visible_rect);
-
-       gtk_text_view_get_line_at_y (view,
-                                    &iter,
-                                    visible_rect.y + visible_rect.height,
-                                    NULL);
-
-       gtk_text_iter_forward_line (&iter);
-
-       return gtk_text_iter_get_line (&iter);
-}
-
-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_num = get_last_visible_line_number (lines);
-
-               /* 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).
-                * Another solution that has better performances is to compare
-                * the total number of lines in the buffer, instead of the last
-                * visible line. But it has the drawback that the gutter is
-                * continuously redrawn during file loading.
-                *
-                * 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->prev_line_num != line_num)
-               {
-                       lines->prev_line_num = line_num;
-                       gtk_source_gutter_renderer_queue_draw (renderer);
-               }
+               GTK_SOURCE_GUTTER_RENDERER_LINES (renderer)->cursor_visible = 
gtk_text_view_get_cursor_visible (GTK_TEXT_VIEW (new_view));
        }
 
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (_gtk_source_gutter_renderer_lines_parent_class)->end != NULL)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (_gtk_source_gutter_renderer_lines_parent_class)->end 
(renderer);
-       }
+       GTK_SOURCE_GUTTER_RENDERER_CLASS (_gtk_source_gutter_renderer_lines_parent_class)->change_view 
(renderer, old_view);
 }
 
 static void
@@ -316,11 +203,11 @@ extend_selection_to_line (GtkSourceGutterRendererLines *renderer,
        GtkTextIter start;
        GtkTextIter end;
        GtkTextIter line_end;
-       GtkTextBuffer *buffer;
+       GtkSourceBuffer *buffer;
 
-       buffer = get_buffer (renderer);
+       buffer = gtk_source_gutter_renderer_get_buffer (GTK_SOURCE_GUTTER_RENDERER (renderer));
 
-       gtk_text_buffer_get_selection_bounds (buffer,
+       gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer),
                                              &start,
                                              &end);
 
@@ -333,7 +220,7 @@ extend_selection_to_line (GtkSourceGutterRendererLines *renderer,
 
        if (gtk_text_iter_compare (&start, line_start) < 0)
        {
-               gtk_text_buffer_select_range (buffer,
+               gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer),
                                              &start,
                                              &line_end);
        }
@@ -341,13 +228,13 @@ extend_selection_to_line (GtkSourceGutterRendererLines *renderer,
        {
                /* if the selection is in this line, extend
                 * the selection to the whole line */
-               gtk_text_buffer_select_range (buffer,
+               gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer),
                                              &line_end,
                                              line_start);
        }
        else
        {
-               gtk_text_buffer_select_range (buffer,
+               gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer),
                                              &end,
                                              line_start);
        }
@@ -358,9 +245,9 @@ select_line (GtkSourceGutterRendererLines *renderer,
              GtkTextIter                  *line_start)
 {
        GtkTextIter iter;
-       GtkTextBuffer *buffer;
+       GtkSourceBuffer *buffer;
 
-       buffer = get_buffer (renderer);
+       buffer = gtk_source_gutter_renderer_get_buffer (GTK_SOURCE_GUTTER_RENDERER (renderer));
 
        iter = *line_start;
 
@@ -370,31 +257,37 @@ select_line (GtkSourceGutterRendererLines *renderer,
        }
 
        /* Select the line, put the cursor at the end of the line */
-       gtk_text_buffer_select_range (buffer, &iter, line_start);
+       gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &iter, line_start);
 }
 
 static void
 gutter_renderer_activate (GtkSourceGutterRenderer *renderer,
                           GtkTextIter             *iter,
                           GdkRectangle            *rect,
-                          GdkEvent                *event)
+                          guint                    button,
+                          GdkModifierType          state,
+                          gint                     n_presses)
 {
        GtkSourceGutterRendererLines *lines;
+       GtkSourceBuffer *buffer;
 
        lines = GTK_SOURCE_GUTTER_RENDERER_LINES (renderer);
 
-       if (event->type == GDK_BUTTON_PRESS && (event->button.button == 1))
+       if (button != 1)
        {
-               GtkTextBuffer *buffer;
+               return;
+       }
 
-               buffer = get_buffer (lines);
+       buffer = gtk_source_gutter_renderer_get_buffer (renderer);
 
-               if ((event->button.state & GDK_CONTROL_MASK) != 0)
+       if (n_presses == 1)
+       {
+               if ((state & GDK_CONTROL_MASK) != 0)
                {
                        /* Single click + Ctrl -> select the line */
                        select_line (lines, iter);
                }
-               else if ((event->button.state & GDK_SHIFT_MASK) != 0)
+               else if ((state & GDK_SHIFT_MASK) != 0)
                {
                        /* Single click + Shift -> extended current
                           selection to include the clicked line */
@@ -402,10 +295,10 @@ gutter_renderer_activate (GtkSourceGutterRenderer *renderer,
                }
                else
                {
-                       gtk_text_buffer_place_cursor (buffer, iter);
+                       gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (buffer), iter);
                }
        }
-       else if (event->type == GDK_2BUTTON_PRESS && (event->button.button == 1))
+       else if (n_presses == 2)
        {
                select_line (lines, iter);
        }
@@ -414,20 +307,87 @@ gutter_renderer_activate (GtkSourceGutterRenderer *renderer,
 static gboolean
 gutter_renderer_query_activatable (GtkSourceGutterRenderer *renderer,
                                    GtkTextIter             *iter,
-                                   GdkRectangle            *area,
-                                   GdkEvent                *event)
+                                   GdkRectangle            *area)
+{
+       return gtk_source_gutter_renderer_get_buffer (renderer) != NULL;
+}
+
+static void
+gtk_source_gutter_renderer_lines_measure (GtkWidget      *widget,
+                                          GtkOrientation  orientation,
+                                          int             for_size,
+                                          int            *minimum,
+                                          int            *natural,
+                                          int            *minimum_baseline,
+                                          int            *natural_baseline)
+{
+       GtkSourceGutterRendererLines *renderer = GTK_SOURCE_GUTTER_RENDERER_LINES (widget);
+
+       if (orientation == GTK_ORIENTATION_VERTICAL)
+       {
+               *minimum = 0;
+               *natural = 0;
+       }
+       else
+       {
+               GtkSourceBuffer *buffer;
+               gchar markup[32];
+               guint num_lines;
+               gint size;
+               gint xpad;
+
+               buffer = gtk_source_gutter_renderer_get_buffer (GTK_SOURCE_GUTTER_RENDERER (renderer));
+               num_lines = MAX (99, gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (buffer)));
+
+               g_snprintf (markup, sizeof markup, "<b>%u</b>", num_lines);
+               gtk_source_gutter_renderer_text_measure_markup (GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer),
+                                                               markup,
+                                                               &size,
+                                                               NULL);
+
+               xpad = gtk_source_gutter_renderer_get_xpad (GTK_SOURCE_GUTTER_RENDERER (renderer));
+
+               *natural = *minimum = size + xpad * 2;
+       }
+
+       *minimum_baseline = -1;
+       *natural_baseline = -1;
+}
+
+static void
+gtk_source_gutter_renderer_lines_query_data (GtkSourceGutterRenderer *renderer,
+                                             GtkSourceGutterLines    *lines,
+                                             guint                    line)
 {
-       return get_buffer (GTK_SOURCE_GUTTER_RENDERER_LINES (renderer)) != NULL;
+       GtkSourceGutterRendererLines *self = GTK_SOURCE_GUTTER_RENDERER_LINES (renderer);
+       gint len;
+
+       if G_UNLIKELY (self->cursor_visible && gtk_source_gutter_lines_is_cursor (lines, line))
+       {
+               gchar text[32];
+
+               len = g_snprintf (text, sizeof text, "<b>%d</b>", line + 1);
+               gtk_source_gutter_renderer_text_set_markup (GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer), text, 
len);
+       }
+       else
+       {
+               const gchar *text;
+
+               len = _gtk_source_utils_int_to_string (line + 1, &text);
+               gtk_source_gutter_renderer_text_set_text (GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer), text, 
len);
+       }
 }
 
 static void
 _gtk_source_gutter_renderer_lines_class_init (GtkSourceGutterRendererLinesClass *klass)
 {
        GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       widget_class->measure = gtk_source_gutter_renderer_lines_measure;
 
-       renderer_class->query_data = gutter_renderer_query_data;
-       renderer_class->end = gutter_renderer_end;
        renderer_class->query_activatable = gutter_renderer_query_activatable;
+       renderer_class->query_data = gtk_source_gutter_renderer_lines_query_data;
        renderer_class->activate = gutter_renderer_activate;
        renderer_class->change_buffer = gutter_renderer_change_buffer;
        renderer_class->change_view = gutter_renderer_change_view;
diff --git a/gtksourceview/gtksourcegutterrenderermarks.c b/gtksourceview/gtksourcegutterrenderermarks.c
index 70f9d508..0c9dbf6d 100644
--- a/gtksourceview/gtksourcegutterrenderermarks.c
+++ b/gtksourceview/gtksourcegutterrenderermarks.c
@@ -96,28 +96,23 @@ measure_line_height (GtkSourceView *view)
        return height - 2;
 }
 
-static GdkPixbuf *
-composite_marks (GtkSourceView *view,
-                 GSList        *marks,
-                 gint           size)
+static void
+composite_marks (GtkSourceView                 *view,
+                 GtkSourceGutterRendererPixbuf *renderer,
+                 GSList                        *marks,
+                 gint                           size)
 {
-       GdkPixbuf *composite;
-       gint mark_width;
-       gint mark_height;
-
        /* Draw the mark with higher priority */
        marks = g_slist_sort_with_data (marks, sort_marks_by_priority, view);
 
-       composite = NULL;
-       mark_width = 0;
-       mark_height = 0;
+       gtk_source_gutter_renderer_pixbuf_set_paintable (renderer, NULL);
 
        /* composite all the pixbufs for the marks present at the line */
        do
        {
                GtkSourceMark *mark;
                GtkSourceMarkAttributes *attrs;
-               const GdkPixbuf *pixbuf;
+               GdkPaintable *paintable;
 
                mark = marks->data;
                attrs = gtk_source_view_get_mark_attributes (view,
@@ -129,81 +124,53 @@ composite_marks (GtkSourceView *view,
                        continue;
                }
 
-               pixbuf = gtk_source_mark_attributes_render_icon (attrs,
-                                                                GTK_WIDGET (view),
-                                                                size);
+               paintable = gtk_source_mark_attributes_render_icon (attrs,
+                                                                   GTK_WIDGET (view),
+                                                                   size);
 
-               if (pixbuf != NULL)
+               if (paintable != NULL)
                {
-                       if (composite == NULL)
-                       {
-                               composite = gdk_pixbuf_copy (pixbuf);
-                               mark_width = gdk_pixbuf_get_width (composite);
-                               mark_height = gdk_pixbuf_get_height (composite);
-                       }
-                       else
-                       {
-                               gint pixbuf_w;
-                               gint pixbuf_h;
-
-                               pixbuf_w = gdk_pixbuf_get_width (pixbuf);
-                               pixbuf_h = gdk_pixbuf_get_height (pixbuf);
-
-                               gdk_pixbuf_composite (pixbuf,
-                                                     composite,
-                                                     0, 0,
-                                                     mark_width, mark_height,
-                                                     0, 0,
-                                                     (gdouble) pixbuf_w / mark_width,
-                                                     (gdouble) pixbuf_h / mark_height,
-                                                     GDK_INTERP_BILINEAR,
-                                                     COMPOSITE_ALPHA);
-                       }
+                       gtk_source_gutter_renderer_pixbuf_overlay_paintable (renderer, paintable);
                }
 
                marks = g_slist_next (marks);
        }
        while (marks);
-
-       return composite;
 }
 
 static void
-gutter_renderer_query_data (GtkSourceGutterRenderer      *renderer,
-                            GtkTextIter                  *start,
-                            GtkTextIter                  *end,
-                            GtkSourceGutterRendererState  state)
+gutter_renderer_query_data (GtkSourceGutterRenderer *renderer,
+                            GtkSourceGutterLines    *lines,
+                            guint                    line)
 {
-       GSList *marks;
-       GdkPixbuf *pixbuf = NULL;
-       gint size = 0;
-       GtkSourceView *view;
        GtkSourceBuffer *buffer;
+       GtkSourceView *view;
+       GtkTextIter iter;
+       GSList *marks;
 
        view = GTK_SOURCE_VIEW (gtk_source_gutter_renderer_get_view (renderer));
        buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
 
-       marks = gtk_source_buffer_get_source_marks_at_iter (buffer,
-                                                           start,
-                                                           NULL);
+       gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &iter, line);
+       marks = gtk_source_buffer_get_source_marks_at_iter (buffer, &iter, NULL);
 
        if (marks != NULL)
        {
-               size = measure_line_height (view);
-               pixbuf = composite_marks (view, marks, size);
-
+               gint size = measure_line_height (view);
+               composite_marks (view, GTK_SOURCE_GUTTER_RENDERER_PIXBUF (renderer), marks, size);
+               g_object_set (G_OBJECT (renderer),
+                             "xpad", 2,
+                             "yalign", 0.5,
+                             "xalign", 0.5,
+                             "alignment-mode", GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST,
+                             NULL);
                g_slist_free (marks);
        }
-
-       g_object_set (G_OBJECT (renderer),
-                     "pixbuf", pixbuf,
-                     "xpad", 2,
-                     "yalign", 0.5,
-                     "xalign", 0.5,
-                     "alignment-mode", GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST,
-                     NULL);
-
-       g_clear_object (&pixbuf);
+       else
+       {
+               gtk_source_gutter_renderer_pixbuf_set_paintable (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (renderer),
+                                                                NULL);
+       }
 }
 
 static gboolean
@@ -211,11 +178,9 @@ set_tooltip_widget_from_marks (GtkSourceView *view,
                                GtkTooltip    *tooltip,
                                GSList        *marks)
 {
+       const gint icon_size = 16;
        GtkGrid *grid = NULL;
        gint row_num = 0;
-       gint icon_size;
-
-       gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_size);
 
        for (; marks; marks = g_slist_next (marks))
        {
@@ -225,7 +190,7 @@ set_tooltip_widget_from_marks (GtkSourceView *view,
                gchar *text;
                gboolean ismarkup = FALSE;
                GtkWidget *label;
-               const GdkPixbuf *pixbuf;
+               GdkPaintable *paintable;
 
                mark = marks->data;
                category = gtk_source_mark_get_category (mark);
@@ -275,23 +240,19 @@ set_tooltip_widget_from_marks (GtkSourceView *view,
                gtk_widget_set_valign (label, GTK_ALIGN_START);
                gtk_widget_show (label);
 
-               pixbuf = gtk_source_mark_attributes_render_icon (attrs,
-                                                                GTK_WIDGET (view),
-                                                                icon_size);
+               paintable = gtk_source_mark_attributes_render_icon (attrs,
+                                                                   GTK_WIDGET (view),
+                                                                   icon_size);
 
-               if (pixbuf == NULL)
+               if (paintable == NULL)
                {
                        gtk_grid_attach (grid, label, 0, row_num, 2, 1);
                }
                else
                {
                        GtkWidget *image;
-                       GdkPixbuf *copy;
 
-                       /* FIXME why a copy is needed? */
-                       copy = gdk_pixbuf_copy (pixbuf);
-                       image = gtk_image_new_from_pixbuf (copy);
-                       g_object_unref (copy);
+                       image = gtk_image_new_from_paintable (paintable);
 
                        gtk_widget_set_halign (image, GTK_ALIGN_START);
                        gtk_widget_set_valign (image, GTK_ALIGN_START);
@@ -329,24 +290,26 @@ set_tooltip_widget_from_marks (GtkSourceView *view,
 }
 
 static gboolean
-gutter_renderer_query_tooltip (GtkSourceGutterRenderer *renderer,
-                               GtkTextIter             *iter,
-                               GdkRectangle            *area,
-                               gint                     x,
-                               gint                     y,
-                               GtkTooltip              *tooltip)
+gutter_renderer_query_tooltip (GtkWidget    *widget,
+                               gint          x,
+                               gint          y,
+                               gboolean      keyboard,
+                               GtkTooltip   *tooltip)
 {
+       GtkSourceGutterRenderer *renderer;
        GSList *marks;
        GtkSourceView *view;
        GtkSourceBuffer *buffer;
+       GtkTextIter iter;
        gboolean ret;
 
+       renderer = GTK_SOURCE_GUTTER_RENDERER (widget);
        view = GTK_SOURCE_VIEW (gtk_source_gutter_renderer_get_view (renderer));
        buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
 
-       marks = gtk_source_buffer_get_source_marks_at_iter (buffer,
-                                                           iter,
-                                                           NULL);
+       gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, 0, y);
+
+       marks = gtk_source_buffer_get_source_marks_at_iter (buffer, &iter, NULL);
 
        if (marks != NULL)
        {
@@ -369,24 +332,24 @@ gutter_renderer_query_tooltip (GtkSourceGutterRenderer *renderer,
 static gboolean
 gutter_renderer_query_activatable (GtkSourceGutterRenderer *renderer,
                                    GtkTextIter             *iter,
-                                   GdkRectangle            *area,
-                                   GdkEvent                *event)
+                                   GdkRectangle            *area)
 {
        return TRUE;
 }
 
 static void
 gutter_renderer_change_view (GtkSourceGutterRenderer *renderer,
-                             GtkTextView             *old_view)
+                            GtkSourceView           *old_view)
 {
        GtkSourceView *view;
 
-       view = GTK_SOURCE_VIEW (gtk_source_gutter_renderer_get_view (renderer));
+       view = gtk_source_gutter_renderer_get_view (renderer);
 
        if (view != NULL)
        {
-               gtk_source_gutter_renderer_set_size (renderer,
-                                                    measure_line_height (view));
+               gtk_widget_set_size_request (GTK_WIDGET (renderer), 
+                                            measure_line_height (view),
+                                            -1);
        }
 
        if (GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_marks_parent_class)->change_view != 
NULL)
@@ -400,9 +363,11 @@ static void
 gtk_source_gutter_renderer_marks_class_init (GtkSourceGutterRendererMarksClass *klass)
 {
        GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       widget_class->query_tooltip = gutter_renderer_query_tooltip;
 
        renderer_class->query_data = gutter_renderer_query_data;
-       renderer_class->query_tooltip = gutter_renderer_query_tooltip;
        renderer_class->query_activatable = gutter_renderer_query_activatable;
        renderer_class->change_view = gutter_renderer_change_view;
 }
diff --git a/gtksourceview/gtksourcegutterrendererpixbuf.c b/gtksourceview/gtksourcegutterrendererpixbuf.c
index 46026886..b7db4bae 100644
--- a/gtksourceview/gtksourcegutterrendererpixbuf.c
+++ b/gtksourceview/gtksourcegutterrendererpixbuf.c
@@ -36,6 +36,8 @@
 typedef struct
 {
        GtkSourcePixbufHelper *helper;
+       GdkPaintable          *paintable;
+       GPtrArray             *overlays;
 } GtkSourceGutterRendererPixbufPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceGutterRendererPixbuf, gtk_source_gutter_renderer_pixbuf, 
GTK_SOURCE_TYPE_GUTTER_RENDERER)
@@ -46,147 +48,80 @@ enum
        PROP_PIXBUF,
        PROP_ICON_NAME,
        PROP_GICON,
+        PROP_PAINTABLE,
 };
 
 static void
-center_on (GtkSourceGutterRenderer *renderer,
-           GdkRectangle            *cell_area,
-           GtkTextIter             *iter,
-           gint                     width,
-           gint                     height,
-           gfloat                   xalign,
-           gfloat                   yalign,
-           gint                    *x,
-           gint                    *y)
+clear_overlays (GtkSourceGutterRendererPixbuf *renderer)
 {
-       GtkTextView *view;
-       GtkTextWindowType window_type;
-       GdkRectangle buffer_location;
-       gint window_y;
-
-       view = gtk_source_gutter_renderer_get_view (renderer);
-       window_type = gtk_source_gutter_renderer_get_window_type (renderer);
-
-       gtk_text_view_get_iter_location (view, iter, &buffer_location);
-
-       gtk_text_view_buffer_to_window_coords (view,
-                                              window_type,
-                                              0, buffer_location.y,
-                                              NULL, &window_y);
+       GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
 
-       *x = cell_area->x + (cell_area->width - width) * xalign;
-       *y = window_y + (buffer_location.height - height) * yalign;
+       if (priv->overlays != NULL && priv->overlays->len > 0)
+       {
+               g_ptr_array_remove_range (priv->overlays, 0, priv->overlays->len);
+       }
 }
 
 static void
-gutter_renderer_pixbuf_draw (GtkSourceGutterRenderer      *renderer,
-                             cairo_t                      *cr,
-                             GdkRectangle                 *background_area,
-                             GdkRectangle                 *cell_area,
-                             GtkTextIter                  *start,
-                             GtkTextIter                  *end,
-                             GtkSourceGutterRendererState  state)
+gutter_renderer_pixbuf_snapshot_line (GtkSourceGutterRenderer      *renderer,
+                                      GtkSnapshot                  *snapshot,
+                                      GtkSourceGutterLines         *lines,
+                                      guint                         line)
 {
        GtkSourceGutterRendererPixbuf *pix = GTK_SOURCE_GUTTER_RENDERER_PIXBUF (renderer);
        GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(pix);
+       GtkWidget *widget = GTK_WIDGET (renderer);
+       GdkPaintable *paintable;
+       GtkSourceView *view;
        gint width;
        gint height;
-       gfloat xalign;
-       gfloat yalign;
-       GtkSourceGutterRendererAlignmentMode mode;
-       GtkTextView *view;
-       gint scale;
-       gint x = 0;
-       gint y = 0;
-       GdkPixbuf *pixbuf;
-       cairo_surface_t *surface;
-
-       /* Chain up to draw background */
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_pixbuf_parent_class)->draw != NULL)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_pixbuf_parent_class)->draw 
(renderer,
-                                                                                                        cr,
-                                                                                                        
background_area,
-                                                                                                        
cell_area,
-                                                                                                        
start,
-                                                                                                        end,
-                                                                                                        
state);
-       }
+       gfloat x = 0;
+       gfloat y = 0;
+       guint i;
+       gint size;
 
        view = gtk_source_gutter_renderer_get_view (renderer);
 
-       pixbuf = gtk_source_pixbuf_helper_render (priv->helper,
-                                                 GTK_WIDGET (view),
-                                                 cell_area->width);
+       width = gtk_widget_get_width (widget);
+       height = gtk_widget_get_height (widget);
+       size = MIN (width, height);
 
-       if (!pixbuf)
-       {
-               return;
-       }
+       paintable = gtk_source_pixbuf_helper_render (priv->helper,
+                                                    GTK_WIDGET (view),
+                                                    size);
 
-       width = gdk_pixbuf_get_width (pixbuf);
-       height = gdk_pixbuf_get_height (pixbuf);
-
-       /*
-        * We might have gotten a pixbuf back from the helper that will allow
-        * us to render for HiDPI. If we detect this, we pretend that we got a
-        * different size back and then gdk_cairo_surface_create_from_pixbuf()
-        * will take care of the rest.
-        */
-       scale = gtk_widget_get_scale_factor (GTK_WIDGET (view));
-       if ((scale > 1) &&
-           ((width > cell_area->width) || (height > cell_area->height)) &&
-           (width <= (cell_area->width * scale)) &&
-           (height <= (cell_area->height * scale)))
+       /* Short-circuit if there is nothing to snapshot */
+       if (paintable == NULL &&
+           (priv->overlays == NULL || priv->overlays->len == 0))
        {
-               width = width / scale;
-               height = height / scale;
+               return;
        }
 
-       gtk_source_gutter_renderer_get_alignment (renderer,
-                                                 &xalign,
-                                                 &yalign);
+       gtk_source_gutter_renderer_align_cell (renderer, line, size, size, &x, &y);
 
-       mode = gtk_source_gutter_renderer_get_alignment_mode (renderer);
+       gtk_snapshot_save (snapshot);
+       gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
 
-       switch (mode)
+       if (paintable != NULL)
        {
-               case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL:
-                       x = cell_area->x + (cell_area->width - width) * xalign;
-                       y = cell_area->y + (cell_area->height - height) * yalign;
-                       break;
-               case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST:
-                       center_on (renderer,
-                                  cell_area,
-                                  start,
-                                  width,
-                                  height,
-                                  xalign,
-                                  yalign,
-                                  &x,
-                                  &y);
-                       break;
-               case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_LAST:
-                       center_on (renderer,
-                                  cell_area,
-                                  end,
-                                  width,
-                                  height,
-                                  xalign,
-                                  yalign,
-                                  &x,
-                                  &y);
-                       break;
-               default:
-                       g_assert_not_reached ();
+               gdk_paintable_snapshot (paintable, snapshot, size, size);
+       }
+       else if (priv->paintable != NULL)
+       {
+               gdk_paintable_snapshot (priv->paintable, snapshot, size, size);
        }
 
-       surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL);
-       cairo_set_source_surface (cr, surface, x, y);
+       if (priv->overlays != NULL)
+       {
+               for (i = 0; i < priv->overlays->len; i++)
+               {
+                       GdkPaintable *ele = g_ptr_array_index (priv->overlays, i);
 
-       cairo_paint (cr);
+                       gdk_paintable_snapshot (ele, snapshot, size, size);
+               }
+       }
 
-       cairo_surface_destroy (surface);
+       gtk_snapshot_restore (snapshot);
 }
 
 static void
@@ -195,7 +130,8 @@ gtk_source_gutter_renderer_pixbuf_finalize (GObject *object)
        GtkSourceGutterRendererPixbuf *renderer = GTK_SOURCE_GUTTER_RENDERER_PIXBUF (object);
        GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
 
-       gtk_source_pixbuf_helper_free (priv->helper);
+        g_clear_pointer (&priv->helper, gtk_source_pixbuf_helper_free);
+        g_clear_pointer (&priv->overlays, g_ptr_array_unref);
 
        G_OBJECT_CLASS (gtk_source_gutter_renderer_pixbuf_parent_class)->finalize (object);
 }
@@ -206,11 +142,9 @@ set_pixbuf (GtkSourceGutterRendererPixbuf *renderer,
 {
        GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
 
+        g_clear_object (&priv->paintable);
+        clear_overlays (renderer);
        gtk_source_pixbuf_helper_set_pixbuf (priv->helper, pixbuf);
-
-       g_object_notify (G_OBJECT (renderer), "pixbuf");
-
-       gtk_source_gutter_renderer_queue_draw (GTK_SOURCE_GUTTER_RENDERER (renderer));
 }
 
 static void
@@ -219,11 +153,9 @@ set_gicon (GtkSourceGutterRendererPixbuf *renderer,
 {
        GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
 
+        g_clear_object (&priv->paintable);
+        clear_overlays (renderer);
        gtk_source_pixbuf_helper_set_gicon (priv->helper, icon);
-
-       g_object_notify (G_OBJECT (renderer), "gicon");
-
-       gtk_source_gutter_renderer_queue_draw (GTK_SOURCE_GUTTER_RENDERER (renderer));
 }
 
 static void
@@ -232,11 +164,9 @@ set_icon_name (GtkSourceGutterRendererPixbuf *renderer,
 {
        GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
 
+        g_clear_object (&priv->paintable);
+        clear_overlays (renderer);
        gtk_source_pixbuf_helper_set_icon_name (priv->helper, icon_name);
-
-       g_object_notify (G_OBJECT (renderer), "icon-name");
-
-       gtk_source_gutter_renderer_queue_draw (GTK_SOURCE_GUTTER_RENDERER (renderer));
 }
 
 
@@ -246,9 +176,7 @@ gtk_source_gutter_renderer_pixbuf_set_property (GObject      *object,
                                                 const GValue *value,
                                                 GParamSpec   *pspec)
 {
-       GtkSourceGutterRendererPixbuf *renderer;
-
-       renderer = GTK_SOURCE_GUTTER_RENDERER_PIXBUF (object);
+       GtkSourceGutterRendererPixbuf *renderer = GTK_SOURCE_GUTTER_RENDERER_PIXBUF (object);
 
        switch (prop_id)
        {
@@ -261,6 +189,10 @@ gtk_source_gutter_renderer_pixbuf_set_property (GObject      *object,
                case PROP_GICON:
                        set_gicon (renderer, g_value_get_object (value));
                        break;
+               case PROP_PAINTABLE:
+                       gtk_source_gutter_renderer_pixbuf_set_paintable (renderer,
+                                                                        g_value_get_object (value));
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -290,6 +222,9 @@ gtk_source_gutter_renderer_pixbuf_get_property (GObject    *object,
                        g_value_set_object (value,
                                            gtk_source_pixbuf_helper_get_gicon (priv->helper));
                        break;
+               case PROP_PAINTABLE:
+                       g_value_set_object (value, priv->paintable);
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -303,11 +238,18 @@ gtk_source_gutter_renderer_pixbuf_class_init (GtkSourceGutterRendererPixbufClass
        GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass);
 
        object_class->finalize = gtk_source_gutter_renderer_pixbuf_finalize;
-
        object_class->get_property = gtk_source_gutter_renderer_pixbuf_get_property;
        object_class->set_property = gtk_source_gutter_renderer_pixbuf_set_property;
 
-       renderer_class->draw = gutter_renderer_pixbuf_draw;
+       renderer_class->snapshot_line = gutter_renderer_pixbuf_snapshot_line;
+
+       g_object_class_install_property (object_class,
+                                        PROP_PAINTABLE,
+                                        g_param_spec_object ("paintable",
+                                                             "Paintable",
+                                                             "The paintable",
+                                                             GDK_TYPE_PAINTABLE,
+                                                             G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
 
        g_object_class_install_property (object_class,
                                         PROP_PIXBUF,
@@ -315,7 +257,7 @@ gtk_source_gutter_renderer_pixbuf_class_init (GtkSourceGutterRendererPixbufClass
                                                              "Pixbuf",
                                                              "The pixbuf",
                                                              GDK_TYPE_PIXBUF,
-                                                             G_PARAM_READWRITE));
+                                                             G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
 
        g_object_class_install_property (object_class,
                                         PROP_ICON_NAME,
@@ -323,7 +265,7 @@ gtk_source_gutter_renderer_pixbuf_class_init (GtkSourceGutterRendererPixbufClass
                                                              "Icon Name",
                                                              "The icon name",
                                                              NULL,
-                                                             G_PARAM_READWRITE));
+                                                             G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
 
        g_object_class_install_property (object_class,
                                         PROP_GICON,
@@ -331,7 +273,7 @@ gtk_source_gutter_renderer_pixbuf_class_init (GtkSourceGutterRendererPixbufClass
                                                              "GIcon",
                                                              "The gicon",
                                                              G_TYPE_ICON,
-                                                             G_PARAM_READWRITE));
+                                                             G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -448,3 +390,71 @@ gtk_source_gutter_renderer_pixbuf_get_icon_name (GtkSourceGutterRendererPixbuf *
 
        return gtk_source_pixbuf_helper_get_icon_name (priv->helper);
 }
+
+/**
+ * gtk_source_gutter_renderer_pixbuf_set_paintable:
+ * @renderer: a #GtkSourceGutterRendererPixbuf
+ * @paintable: (nullable): the paintable, or %NULL.
+ */
+void
+gtk_source_gutter_renderer_pixbuf_set_paintable (GtkSourceGutterRendererPixbuf *renderer,
+                                                 GdkPaintable                  *paintable)
+{
+       GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
+
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER_PIXBUF (renderer));
+       g_return_if_fail (!paintable || GDK_IS_PAINTABLE (paintable));
+
+       clear_overlays (renderer);
+       gtk_source_pixbuf_helper_set_icon_name (priv->helper, NULL);
+       g_set_object (&priv->paintable, paintable);
+}
+
+/**
+ * gtk_source_gutter_renderer_pixbuf_get_paintable:
+ * @renderer: a #GtkSourceGutterRendererPixbuf
+ *
+ * Gets a #GdkPaintable that was set with
+ * gtk_source_gutter_renderer_pixbuf_set_paintable()
+ *
+ * Returns: (transfer none) (nullable): a #GdkPaintable or %NULL
+ *
+ * Since: 5.0
+ */
+GdkPaintable *
+gtk_source_gutter_renderer_pixbuf_get_paintable (GtkSourceGutterRendererPixbuf *renderer)
+{
+       GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
+
+       g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER_PIXBUF (renderer), NULL);
+
+       return priv->paintable;
+}
+
+/**
+ * gtk_source_gutter_renderer_pixbuf_overlay_paintable:
+ * @renderer: a #GtkSourceGutterRendererPixbuf
+ * @paintable: a #GdkPaintable
+ *
+ * Allows overlaying a paintable on top of any other image that
+ * has been set for the pixbuf. This will be applied when the
+ * widget is next snapshot.
+ *
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_renderer_pixbuf_overlay_paintable (GtkSourceGutterRendererPixbuf *renderer,
+                                                     GdkPaintable                  *paintable)
+{
+       GtkSourceGutterRendererPixbufPrivate *priv = gtk_source_gutter_renderer_pixbuf_get_instance_private 
(renderer);
+
+       g_return_if_fail (GTK_SOURCE_IS_GUTTER_RENDERER_PIXBUF (renderer));
+       g_return_if_fail (GDK_IS_PAINTABLE (paintable));
+
+       if (priv->overlays == NULL)
+       {
+               priv->overlays = g_ptr_array_new_with_free_func (g_object_unref);
+       }
+
+       g_ptr_array_add (priv->overlays, g_object_ref (paintable));
+}
diff --git a/gtksourceview/gtksourcegutterrendererpixbuf.h b/gtksourceview/gtksourcegutterrendererpixbuf.h
index ee82b6a4..5bb1f289 100644
--- a/gtksourceview/gtksourcegutterrendererpixbuf.h
+++ b/gtksourceview/gtksourcegutterrendererpixbuf.h
@@ -43,21 +43,29 @@ struct _GtkSourceGutterRendererPixbufClass
 };
 
 GTK_SOURCE_AVAILABLE_IN_ALL
-GtkSourceGutterRenderer *gtk_source_gutter_renderer_pixbuf_new           (void);
+GtkSourceGutterRenderer *gtk_source_gutter_renderer_pixbuf_new               (void);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                     gtk_source_gutter_renderer_pixbuf_set_pixbuf    (GtkSourceGutterRendererPixbuf 
*renderer,
-                                                                          GdkPixbuf                     
*pixbuf);
+void                     gtk_source_gutter_renderer_pixbuf_set_pixbuf        (GtkSourceGutterRendererPixbuf 
*renderer,
+                                                                              GdkPixbuf                     
*pixbuf);
 GTK_SOURCE_AVAILABLE_IN_ALL
-GdkPixbuf               *gtk_source_gutter_renderer_pixbuf_get_pixbuf    (GtkSourceGutterRendererPixbuf 
*renderer);
+GdkPixbuf               *gtk_source_gutter_renderer_pixbuf_get_pixbuf        (GtkSourceGutterRendererPixbuf 
*renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                     gtk_source_gutter_renderer_pixbuf_set_gicon     (GtkSourceGutterRendererPixbuf 
*renderer,
-                                                                          GIcon                         
*icon);
+void                     gtk_source_gutter_renderer_pixbuf_set_gicon         (GtkSourceGutterRendererPixbuf 
*renderer,
+                                                                              GIcon                         
*icon);
 GTK_SOURCE_AVAILABLE_IN_ALL
-GIcon                   *gtk_source_gutter_renderer_pixbuf_get_gicon     (GtkSourceGutterRendererPixbuf 
*renderer);
+GIcon                   *gtk_source_gutter_renderer_pixbuf_get_gicon         (GtkSourceGutterRendererPixbuf 
*renderer);
 GTK_SOURCE_AVAILABLE_IN_ALL
-void                     gtk_source_gutter_renderer_pixbuf_set_icon_name (GtkSourceGutterRendererPixbuf 
*renderer,
-                                                                          const gchar                   
*icon_name);
+void                     gtk_source_gutter_renderer_pixbuf_set_icon_name     (GtkSourceGutterRendererPixbuf 
*renderer,
+                                                                              const gchar                   
*icon_name);
 GTK_SOURCE_AVAILABLE_IN_ALL
-const gchar             *gtk_source_gutter_renderer_pixbuf_get_icon_name (GtkSourceGutterRendererPixbuf 
*renderer);
+const gchar             *gtk_source_gutter_renderer_pixbuf_get_icon_name     (GtkSourceGutterRendererPixbuf 
*renderer);
+GTK_SOURCE_AVAILABLE_IN_ALL
+GdkPaintable            *gtk_source_gutter_renderer_pixbuf_get_paintable     (GtkSourceGutterRendererPixbuf 
*renderer);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void                     gtk_source_gutter_renderer_pixbuf_set_paintable     (GtkSourceGutterRendererPixbuf 
*renderer,
+                                                                              GdkPaintable                  
*paintable);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void                     gtk_source_gutter_renderer_pixbuf_overlay_paintable (GtkSourceGutterRendererPixbuf 
*renderer,
+                                                                              GdkPaintable                  
*paintable);
 
 G_END_DECLS
diff --git a/gtksourceview/gtksourcegutterrenderertext.c b/gtksourceview/gtksourcegutterrenderertext.c
index c8085afe..82891803 100644
--- a/gtksourceview/gtksourcegutterrenderertext.c
+++ b/gtksourceview/gtksourcegutterrenderertext.c
@@ -34,11 +34,11 @@
 
 typedef struct
 {
-       gchar *text;
-
+       gchar       *text;
        PangoLayout *cached_layout;
-
-       guint is_markup : 1;
+       GdkRGBA      cached_color;
+       gsize        text_len;
+       guint        is_markup : 1;
 } GtkSourceGutterRendererTextPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceGutterRendererText, gtk_source_gutter_renderer_text, 
GTK_SOURCE_TYPE_GUTTER_RENDERER)
@@ -47,171 +47,89 @@ enum
 {
        PROP_0,
        PROP_MARKUP,
-       PROP_TEXT
+       PROP_TEXT,
+       N_PROPS
 };
 
 static void
-gutter_renderer_text_begin (GtkSourceGutterRenderer *renderer,
-                            cairo_t                 *cr,
-                            GdkRectangle            *background_area,
-                            GdkRectangle            *cell_area,
-                            GtkTextIter             *start,
-                            GtkTextIter             *end)
+gtk_source_gutter_renderer_text_begin (GtkSourceGutterRenderer *renderer,
+                                       GtkSourceGutterLines    *lines)
 {
+
        GtkSourceGutterRendererText *text = GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer);
        GtkSourceGutterRendererTextPrivate *priv = gtk_source_gutter_renderer_text_get_instance_private 
(text);
-       GtkTextView *view;
 
-       view = gtk_source_gutter_renderer_get_view (renderer);
+       GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->begin (renderer, 
lines);
 
        g_clear_object (&priv->cached_layout);
-       priv->cached_layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL);
-
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->begin != NULL)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->begin 
(renderer,
-                                                                                                       cr,
-                                                                                                       
background_area,
-                                                                                                       
cell_area,
-                                                                                                       start,
-                                                                                                       end);
-       }
-}
-
-static void
-center_on (GtkTextView  *view,
-           GdkRectangle *cell_area,
-           GtkTextIter  *iter,
-           gint          width,
-           gint          height,
-           gfloat        xalign,
-           gfloat        yalign,
-           gint         *x,
-           gint         *y)
-{
-       GdkRectangle location;
-
-       gtk_text_view_get_iter_location (view, iter, &location);
-
-       *x = cell_area->x + (cell_area->width - width) * xalign;
-       *y = cell_area->y + (location.height - height) * yalign;
+       priv->cached_layout = gtk_widget_create_pango_layout (GTK_WIDGET (renderer), NULL);
 }
 
 static void
-gutter_renderer_text_draw (GtkSourceGutterRenderer      *renderer,
-                           cairo_t                      *cr,
-                           GdkRectangle                 *background_area,
-                           GdkRectangle                 *cell_area,
-                           GtkTextIter                  *start,
-                           GtkTextIter                  *end,
-                           GtkSourceGutterRendererState  state)
+gtk_source_gutter_renderer_text_snapshot_line (GtkSourceGutterRenderer *renderer,
+                                               GtkSnapshot             *snapshot,
+                                               GtkSourceGutterLines    *lines,
+                                               guint                    line)
 {
        GtkSourceGutterRendererText *text = GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer);
        GtkSourceGutterRendererTextPrivate *priv = gtk_source_gutter_renderer_text_get_instance_private 
(text);
-       GtkTextView *view;
+       PangoLayout *layout;
+       gfloat x;
+       gfloat y;
        gint width;
        gint height;
-       gfloat xalign;
-       gfloat yalign;
-       GtkSourceGutterRendererAlignmentMode mode;
-       gint x = 0;
-       gint y = 0;
-       GtkStyleContext *context;
-
-       /* Chain up to draw background */
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->draw != NULL)
+
+       if (priv->text == NULL || priv->text_len == 0)
        {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->draw 
(renderer,
-                                                                                                      cr,
-                                                                                                      
background_area,
-                                                                                                      
cell_area,
-                                                                                                      start,
-                                                                                                      end,
-                                                                                                      state);
+               return;
        }
 
-       view = gtk_source_gutter_renderer_get_view (renderer);
+       layout = priv->cached_layout;
 
        if (priv->is_markup)
        {
-               pango_layout_set_markup (priv->cached_layout,
+               pango_layout_set_markup (layout,
                                         priv->text,
-                                        -1);
+                                        priv->text_len);
        }
        else
        {
-               pango_layout_set_text (priv->cached_layout,
+               pango_layout_set_text (layout,
                                       priv->text,
-                                      -1);
+                                      priv->text_len);
        }
 
-       pango_layout_get_pixel_size (priv->cached_layout, &width, &height);
+       pango_layout_get_pixel_size (layout, &width, &height);
 
-       gtk_source_gutter_renderer_get_alignment (renderer,
-                                                 &xalign,
-                                                 &yalign);
+       gtk_source_gutter_renderer_align_cell (renderer,
+                                              line,
+                                              width,
+                                              height,
+                                              &x,
+                                              &y);
 
-       /* Avoid calculations if we don't wrap text */
-       if (gtk_text_view_get_wrap_mode (view) == GTK_WRAP_NONE)
-       {
-               mode = GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL;
-       }
-       else
-       {
-               mode = gtk_source_gutter_renderer_get_alignment_mode (renderer);
-       }
+       gtk_snapshot_render_layout (snapshot,
+                                   gtk_widget_get_style_context (GTK_WIDGET (text)),
+                                   x,
+                                   y,
+                                   layout);
 
-       switch (mode)
+       if (priv->is_markup)
        {
-               case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL:
-                       x = cell_area->x + (cell_area->width - width) * xalign;
-                       y = cell_area->y + (cell_area->height - height) * yalign;
-                       break;
-
-               case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST:
-                       center_on (view,
-                                  cell_area,
-                                  start,
-                                  width,
-                                  height,
-                                  xalign,
-                                  yalign,
-                                  &x,
-                                  &y);
-                       break;
-
-               case GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_LAST:
-                       center_on (view,
-                                  cell_area,
-                                  end,
-                                  width,
-                                  height,
-                                  xalign,
-                                  yalign,
-                                  &x,
-                                  &y);
-                       break;
-
-               default:
-                       g_assert_not_reached ();
+               pango_layout_set_attributes (layout, NULL);
        }
-
-       context = gtk_widget_get_style_context (GTK_WIDGET (view));
-       gtk_render_layout (context, cr, x, y, priv->cached_layout);
 }
 
 static void
-gutter_renderer_text_end (GtkSourceGutterRenderer *renderer)
+gtk_source_gutter_renderer_text_end (GtkSourceGutterRenderer *renderer)
 {
+
        GtkSourceGutterRendererText *text = GTK_SOURCE_GUTTER_RENDERER_TEXT (renderer);
        GtkSourceGutterRendererTextPrivate *priv = gtk_source_gutter_renderer_text_get_instance_private 
(text);
 
-       g_clear_object (&priv->cached_layout);
+       GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->end (renderer);
 
-       if (GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->end != NULL)
-       {
-               GTK_SOURCE_GUTTER_RENDERER_CLASS (gtk_source_gutter_renderer_text_parent_class)->end 
(renderer);
-       }
+       g_clear_object (&priv->cached_layout);
 }
 
 static void
@@ -221,7 +139,7 @@ measure_text (GtkSourceGutterRendererText *renderer,
               gint                        *width,
               gint                        *height)
 {
-       GtkTextView *view;
+       GtkSourceView *view;
        PangoLayout *layout;
 
        view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (renderer));
@@ -290,13 +208,53 @@ gtk_source_gutter_renderer_text_measure_markup (GtkSourceGutterRendererText *ren
        measure_text (renderer, markup, NULL, width, height);
 }
 
+static void
+gtk_source_gutter_renderer_text_real_measure (GtkWidget      *widget,
+                                              GtkOrientation  orientation,
+                                              int             for_size,
+                                              int            *minimum,
+                                              int            *natural,
+                                              int            *minimum_baseline,
+                                              int            *natural_baseline)
+{
+       GtkSourceGutterRendererText *renderer = GTK_SOURCE_GUTTER_RENDERER_TEXT (widget);
+       GtkSourceGutterRendererTextPrivate *priv = gtk_source_gutter_renderer_text_get_instance_private 
(renderer);
+
+       *minimum = 0;
+       *natural = 0;
+       *minimum_baseline = -1;
+       *natural_baseline = -1;
+
+       if (orientation == GTK_ORIENTATION_HORIZONTAL)
+       {
+               gint xpad = gtk_source_gutter_renderer_get_xpad (GTK_SOURCE_GUTTER_RENDERER (renderer));
+               gint width = 0;
+               gint height = 0;
+
+               if (priv->text != NULL)
+               {
+                       if (priv->is_markup)
+                       {
+                               measure_text (renderer, priv->text, NULL, &width, &height);
+                       }
+                       else
+                       {
+                               measure_text (renderer, NULL, priv->text, &width, &height);
+                       }
+               }
+
+               *natural = *minimum = width + 2 * xpad;
+       }
+
+}
+
 static void
 gtk_source_gutter_renderer_text_finalize (GObject *object)
 {
        GtkSourceGutterRendererText *renderer = GTK_SOURCE_GUTTER_RENDERER_TEXT (object);
        GtkSourceGutterRendererTextPrivate *priv = gtk_source_gutter_renderer_text_get_instance_private 
(renderer);
 
-       g_free (priv->text);
+       g_clear_pointer (&priv->text, g_free);
        g_clear_object (&priv->cached_layout);
 
        G_OBJECT_CLASS (gtk_source_gutter_renderer_text_parent_class)->finalize (object);
@@ -312,8 +270,18 @@ set_text (GtkSourceGutterRendererText *renderer,
 
        g_free (priv->text);
 
-       priv->text = length >= 0 ? g_strndup (text, length) : g_strdup (text);
-       priv->is_markup = is_markup;
+       if (text == NULL)
+       {
+               priv->text_len = 0;
+               priv->text = NULL;
+               priv->is_markup = FALSE;
+       }
+       else
+       {
+               priv->text_len = length >= 0 ? length : strlen (text);
+               priv->text = g_strndup (text, priv->text_len);
+               priv->is_markup = !!is_markup;
+       }
 }
 
 static void
@@ -322,9 +290,7 @@ gtk_source_gutter_renderer_text_set_property (GObject      *object,
                                               const GValue *value,
                                               GParamSpec   *pspec)
 {
-       GtkSourceGutterRendererText *renderer;
-
-       renderer = GTK_SOURCE_GUTTER_RENDERER_TEXT (object);
+       GtkSourceGutterRendererText *renderer = GTK_SOURCE_GUTTER_RENDERER_TEXT (object);
 
        switch (prop_id)
        {
@@ -367,16 +333,18 @@ static void
 gtk_source_gutter_renderer_text_class_init (GtkSourceGutterRendererTextClass *klass)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
        GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass);
 
        object_class->finalize = gtk_source_gutter_renderer_text_finalize;
-
        object_class->get_property = gtk_source_gutter_renderer_text_get_property;
        object_class->set_property = gtk_source_gutter_renderer_text_set_property;
 
-       renderer_class->begin = gutter_renderer_text_begin;
-       renderer_class->draw = gutter_renderer_text_draw;
-       renderer_class->end = gutter_renderer_text_end;
+       widget_class->measure = gtk_source_gutter_renderer_text_real_measure;
+
+       renderer_class->begin = gtk_source_gutter_renderer_text_begin;
+       renderer_class->end = gtk_source_gutter_renderer_text_end;
+       renderer_class->snapshot_line = gtk_source_gutter_renderer_text_snapshot_line;
 
        g_object_class_install_property (object_class,
                                         PROP_MARKUP,


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