[gnome-builder/wip/chergert/gutter] wip



commit d108d07d41475ebfaafad6e486ea69b503f07428
Author: Christian Hergert <chergert redhat com>
Date:   Sun Sep 17 03:39:02 2017 -0700

    wip

 data/style-schemes/builder-dark.xml                |    4 +-
 data/style-schemes/builder.xml                     |    5 +-
 libide/debugger/ide-debugger-editor-view-addin.c   |  135 ---
 libide/debugger/ide-debugger-plugin.c              |    4 -
 libide/meson.build                                 |    4 +-
 libide/sourceview/ide-omni-gutter-renderer.c       | 1176 ++++++++++++++++++++
 .../ide-omni-gutter-renderer.h}                    |   15 +-
 libide/sourceview/ide-source-view.c                |   60 +-
 8 files changed, 1213 insertions(+), 190 deletions(-)
---
diff --git a/data/style-schemes/builder-dark.xml b/data/style-schemes/builder-dark.xml
index 6b00aef..814c913 100644
--- a/data/style-schemes/builder-dark.xml
+++ b/data/style-schemes/builder-dark.xml
@@ -81,8 +81,8 @@
   <style name="snippet::area"               background="#rgba(86,114,151,.5)"/>
 
   <!-- Debugger -->
-  <style
-    name="debugger::current-breakpoint"     foreground="#2e3436" background="#fcaf3e"/>
+  <style name="debugger::current-breakpoint" foreground="#2e3436" background="#fcaf3e"/>
+  <style name="debugger::breakpoint"         foreground="#ffffff" background="#204a87"/>
 
   <!-- Hover links -->
   <style name="action::hover-definition"    background="#41464c" underline="true"/>
diff --git a/data/style-schemes/builder.xml b/data/style-schemes/builder.xml
index 4f4eead..2abf4f4 100644
--- a/data/style-schemes/builder.xml
+++ b/data/style-schemes/builder.xml
@@ -76,7 +76,7 @@
   <style name="map-overlay"                 background="#rgba(193,203,210,0.55)"/>
   <style name="cursor"                      foreground="aluminium4"/>
   <style name="current-line"                background="#rgba(238,238,236,.75)"/>
-  <style name="current-line-number"         background="#rgba(238,238,236,.75)"/>
+  <style name="current-line-number"         background="#rgba(238,238,236,.75)" bold="true"/>
   <style name="draw-spaces"                 foreground="aluminium3"/>
   <style name="line-numbers"                foreground="line1" background="bg1"/>
   <style name="background-pattern"          background="#rgba(.125,.125,.125,.025)"/>
@@ -87,6 +87,9 @@
   <style name="diagnostician::note"         underline="error" underline-color="blue1"/>
   <style name="diagnostician::warning"      underline="error" underline-color="orange1"/>
 
+  <!-- Debugger -->
+  <style name="debugger::breakpoint"        background="#4a90d9" foreground="#ffffff"/>
+
   <!-- Snippets -->
   <style name="snippet::tab-stop"           background="#fcaf3e" foreground="text1"/>
   <style name="snippet::area"               background="#rgba(32,74,135,.1)"/>
diff --git a/libide/debugger/ide-debugger-plugin.c b/libide/debugger/ide-debugger-plugin.c
index 6ecb5a6..5feb415 100644
--- a/libide/debugger/ide-debugger-plugin.c
+++ b/libide/debugger/ide-debugger-plugin.c
@@ -19,7 +19,6 @@
 #include <libpeas/peas.h>
 
 #include "debugger/ide-debugger-editor-addin.h"
-#include "debugger/ide-debugger-editor-view-addin.h"
 #include "editor/ide-editor-addin.h"
 #include "editor/ide-editor-view-addin.h"
 
@@ -29,7 +28,4 @@ ide_debugger_register_types (PeasObjectModule *module)
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_EDITOR_ADDIN,
                                               IDE_TYPE_DEBUGGER_EDITOR_ADDIN);
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_EDITOR_VIEW_ADDIN,
-                                              IDE_TYPE_DEBUGGER_EDITOR_VIEW_ADDIN);
 }
diff --git a/libide/meson.build b/libide/meson.build
index acec572..ff0d242 100644
--- a/libide/meson.build
+++ b/libide/meson.build
@@ -517,8 +517,6 @@ libide_sources = libide_generated_headers + libide_public_sources + [
   'debugger/ide-debugger-disassembly-view.h',
   'debugger/ide-debugger-editor-addin.c',
   'debugger/ide-debugger-editor-addin.h',
-  'debugger/ide-debugger-editor-view-addin.c',
-  'debugger/ide-debugger-editor-view-addin.h',
   'debugger/ide-debugger-fallbacks.c',
   'debugger/ide-debugger-gutter-renderer.c',
   'debugger/ide-debugger-gutter-renderer.h',
@@ -595,6 +593,8 @@ libide_sources = libide_generated_headers + libide_public_sources + [
   'snippets/ide-source-snippet-parser.c',
   'snippets/ide-source-snippet-parser.h',
   'snippets/ide-source-snippet-private.h',
+  'sourceview/ide-omni-gutter-renderer.c',
+  'sourceview/ide-omni-gutter-renderer.h',
   'sourceview/ide-line-change-gutter-renderer.c',
   'sourceview/ide-line-change-gutter-renderer.h',
   'sourceview/ide-line-diagnostics-gutter-renderer.c',
diff --git a/libide/sourceview/ide-omni-gutter-renderer.c b/libide/sourceview/ide-omni-gutter-renderer.c
new file mode 100644
index 0000000..5db2bd8
--- /dev/null
+++ b/libide/sourceview/ide-omni-gutter-renderer.c
@@ -0,0 +1,1176 @@
+/* ide-omni-gutter-renderer.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-omni-gutter-renderer"
+
+#include <dazzle.h>
+#include <string.h>
+
+#include "ide-context.h"
+#include "ide-debug.h"
+
+#include "buffers/ide-buffer.h"
+#include "debugger/ide-debug-manager.h"
+#include "debugger/ide-debugger-breakpoint.h"
+#include "debugger/ide-debugger-breakpoints.h"
+#include "debugger/ide-debugger-private.h"
+#include "files/ide-file.h"
+#include "sourceview/ide-omni-gutter-renderer.h"
+#include "sourceview/ide-source-view.h"
+
+#define DIAGNOSTICS_SIZE 16
+#define ARROW_WIDTH      7
+#define CHANGE_WIDTH     2
+
+#define IS_BREAKPOINT(i) ((i)->is_breakpoint || (i)->is_countpoint || (i)->is_watchpoint)
+#define IS_DIAGNOSTIC(i) ((i)->is_error || (i)->is_warning || (i)->is_note)
+
+struct _IdeOmniGutterRenderer
+{
+  GtkSourceGutterRenderer parent_instance;
+
+  IdeDebuggerBreakpoints *breakpoints;
+
+  GArray *lines;
+  guint begin_line;
+
+  DzlSignalGroup *view_signals;
+  DzlSignalGroup *buffer_signals;
+
+  cairo_surface_t *note_surface;
+  cairo_surface_t *warning_surface;
+  cairo_surface_t *error_surface;
+  cairo_surface_t *note_selected_surface;
+  cairo_surface_t *warning_selected_surface;
+  cairo_surface_t *error_selected_surface;
+
+  struct {
+    GdkRGBA fg;
+    GdkRGBA bg;
+    gboolean bold;
+  } text, current, bkpt;
+
+  GdkRGBA stopped_bg;
+
+  struct {
+    GdkRGBA add;
+    GdkRGBA remove;
+    GdkRGBA change;
+  } changes;
+
+  PangoLayout *layout;
+  PangoAttrList *bold_attrs;
+
+  guint n_chars;
+
+  gint stopped_line;
+
+  guint resize_source;
+
+  int  number_width;
+};
+
+enum {
+  FOREGROUND,
+  BACKGROUND,
+};
+
+typedef struct
+{
+  guint is_breakpoint : 1;
+  guint is_countpoint : 1;
+  guint is_watchpoint : 1;
+  guint is_add : 1;
+  guint is_change : 1;
+  guint is_delete : 1;
+  guint is_warning : 1;
+  guint is_note : 1;
+  guint is_error : 1;
+} LineInfo;
+
+G_DEFINE_TYPE (IdeOmniGutterRenderer, ide_omni_gutter_renderer, GTK_SOURCE_TYPE_GUTTER_RENDERER)
+
+static GdkRGBA rgbaAdded;
+static GdkRGBA rgbaChanged;
+static GdkRGBA rgbaRemoved;
+
+static gboolean
+get_style_boolean (GtkSourceStyleScheme *scheme,
+                   const gchar          *style_name,
+                   const gchar          *property,
+                   gboolean             *val)
+{
+  GtkSourceStyle *style;
+
+  g_assert (!scheme || GTK_SOURCE_IS_STYLE_SCHEME (scheme));
+  g_assert (style_name != NULL);
+  g_assert (property != NULL);
+  g_assert (val != NULL);
+
+  *val = FALSE;
+
+  if (scheme == NULL)
+    return FALSE;
+
+  style = gtk_source_style_scheme_get_style (scheme, style_name);
+
+  if (style != NULL)
+    {
+      g_object_get (style, property, val, NULL);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+get_style_rgba (GtkSourceStyleScheme *scheme,
+                const gchar          *style_name,
+                int                   type,
+                GdkRGBA              *rgba)
+{
+  GtkSourceStyle *style;
+
+  g_assert (!scheme || GTK_SOURCE_IS_STYLE_SCHEME (scheme));
+  g_assert (style_name != NULL);
+  g_assert (type == FOREGROUND || type == BACKGROUND);
+  g_assert (rgba != NULL);
+
+  memset (rgba, 0, sizeof *rgba);
+
+  if (scheme == NULL)
+    return FALSE;
+
+  style = gtk_source_style_scheme_get_style (scheme, style_name);
+
+  if (style != NULL)
+    {
+      g_autofree gchar *str = NULL;
+      gboolean set = FALSE;
+
+      g_object_get (style,
+                    type ? "background" : "foreground", &str,
+                    type ? "background-set" : "foreground-set", &set,
+                    NULL);
+
+      if (str != NULL && set)
+        {
+          gdk_rgba_parse (rgba, str);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+reload_style_colors (IdeOmniGutterRenderer *self,
+                     GtkSourceStyleScheme  *scheme)
+{
+  GtkStyleContext *context;
+  GtkTextView *view;
+  GtkStateFlags state;
+  GdkRGBA fg;
+  GdkRGBA bg;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (!scheme || GTK_SOURCE_IS_STYLE_SCHEME (scheme));
+
+  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));
+  if (view == NULL)
+    return;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (view));
+  state = gtk_style_context_get_state (context);
+  gtk_style_context_get_color (context, state, &fg);
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+  gtk_style_context_get_background_color (context, state, &bg);
+  G_GNUC_END_IGNORE_DEPRECATIONS;
+
+  if (!get_style_rgba (scheme, "line-numbers", FOREGROUND, &self->text.fg))
+    self->text.fg = fg;
+
+  if (!get_style_rgba (scheme, "line-numbers", BACKGROUND, &self->text.bg))
+    self->text.bg = bg;
+
+  if (!get_style_boolean (scheme, "line-numbers", "bold", &self->text.bold))
+    self->text.bold = FALSE;
+
+  if (!get_style_rgba (scheme, "current-line-number", FOREGROUND, &self->current.fg))
+    self->current.fg = fg;
+
+  if (!get_style_rgba (scheme, "current-line-number", BACKGROUND, &self->current.bg))
+    self->current.bg = bg;
+
+  if (!get_style_boolean (scheme, "current-line-number", "bold", &self->current.bold))
+    self->current.bold = FALSE;
+
+  if (!get_style_rgba (scheme, "debugger::current-breakpoint", BACKGROUND, &self->stopped_bg))
+    gdk_rgba_parse (&self->stopped_bg, "#fcaf3e");
+
+  if (!get_style_rgba (scheme, "debugger::breakpoint", FOREGROUND, &self->bkpt.fg))
+    get_style_rgba (scheme, "selection", FOREGROUND, &self->bkpt.fg);
+
+  if (!get_style_rgba (scheme, "debugger::breakpoint", BACKGROUND, &self->bkpt.bg))
+    get_style_rgba (scheme, "selection", BACKGROUND, &self->bkpt.bg);
+
+  if (!get_style_boolean (scheme, "debugger::breakpoint", "bold", &self->bkpt.bold))
+    self->bkpt.bold = FALSE;
+
+  if (!get_style_rgba (scheme, "gutter::added-line", FOREGROUND, &self->changes.add))
+    gdk_rgba_parse (&self->changes.add, "#8ae234");
+
+  if (!get_style_rgba (scheme, "gutter::changed-line", FOREGROUND, &self->changes.change))
+    gdk_rgba_parse (&self->changes.change, "#fcaf3e");
+
+  if (!get_style_rgba (scheme, "gutter::removed-line", FOREGROUND, &self->changes.remove))
+    gdk_rgba_parse (&self->changes.remove, "#ef2929");
+}
+
+static void
+collect_breakpoint_info (IdeDebuggerBreakpoint *breakpoint,
+                         gpointer               user_data)
+{
+  struct {
+    GArray *lines;
+    guint begin;
+    guint end;
+  } *bkpt_info = user_data;
+  guint line;
+
+  if (!(line = ide_debugger_breakpoint_get_line (breakpoint)))
+    return;
+
+  line--;
+
+  if (line >= bkpt_info->begin && line <= bkpt_info->end)
+    {
+      IdeDebuggerBreakMode mode = ide_debugger_breakpoint_get_mode (breakpoint);
+      LineInfo *info = &g_array_index (bkpt_info->lines, LineInfo, line - bkpt_info->begin);
+
+      info->is_watchpoint = !!(mode & IDE_DEBUGGER_BREAK_WATCHPOINT);
+      info->is_countpoint = !!(mode & IDE_DEBUGGER_BREAK_COUNTPOINT);
+      info->is_breakpoint = !!(mode & IDE_DEBUGGER_BREAK_BREAKPOINT);
+    }
+}
+
+static void
+ide_omni_gutter_renderer_load_breakpoints (IdeOmniGutterRenderer *self,
+                                           GtkTextIter           *begin,
+                                           GtkTextIter           *end,
+                                           GArray                *lines)
+{
+  struct {
+    GArray *lines;
+    guint begin;
+    guint end;
+  } bkpt_info;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (begin != NULL);
+  g_assert (lines != NULL);
+  g_assert (lines->len > 0);
+
+  bkpt_info.lines = lines;
+  bkpt_info.begin = gtk_text_iter_get_line (begin);
+  bkpt_info.end = gtk_text_iter_get_line (end);
+
+  if (self->breakpoints != NULL)
+    ide_debugger_breakpoints_foreach (self->breakpoints,
+                                      (GFunc)collect_breakpoint_info,
+                                      &bkpt_info);
+}
+
+static void
+ide_omni_gutter_renderer_load_basic (IdeOmniGutterRenderer *self,
+                                     GtkTextIter           *begin,
+                                     GArray                *lines)
+{
+  IdeBuffer *buffer;
+  guint line;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (begin != NULL);
+  g_assert (lines != NULL);
+  g_assert (lines->len > 0);
+
+  buffer = (IdeBuffer *)gtk_text_iter_get_buffer (begin);
+
+  if (!IDE_IS_BUFFER (buffer))
+    return;
+
+  line = gtk_text_iter_get_line (begin);
+
+  if (buffer != NULL)
+    {
+      for (guint i = 0; i < lines->len; i++)
+        {
+          LineInfo *info = &g_array_index (lines, LineInfo, i);
+          IdeBufferLineFlags flags = ide_buffer_get_line_flags (buffer, line + i);
+
+          info->is_add = !!(flags & IDE_BUFFER_LINE_FLAGS_ADDED);
+          info->is_change = !!(flags & IDE_BUFFER_LINE_FLAGS_CHANGED);
+          info->is_delete = !!(flags & IDE_BUFFER_LINE_FLAGS_DELETED);
+          info->is_warning = !!(flags & IDE_BUFFER_LINE_FLAGS_WARNING);
+          info->is_note = !!(flags & IDE_BUFFER_LINE_FLAGS_NOTE);
+          info->is_error = !!(flags & IDE_BUFFER_LINE_FLAGS_ERROR);
+        }
+    }
+}
+
+static inline gint
+count_num_digits (gint num_lines)
+{
+  if (num_lines < 100)
+    return 2;
+  else if (num_lines < 1000)
+    return 3;
+  else if (num_lines < 10000)
+    return 4;
+  else if (num_lines < 100000)
+    return 5;
+  else if (num_lines < 1000000)
+    return 6;
+  else
+    return 10;
+}
+
+static void
+ide_omni_gutter_renderer_recalculate_size (IdeOmniGutterRenderer *self,
+                                           IdeSourceView         *view)
+{
+  const PangoFontDescription *font_desc;
+  g_autofree gchar *numbers = NULL;
+  GtkTextBuffer *buffer;
+  PangoLayout *layout;
+  GtkTextIter end;
+  guint line;
+  int height;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (IDE_IS_SOURCE_VIEW (view));
+
+  /*
+   * First, we need to get the size of the text for the last line of the
+   * buffer, which will be the longest. We size the font with '9' since it
+   * will generally be the widest of the numbers. Although, we only support
+   * monospace anyway, so it shouldn't matter.
+   */
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+  gtk_text_buffer_get_end_iter (buffer, &end);
+  line = gtk_text_iter_get_line (&end) + 1;
+
+  self->n_chars = count_num_digits (line);
+  numbers = g_strnfill (self->n_chars, '9');
+
+  font_desc = ide_source_view_get_font_desc (view);
+  layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), numbers);
+  pango_layout_set_font_description (layout, font_desc);
+  pango_layout_get_pixel_size (layout, &self->number_width, &height);
+  g_clear_object (&layout);
+
+  /*
+   * The spacing for the different items in the gutter looks like:
+   *
+   * Spacing (2px) Diagnostics (16px) Numbers(N) Changes(2) Spacing(2px)
+   */
+
+  gtk_source_gutter_renderer_set_size (GTK_SOURCE_GUTTER_RENDERER (self),
+                                       (2 +
+                                        DIAGNOSTICS_SIZE +
+                                        2 +
+                                        self->number_width +
+                                        2 +
+                                        ARROW_WIDTH +
+                                        2));
+
+  gtk_source_gutter_renderer_queue_draw (GTK_SOURCE_GUTTER_RENDERER (self));
+}
+
+static void
+ide_omni_gutter_renderer_notify_font_desc (IdeOmniGutterRenderer *self,
+                                           GParamSpec            *pspec,
+                                           IdeSourceView         *view)
+{
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (IDE_IS_SOURCE_VIEW (view));
+
+  ide_omni_gutter_renderer_recalculate_size (self, view);
+}
+
+static void
+ide_omni_gutter_renderer_end (GtkSourceGutterRenderer *renderer)
+{
+  IdeOmniGutterRenderer *self = (IdeOmniGutterRenderer *)renderer;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+
+  g_clear_object (&self->layout);
+}
+
+static void
+ide_omni_gutter_renderer_begin (GtkSourceGutterRenderer *renderer,
+                                cairo_t                 *cr,
+                                GdkRectangle            *bg_area,
+                                GdkRectangle            *cell_area,
+                                GtkTextIter             *begin,
+                                GtkTextIter             *end)
+{
+  IdeOmniGutterRenderer *self = (IdeOmniGutterRenderer *)renderer;
+  GtkTextTagTable *table;
+  GtkTextBuffer *buffer;
+  IdeSourceView *view;
+  GtkTextTag *tag;
+  GtkTextIter bkpt;
+  guint end_line;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (renderer));
+  g_assert (cr != NULL);
+  g_assert (bg_area != NULL);
+  g_assert (cell_area != NULL);
+  g_assert (begin != NULL);
+  g_assert (end != NULL);
+
+  self->stopped_line = -1;
+
+  buffer = gtk_text_iter_get_buffer (begin);
+  table = gtk_text_buffer_get_tag_table (buffer);
+  tag = gtk_text_tag_table_lookup (table, "debugger::current-breakpoint");
+
+  /*
+   * Locate the current stopped breakpoint if any.
+   */
+
+  if (tag != NULL)
+    {
+      bkpt = *begin;
+      gtk_text_iter_backward_char (&bkpt);
+      if (gtk_text_iter_forward_to_tag_toggle (&bkpt, tag) &&
+          gtk_text_iter_starts_tag (&bkpt, tag))
+        self->stopped_line = gtk_text_iter_get_line (&bkpt);
+    }
+
+  /*
+   * This function is called before we render any of the lines in
+   * the gutter. To reduce our overhead, we want to collect information
+   * for all of the line numbers upfront.
+   */
+
+  view = IDE_SOURCE_VIEW (gtk_source_gutter_renderer_get_view (renderer));
+
+  self->begin_line = gtk_text_iter_get_line (begin);
+  end_line = gtk_text_iter_get_line (end);
+
+  g_array_set_size (self->lines, end_line - self->begin_line + 1);
+  memset (self->lines->data, 0, self->lines->len * sizeof (LineInfo));
+
+  ide_omni_gutter_renderer_load_basic (self, begin, self->lines);
+  ide_omni_gutter_renderer_load_breakpoints (self, begin, end, self->lines);
+
+  self->layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), "");
+  pango_layout_set_alignment (self->layout, PANGO_ALIGN_RIGHT);
+  pango_layout_set_width (self->layout, (cell_area->width - ARROW_WIDTH - 4) * PANGO_SCALE);
+  pango_layout_set_font_description (self->layout,
+                                     ide_source_view_get_font_desc (view));
+}
+
+static gboolean
+ide_omni_gutter_renderer_query_activatable (GtkSourceGutterRenderer *renderer,
+                                            GtkTextIter             *begin,
+                                            GdkRectangle            *area,
+                                            GdkEvent                *event)
+{
+  IdeOmniGutterRenderer *self = (IdeOmniGutterRenderer *)renderer;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (begin != NULL);
+  g_assert (area != NULL);
+  g_assert (event != NULL);
+
+  return (self->breakpoints != NULL);
+}
+
+static void
+animate_at_iter (IdeOmniGutterRenderer *self,
+                 GdkRectangle          *area,
+                 GtkTextIter           *iter)
+{
+  DzlBoxTheatric *theatric;
+  GtkTextView *view;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (area != NULL);
+  g_assert (iter != NULL);
+
+#define ANIMATION_X_GROW 50
+#define ANIMATION_Y_GROW 30
+
+  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));
+
+  theatric = g_object_new (DZL_TYPE_BOX_THEATRIC,
+                           "alpha", 0.3,
+                           "background", "#729fcf",
+                           "height", area->height,
+                           "target", view,
+                           "width", area->width,
+                           "x", area->x,
+                           "y", area->y,
+                           NULL);
+
+  dzl_object_animate_full (theatric,
+                           DZL_ANIMATION_EASE_IN_CUBIC,
+                           100,
+                           gtk_widget_get_frame_clock (GTK_WIDGET (view)),
+                           g_object_unref,
+                           theatric,
+                           "x", area->x - ANIMATION_X_GROW,
+                           "width", area->width + (ANIMATION_X_GROW * 2),
+                           "y", area->y - ANIMATION_Y_GROW,
+                           "height", area->height + (ANIMATION_Y_GROW * 2),
+                           "alpha", 0.0,
+                           NULL);
+}
+
+static void
+ide_omni_gutter_renderer_activate (GtkSourceGutterRenderer *renderer,
+                                   GtkTextIter             *iter,
+                                   GdkRectangle            *area,
+                                   GdkEvent                *event)
+{
+  IdeOmniGutterRenderer *self = (IdeOmniGutterRenderer *)renderer;
+  IdeDebuggerBreakpoint *breakpoint;
+  IdeDebuggerBreakMode break_type = IDE_DEBUGGER_BREAK_NONE;
+  g_autofree gchar *path = NULL;
+  IdeDebugManager *debug_manager;
+  GtkTextBuffer *buffer;
+  IdeContext *context;
+  GFile *file;
+  guint line;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (iter != NULL);
+  g_assert (area != NULL);
+  g_assert (event != NULL);
+  g_assert (self->breakpoints != NULL);
+
+  buffer = gtk_text_iter_get_buffer (iter);
+  context = ide_buffer_get_context (IDE_BUFFER (buffer));
+  debug_manager = ide_context_get_debug_manager (context);
+
+  line = gtk_text_iter_get_line (iter) + 1;
+  file = ide_debugger_breakpoints_get_file (self->breakpoints);
+  path = g_file_get_path (file);
+
+  /* TODO: Should we show a Popover here to select the type? */
+  IDE_TRACE_MSG ("Toggle breakpoint on line %u [breakpoints=%p]",
+                 line, self->breakpoints);
+
+  breakpoint = ide_debugger_breakpoints_get_line (self->breakpoints, line);
+  if (breakpoint != NULL)
+    break_type = ide_debugger_breakpoint_get_mode (breakpoint);
+
+  switch (break_type)
+    {
+    case IDE_DEBUGGER_BREAK_NONE:
+      {
+        g_autoptr(IdeDebuggerBreakpoint) to_insert = NULL;
+
+        to_insert = ide_debugger_breakpoint_new (NULL);
+
+        ide_debugger_breakpoint_set_line (to_insert, line);
+        ide_debugger_breakpoint_set_file (to_insert, path);
+        ide_debugger_breakpoint_set_mode (to_insert, IDE_DEBUGGER_BREAK_BREAKPOINT);
+        ide_debugger_breakpoint_set_enabled (to_insert, TRUE);
+
+        _ide_debug_manager_add_breakpoint (debug_manager, to_insert);
+      }
+      break;
+
+    case IDE_DEBUGGER_BREAK_BREAKPOINT:
+    case IDE_DEBUGGER_BREAK_COUNTPOINT:
+    case IDE_DEBUGGER_BREAK_WATCHPOINT:
+      if (breakpoint != NULL)
+        {
+          _ide_debug_manager_remove_breakpoint (debug_manager, breakpoint);
+          animate_at_iter (self, area, iter);
+        }
+      break;
+
+    default:
+      g_return_if_reached ();
+    }
+
+  /*
+   * We will wait for changes to be applied to the #IdeDebuggerBreakpoints
+   * by the #IdeDebugManager. That will cause the gutter to be invalidated
+   * and redrawn.
+   */
+
+  IDE_EXIT;
+}
+
+static void
+draw_breakpoint_bg (IdeOmniGutterRenderer        *self,
+                    cairo_t                      *cr,
+                    GdkRectangle                 *bg_area,
+                    LineInfo                     *info,
+                    GtkSourceGutterRendererState  state)
+{
+  GdkRectangle area;
+  GdkRGBA rgba;
+
+  g_assert (GTK_SOURCE_IS_GUTTER_RENDERER (self));
+  g_assert (cr != NULL);
+  g_assert (bg_area != NULL);
+
+  area.x = bg_area->x;
+  area.y = bg_area->y + 1;
+  area.height = bg_area->height - 2;
+  area.width = bg_area->width;
+
+  cairo_move_to (cr, area.x, area.y);
+  cairo_line_to (cr,
+                 dzl_cairo_rectangle_x2 (&area) - ARROW_WIDTH,
+                 area.y);
+  cairo_line_to (cr,
+                 dzl_cairo_rectangle_x2 (&area),
+                 dzl_cairo_rectangle_middle (&area));
+  cairo_line_to (cr,
+                 dzl_cairo_rectangle_x2 (&area) - ARROW_WIDTH,
+                 dzl_cairo_rectangle_y2 (&area));
+  cairo_line_to (cr, area.x, dzl_cairo_rectangle_y2 (&area));
+  cairo_close_path (cr);
+
+  rgba = self->bkpt.bg;
+
+  if ((state & GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT) != 0)
+    {
+      if (IS_BREAKPOINT (info))
+        rgba.alpha *= 0.8;
+      else
+        rgba.alpha *= 0.4;
+    }
+
+  gdk_cairo_set_source_rgba (cr, &rgba);
+  cairo_fill (cr);
+}
+
+static void
+draw_add_change (IdeOmniGutterRenderer        *self,
+                 cairo_t                      *cr,
+                 GdkRectangle                 *area,
+                 LineInfo                     *info,
+                 GtkSourceGutterRendererState  state)
+{
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (cr != NULL);
+  g_assert (area != NULL);
+
+  cairo_rectangle (cr,
+                   area->x + area->width - 2 - CHANGE_WIDTH,
+                   area->y,
+                   CHANGE_WIDTH,
+                   area->y + area->height);
+
+  if (info->is_add)
+    gdk_cairo_set_source_rgba (cr, &self->changes.add);
+  else
+    gdk_cairo_set_source_rgba (cr, &self->changes.change);
+
+  cairo_fill (cr);
+}
+
+static void
+draw_diagnostic (IdeOmniGutterRenderer        *self,
+                 cairo_t                      *cr,
+                 GdkRectangle                 *area,
+                 LineInfo                     *info,
+                 GtkSourceGutterRendererState  state)
+{
+  cairo_surface_t *surface = NULL;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (cr != NULL);
+  g_assert (area != NULL);
+
+  if (IS_BREAKPOINT (info) || (state & GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT))
+    {
+      if (info->is_error)
+        surface = self->error_selected_surface;
+      else if (info->is_warning)
+        surface = self->warning_selected_surface;
+      else if (info->is_note)
+        surface = self->note_selected_surface;
+    }
+  else
+    {
+      if (info->is_error)
+        surface = self->error_surface;
+      else if (info->is_warning)
+        surface = self->warning_surface;
+      else if (info->is_note)
+        surface = self->note_surface;
+    }
+
+  if (surface != NULL)
+    {
+      cairo_rectangle (cr,
+                       area->x + 2,
+                       area->y + ((area->height - DIAGNOSTICS_SIZE) / 2) + 1,
+                       DIAGNOSTICS_SIZE, DIAGNOSTICS_SIZE);
+      cairo_set_source_surface (cr,
+                                surface,
+                                area->x + 2,
+                                area->y + ((area->height - DIAGNOSTICS_SIZE) / 2) + 1);
+      cairo_paint (cr);
+    }
+}
+
+static void
+ide_omni_gutter_renderer_draw (GtkSourceGutterRenderer      *renderer,
+                               cairo_t                      *cr,
+                               GdkRectangle                 *bg_area,
+                               GdkRectangle                 *cell_area,
+                               GtkTextIter                  *begin,
+                               GtkTextIter                  *end,
+                               GtkSourceGutterRendererState  state)
+{
+  IdeOmniGutterRenderer *self = (IdeOmniGutterRenderer *)renderer;
+  guint line;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (cr != NULL);
+  g_assert (bg_area != NULL);
+  g_assert (cell_area != NULL);
+  g_assert (begin != NULL);
+  g_assert (end != NULL);
+
+  line = gtk_text_iter_get_line (begin);
+
+  if ((line - self->begin_line) < self->lines->len)
+    {
+      LineInfo *info = &g_array_index (self->lines, LineInfo, line - self->begin_line);
+      gboolean active = state & GTK_SOURCE_GUTTER_RENDERER_STATE_PRELIT;
+      gboolean has_breakpoint = FALSE;
+      gboolean bold = FALSE;
+      gchar linestr[16];
+      gint len;
+
+      if (line == self->stopped_line)
+        {
+          gdk_cairo_rectangle (cr, bg_area);
+          gdk_cairo_set_source_rgba (cr, &self->stopped_bg);
+          cairo_fill (cr);
+        }
+      else if (state & GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR)
+        {
+          gdk_cairo_rectangle (cr, bg_area);
+          gdk_cairo_set_source_rgba (cr, &self->current.bg);
+          cairo_fill (cr);
+        }
+
+      if (info->is_add || info->is_change)
+        draw_add_change (self, cr, cell_area, info, state);
+
+      if (self->breakpoints != NULL)
+        {
+          has_breakpoint = IS_BREAKPOINT (info);
+          if (has_breakpoint || active)
+            draw_breakpoint_bg (self, cr, cell_area, info, state);
+        }
+
+      if (IS_DIAGNOSTIC (info))
+        draw_diagnostic (self, cr, cell_area, info, state);
+
+      len = g_snprintf (linestr, sizeof linestr, "%u", line + 1);
+      pango_layout_set_text (self->layout, linestr, len);
+
+      cairo_move_to (cr, cell_area->x, cell_area->y);
+
+      if (has_breakpoint || active)
+        {
+          gdk_cairo_set_source_rgba (cr, &self->bkpt.fg);
+          bold = self->bkpt.bold;
+        }
+      else if (state & GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR)
+        {
+          gdk_cairo_set_source_rgba (cr, &self->current.fg);
+          bold = self->current.bold;
+        }
+      else
+        {
+          gdk_cairo_set_source_rgba (cr, &self->text.fg);
+          bold = self->text.bold;
+        }
+
+      if (state & GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR)
+        bold |= self->current.bold;
+
+      pango_layout_set_attributes (self->layout, bold ? self->bold_attrs : NULL);
+
+      pango_cairo_show_layout (cr, self->layout);
+    }
+}
+
+static cairo_surface_t *
+get_icon_surface (IdeOmniGutterRenderer *self,
+                  GtkWidget             *widget,
+                  const gchar           *icon_name,
+                  gint                   size,
+                  gboolean               selected)
+{
+  GtkIconTheme *icon_theme;
+  GtkIconInfo *info;
+  GdkScreen *screen;
+  GtkIconLookupFlags flags;
+  gint scale;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (GTK_IS_WIDGET (widget));
+  g_assert (icon_name != NULL);
+
+  screen = gtk_widget_get_screen (widget);
+  icon_theme = gtk_icon_theme_get_for_screen (screen);
+
+  flags = GTK_ICON_LOOKUP_USE_BUILTIN;
+  scale = gtk_widget_get_scale_factor (widget);
+
+  info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name, size, scale, flags);
+
+  if (info != NULL)
+    {
+      g_autoptr(GdkPixbuf) pixbuf = NULL;
+
+      if (gtk_icon_info_is_symbolic (info))
+        {
+          GdkRGBA fg;
+
+          if (selected)
+            fg = self->bkpt.fg;
+          else
+            fg = self->text.fg;
+
+          pixbuf = gtk_icon_info_load_symbolic (info, &fg, &fg, &fg, &fg, NULL, NULL);
+        }
+      else
+        pixbuf = gtk_icon_info_load_icon (info, NULL);
+
+      if (pixbuf != NULL)
+        return gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL);
+    }
+
+  return NULL;
+}
+
+static void
+ide_omni_gutter_renderer_reload_icons (IdeOmniGutterRenderer *self)
+{
+  GtkTextView *view;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+
+  g_clear_pointer (&self->note_surface, cairo_surface_destroy);
+  g_clear_pointer (&self->warning_surface, cairo_surface_destroy);
+  g_clear_pointer (&self->error_surface, cairo_surface_destroy);
+  g_clear_pointer (&self->note_selected_surface, cairo_surface_destroy);
+  g_clear_pointer (&self->warning_selected_surface, cairo_surface_destroy);
+  g_clear_pointer (&self->error_selected_surface, cairo_surface_destroy);
+
+  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));
+  if (view == NULL)
+    return;
+
+  self->note_surface = get_icon_surface (self, GTK_WIDGET (view), "dialog-information-symbolic", 
DIAGNOSTICS_SIZE, FALSE);
+  self->warning_surface = get_icon_surface (self, GTK_WIDGET (view), "dialog-warning-symbolic", 
DIAGNOSTICS_SIZE, FALSE);
+  self->error_surface = get_icon_surface (self, GTK_WIDGET (view), "process-stop-symbolic", 
DIAGNOSTICS_SIZE, FALSE);
+
+  self->note_selected_surface = get_icon_surface (self, GTK_WIDGET (view), "dialog-information-symbolic", 
DIAGNOSTICS_SIZE, TRUE);
+  self->warning_selected_surface = get_icon_surface (self, GTK_WIDGET (view), "dialog-warning-symbolic", 
DIAGNOSTICS_SIZE, TRUE);
+  self->error_selected_surface = get_icon_surface (self, GTK_WIDGET (view), "process-stop-symbolic", 
DIAGNOSTICS_SIZE, TRUE);
+}
+
+static void
+ide_omni_gutter_renderer_reload (IdeOmniGutterRenderer *self)
+{
+  g_autoptr(IdeDebuggerBreakpoints) breakpoints = NULL;
+  GtkSourceLanguage *language;
+  GtkTextBuffer *buffer;
+  GtkTextView *view;
+  const gchar *id = NULL;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+
+  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));
+  buffer = gtk_text_view_get_buffer (view);
+
+  if (NULL != (language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer))))
+    id = gtk_source_language_get_id (language);
+
+  if (IDE_IS_BUFFER (buffer))
+    {
+      IdeContext *context = ide_buffer_get_context (IDE_BUFFER (buffer));
+      IdeDebugManager *debug_manager = ide_context_get_debug_manager (context);
+
+      if (ide_debug_manager_supports_language (debug_manager, id))
+        {
+          IdeFile *file = ide_buffer_get_file (IDE_BUFFER (buffer));
+          GFile *gfile = ide_file_get_file (file);
+
+          breakpoints = ide_debug_manager_get_breakpoints_for_file (debug_manager, gfile);
+        }
+    }
+
+  g_set_object (&self->breakpoints, breakpoints);
+
+  ide_omni_gutter_renderer_reload_icons (self);
+  ide_omni_gutter_renderer_recalculate_size (self, IDE_SOURCE_VIEW (view));
+}
+
+static void
+ide_omni_gutter_renderer_bind_view (IdeOmniGutterRenderer *self,
+                                    IdeSourceView         *view,
+                                    DzlSignalGroup        *view_signals)
+{
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (IDE_IS_SOURCE_VIEW (view));
+  g_assert (DZL_IS_SIGNAL_GROUP (view_signals));
+
+  if (self->buffer_signals != NULL)
+    {
+      GtkTextBuffer *buffer;
+
+      buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+      if (IDE_IS_BUFFER (buffer))
+        dzl_signal_group_set_target (self->buffer_signals, buffer);
+
+      ide_omni_gutter_renderer_reload (self);
+    }
+}
+
+static void
+ide_omni_gutter_renderer_notify_buffer (IdeOmniGutterRenderer *self,
+                                        GParamSpec            *pspec,
+                                        IdeSourceView         *view)
+{
+  GtkTextBuffer *buffer;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (pspec != NULL);
+  g_assert (IDE_IS_SOURCE_VIEW (view));
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+  if (IDE_IS_BUFFER (buffer))
+    dzl_signal_group_set_target (self->buffer_signals, buffer);
+
+  ide_omni_gutter_renderer_reload (self);
+}
+
+static void
+ide_omni_gutter_renderer_notify_file (IdeOmniGutterRenderer *self,
+                                      GParamSpec            *pspec,
+                                      IdeBuffer             *buffer)
+{
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (pspec != NULL);
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  ide_omni_gutter_renderer_reload (self);
+}
+
+static void
+ide_omni_gutter_renderer_notify_view (IdeOmniGutterRenderer *self)
+{
+  GtkTextView *view;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+
+  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));
+  dzl_signal_group_set_target (self->view_signals, view);
+}
+
+static gboolean
+ide_omni_gutter_renderer_do_recalc (gpointer data)
+{
+  IdeOmniGutterRenderer *self = data;
+  GtkTextView *view;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+
+  self->resize_source = 0;
+
+  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));
+  if (IDE_IS_SOURCE_VIEW (view))
+    ide_omni_gutter_renderer_recalculate_size (self, IDE_SOURCE_VIEW (view));
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+ide_omni_gutter_renderer_buffer_changed (IdeOmniGutterRenderer *self,
+                                         IdeBuffer             *buffer)
+{
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  if (self->resize_source == 0)
+    self->resize_source = gdk_threads_add_idle_full (G_PRIORITY_HIGH,
+                                                     ide_omni_gutter_renderer_do_recalc,
+                                                     g_object_ref (self),
+                                                     g_object_unref);
+}
+
+static void
+ide_omni_gutter_renderer_notify_style_scheme (IdeOmniGutterRenderer *self,
+                                              GParamSpec            *pspec,
+                                              IdeBuffer             *buffer)
+{
+  GtkSourceStyleScheme *scheme;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer));
+  reload_style_colors (self, scheme);
+  ide_omni_gutter_renderer_reload_icons (self);
+}
+
+static void
+ide_omni_gutter_renderer_bind_buffer (IdeOmniGutterRenderer *self,
+                                      IdeBuffer             *buffer,
+                                      DzlSignalGroup        *buffer_signals)
+{
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+  g_assert (DZL_IS_SIGNAL_GROUP (buffer_signals));
+
+  ide_omni_gutter_renderer_notify_style_scheme (self, NULL, buffer);
+}
+
+static void
+ide_omni_gutter_renderer_constructed (GObject *object)
+{
+  IdeOmniGutterRenderer *self = (IdeOmniGutterRenderer *)object;
+  GtkTextView *view;
+
+  g_assert (IDE_IS_OMNI_GUTTER_RENDERER (self));
+
+  G_OBJECT_CLASS (ide_omni_gutter_renderer_parent_class)->constructed (object);
+
+  view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (self));
+  dzl_signal_group_set_target (self->view_signals, view);
+}
+
+static void
+ide_omni_gutter_renderer_dispose (GObject *object)
+{
+  IdeOmniGutterRenderer *self = (IdeOmniGutterRenderer *)object;
+
+  g_clear_pointer (&self->note_surface, cairo_surface_destroy);
+  g_clear_pointer (&self->warning_surface, cairo_surface_destroy);
+  g_clear_pointer (&self->error_surface, cairo_surface_destroy);
+  ide_clear_source (&self->resize_source);
+  g_clear_pointer (&self->lines, g_array_unref);
+  g_clear_pointer (&self->bold_attrs, pango_attr_list_unref);
+  g_clear_object (&self->breakpoints);
+  g_clear_object (&self->buffer_signals);
+  g_clear_object (&self->view_signals);
+
+  G_OBJECT_CLASS (ide_omni_gutter_renderer_parent_class)->dispose (object);
+}
+
+static void
+ide_omni_gutter_renderer_class_init (IdeOmniGutterRendererClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass);
+
+  object_class->constructed = ide_omni_gutter_renderer_constructed;
+  object_class->dispose = ide_omni_gutter_renderer_dispose;
+
+  renderer_class->draw = ide_omni_gutter_renderer_draw;
+  renderer_class->begin = ide_omni_gutter_renderer_begin;
+  renderer_class->end = ide_omni_gutter_renderer_end;
+  renderer_class->query_activatable = ide_omni_gutter_renderer_query_activatable;
+  renderer_class->activate = ide_omni_gutter_renderer_activate;
+
+  gdk_rgba_parse (&rgbaAdded, "#8ae234");
+  gdk_rgba_parse (&rgbaChanged, "#fcaf3e");
+  gdk_rgba_parse (&rgbaRemoved, "#ff0000");
+}
+
+static void
+ide_omni_gutter_renderer_init (IdeOmniGutterRenderer *self)
+{
+  self->lines = g_array_new (FALSE, FALSE, sizeof (LineInfo));
+
+  g_signal_connect (self,
+                    "notify::view",
+                    G_CALLBACK (ide_omni_gutter_renderer_notify_view),
+                    NULL);
+
+  self->buffer_signals = dzl_signal_group_new (IDE_TYPE_BUFFER);
+
+  g_signal_connect_swapped (self->buffer_signals,
+                            "bind",
+                            G_CALLBACK (ide_omni_gutter_renderer_bind_buffer),
+                            self);
+
+  dzl_signal_group_connect_swapped (self->buffer_signals,
+                                    "notify::file",
+                                    G_CALLBACK (ide_omni_gutter_renderer_notify_file),
+                                    self);
+
+  dzl_signal_group_connect_swapped (self->buffer_signals,
+                                    "notify::style-scheme",
+                                    G_CALLBACK (ide_omni_gutter_renderer_notify_style_scheme),
+                                    self);
+
+  dzl_signal_group_connect_swapped (self->buffer_signals,
+                                    "changed",
+                                    G_CALLBACK (ide_omni_gutter_renderer_buffer_changed),
+                                    self);
+
+  self->view_signals = dzl_signal_group_new (IDE_TYPE_SOURCE_VIEW);
+
+  g_signal_connect_swapped (self->view_signals,
+                            "bind",
+                            G_CALLBACK (ide_omni_gutter_renderer_bind_view),
+                            self);
+
+  dzl_signal_group_connect_swapped (self->view_signals,
+                                    "notify::buffer",
+                                    G_CALLBACK (ide_omni_gutter_renderer_notify_buffer),
+                                    self);
+
+  dzl_signal_group_connect_swapped (self->view_signals,
+                                    "notify::font-desc",
+                                    G_CALLBACK (ide_omni_gutter_renderer_notify_font_desc),
+                                    self);
+
+  self->bold_attrs = pango_attr_list_new ();
+  pango_attr_list_insert (self->bold_attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+}
+
+IdeOmniGutterRenderer *
+ide_omni_gutter_renderer_new (void)
+{
+  return g_object_new (IDE_TYPE_OMNI_GUTTER_RENDERER, NULL);
+}
diff --git a/libide/debugger/ide-debugger-editor-view-addin.h b/libide/sourceview/ide-omni-gutter-renderer.h
similarity index 63%
rename from libide/debugger/ide-debugger-editor-view-addin.h
rename to libide/sourceview/ide-omni-gutter-renderer.h
index 2e221ca..b666daa 100644
--- a/libide/debugger/ide-debugger-editor-view-addin.h
+++ b/libide/sourceview/ide-omni-gutter-renderer.h
@@ -1,4 +1,4 @@
-/* ide-debugger-editor-view-addin.h
+/* ide-omni-gutter-renderer.h
  *
  * Copyright (C) 2017 Christian Hergert <chergert redhat com>
  *
@@ -16,14 +16,19 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#pragma once
+#ifndef IDE_OMNI_GUTTER_RENDERER_H
+#define IDE_OMNI_GUTTER_RENDERER_H
 
-#include "editor/ide-editor-view-addin.h"
+#include <gtksourceview/gtksource.h>
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_DEBUGGER_EDITOR_VIEW_ADDIN (ide_debugger_editor_view_addin_get_type())
+#define IDE_TYPE_OMNI_GUTTER_RENDERER (ide_omni_gutter_renderer_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeDebuggerEditorViewAddin, ide_debugger_editor_view_addin, IDE, 
DEBUGGER_EDITOR_VIEW_ADDIN, GObject)
+G_DECLARE_FINAL_TYPE (IdeOmniGutterRenderer, ide_omni_gutter_renderer, IDE, OMNI_GUTTER_RENDERER, 
GtkSourceGutterRenderer)
+
+IdeOmniGutterRenderer *ide_omni_gutter_renderer_new (void);
 
 G_END_DECLS
+
+#endif /* IDE_OMNI_GUTTER_RENDERER_H */
diff --git a/libide/sourceview/ide-source-view.c b/libide/sourceview/ide-source-view.c
index b763bf1..7730d4a 100644
--- a/libide/sourceview/ide-source-view.c
+++ b/libide/sourceview/ide-source-view.c
@@ -48,8 +48,7 @@
 #include "sourceview/ide-completion-provider.h"
 #include "sourceview/ide-cursor.h"
 #include "sourceview/ide-indenter.h"
-#include "sourceview/ide-line-change-gutter-renderer.h"
-#include "sourceview/ide-line-diagnostics-gutter-renderer.h"
+#include "sourceview/ide-omni-gutter-renderer.h"
 #include "sourceview/ide-source-iter.h"
 #include "sourceview/ide-source-view-capture.h"
 #include "sourceview/ide-source-view-mode.h"
@@ -94,8 +93,6 @@ typedef struct
   GtkCssProvider              *css_provider;
   PangoFontDescription        *font_desc;
   IdeExtensionAdapter         *indenter_adapter;
-  GtkSourceGutterRenderer     *line_change_renderer;
-  GtkSourceGutterRenderer     *line_diagnostics_renderer;
   IdeSourceViewCapture        *capture;
   gchar                       *display_name;
   IdeSourceViewMode           *mode;
@@ -1415,11 +1412,10 @@ ide_source_view__buffer_notify_highlight_diagnostics_cb (IdeSourceView *self,
                                                          GParamSpec    *pspec,
                                                          IdeBuffer     *buffer)
 {
-  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
-
   g_assert (IDE_IS_SOURCE_VIEW (self));
   g_assert (IDE_IS_BUFFER (buffer));
 
+#if 0
   if (priv->line_diagnostics_renderer != NULL)
     {
       gboolean visible;
@@ -1429,21 +1425,20 @@ ide_source_view__buffer_notify_highlight_diagnostics_cb (IdeSourceView *self,
                     "visible", visible,
                     NULL);
     }
+#endif
 }
 
 static void
 ide_source_view__buffer_line_flags_changed_cb (IdeSourceView *self,
                                                IdeBuffer     *buffer)
 {
-  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
-
   IDE_ENTRY;
 
   g_assert (IDE_IS_SOURCE_VIEW (self));
   g_assert (IDE_IS_BUFFER (buffer));
 
-  gtk_source_gutter_renderer_queue_draw (priv->line_change_renderer);
-  gtk_source_gutter_renderer_queue_draw (priv->line_diagnostics_renderer);
+  gtk_source_gutter_queue_draw (gtk_source_view_get_gutter (GTK_SOURCE_VIEW (self),
+                                                            GTK_TEXT_WINDOW_LEFT));
 
   IDE_EXIT;
 }
@@ -4492,9 +4487,7 @@ ide_source_view_constructed (GObject *object)
 {
   IdeSourceView *self = (IdeSourceView *)object;
   IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
-  GtkSourceGutter *gutter;
   GtkSourceCompletion *completion;
-  gboolean visible;
 
   G_OBJECT_CLASS (ide_source_view_parent_class)->constructed (object);
 
@@ -4519,31 +4512,19 @@ ide_source_view_constructed (GObject *object)
                            self,
                            G_CONNECT_SWAPPED | G_CONNECT_AFTER);
 
-  gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (self), GTK_TEXT_WINDOW_LEFT);
-
-  priv->line_change_renderer = g_object_new (IDE_TYPE_LINE_CHANGE_GUTTER_RENDERER,
-                                             "show-line-deletions", TRUE,
-                                             "size", 2,
-                                             "visible", priv->show_line_changes,
-                                             "xpad", 3,
-                                             NULL);
-  g_object_ref (priv->line_change_renderer);
-  gtk_source_gutter_insert (gutter, priv->line_change_renderer, 0);
-
-  visible = ((priv->buffer != NULL) &&
-             priv->show_line_diagnostics &&
-             ide_buffer_get_highlight_diagnostics (priv->buffer));
-  priv->line_diagnostics_renderer = g_object_new (IDE_TYPE_LINE_DIAGNOSTICS_GUTTER_RENDERER,
-                                                  "size", 16,
-                                                  "visible", visible,
-                                                  "xpad", 2,
-                                                  NULL);
-  g_object_ref (priv->line_diagnostics_renderer);
-  gtk_source_gutter_insert (gutter, priv->line_diagnostics_renderer, -100);
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHOW_LINE_DIAGNOSTICS]);
-
   priv->definition_src_location = NULL;
   ide_source_view_reset_definition_highlight (self);
+
+  {
+    IdeOmniGutterRenderer *renderer;
+    GtkSourceGutter *gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (self), GTK_TEXT_WINDOW_LEFT);
+
+    renderer = g_object_new (IDE_TYPE_OMNI_GUTTER_RENDERER,
+                             "size", 20,
+                             "visible", TRUE,
+                             NULL);
+    gtk_source_gutter_insert (gutter, GTK_SOURCE_GUTTER_RENDERER (renderer), 1000);
+  }
 }
 
 static void
@@ -6287,8 +6268,6 @@ ide_source_view_dispose (GObject *object)
 
   g_clear_object (&priv->capture);
   g_clear_object (&priv->indenter_adapter);
-  g_clear_object (&priv->line_change_renderer);
-  g_clear_object (&priv->line_diagnostics_renderer);
   g_clear_object (&priv->snippets_provider);
   g_clear_object (&priv->css_provider);
   g_clear_object (&priv->mode);
@@ -7711,8 +7690,7 @@ ide_source_view_set_show_line_changes (IdeSourceView *self,
   if (show_line_changes != priv->show_line_changes)
     {
       priv->show_line_changes = show_line_changes;
-      if (priv->line_change_renderer)
-        gtk_source_gutter_renderer_set_visible (priv->line_change_renderer, show_line_changes);
+      /* TODO: Update omni renderer */
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHOW_LINE_CHANGES]);
     }
 }
@@ -7739,16 +7717,16 @@ ide_source_view_set_show_line_diagnostics (IdeSourceView *self,
 
   if (show_line_diagnostics != priv->show_line_diagnostics)
     {
-      gboolean visible;
-
       priv->show_line_diagnostics = show_line_diagnostics;
 
+#if 0
       if ((priv->buffer != NULL) && (priv->line_diagnostics_renderer != NULL))
         {
           visible = (priv->show_line_diagnostics &&
                      ide_buffer_get_highlight_diagnostics (priv->buffer));
           gtk_source_gutter_renderer_set_visible (priv->line_diagnostics_renderer, visible);
         }
+#endif
 
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHOW_LINE_CHANGES]);
     }


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