[gnome-builder/wip/chergert/bug1: 77/101] debugger: more breakpoints plumbing for gutter/debug-manager



commit fd15ec7851984ac6b745bd471f5ac53844a0a3ab
Author: Christian Hergert <chergert redhat com>
Date:   Wed Aug 30 17:45:45 2017 -0700

    debugger: more breakpoints plumbing for gutter/debug-manager

 libide/debugger/ide-debug-manager.c              |  150 ++++++++++++++++++++--
 libide/debugger/ide-debug-manager.h              |    2 +-
 libide/debugger/ide-debugger-breakpoint.c        |    3 +
 libide/debugger/ide-debugger-breakpoints.c       |  118 ++++++++++++++++-
 libide/debugger/ide-debugger-breakpoints.h       |   11 +-
 libide/debugger/ide-debugger-editor-view-addin.c |   33 +++++-
 libide/debugger/ide-debugger-gutter-renderer.c   |  144 +++++++++++++++++----
 libide/debugger/ide-debugger-gutter-renderer.h   |    3 +-
 libide/debugger/ide-debugger-private.h           |   10 +-
 libide/ide.h                                     |    1 +
 libide/meson.build                               |    4 +-
 11 files changed, 423 insertions(+), 56 deletions(-)
---
diff --git a/libide/debugger/ide-debug-manager.c b/libide/debugger/ide-debug-manager.c
index adcd68a..94f079f 100644
--- a/libide/debugger/ide-debug-manager.c
+++ b/libide/debugger/ide-debug-manager.c
@@ -131,10 +131,8 @@ ide_debug_manager_breakpoint_added (IdeDebugManager       *self,
                                     IdeDebugger           *debugger)
 {
   IdeDebuggerBreakpoints *breakpoints;
-  IdeDebuggerBreakMode mode;
   g_autoptr(GFile) file = NULL;
   const gchar *path;
-  guint line;
 
   g_assert (IDE_IS_DEBUG_MANAGER (self));
   g_assert (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
@@ -146,9 +144,7 @@ ide_debug_manager_breakpoint_added (IdeDebugManager       *self,
     return;
 
   file = g_file_new_for_path (path);
-
   breakpoints = g_hash_table_lookup (self->breakpoints, file);
-
   if (breakpoints == NULL)
     {
       breakpoints = g_object_new (IDE_TYPE_DEBUGGER_BREAKPOINTS,
@@ -157,10 +153,7 @@ ide_debug_manager_breakpoint_added (IdeDebugManager       *self,
       g_hash_table_insert (self->breakpoints, g_steal_pointer (&file), breakpoints);
     }
 
-  mode = ide_debugger_breakpoint_get_mode (breakpoint);
-  line = ide_debugger_breakpoint_get_line (breakpoint);
-
-  ide_debugger_breakpoints_set_line (breakpoints, line, mode);
+  _ide_debugger_breakpoints_add (breakpoints, breakpoint);
 }
 
 static void
@@ -171,7 +164,6 @@ ide_debug_manager_breakpoint_removed (IdeDebugManager       *self,
   IdeDebuggerBreakpoints *breakpoints;
   g_autoptr(GFile) file = NULL;
   const gchar *path;
-  guint line;
 
   g_assert (IDE_IS_DEBUG_MANAGER (self));
   g_assert (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
@@ -181,12 +173,12 @@ ide_debug_manager_breakpoint_removed (IdeDebugManager       *self,
   if (path == NULL)
     return;
 
-  line = ide_debugger_breakpoint_get_line (breakpoint);
   file = g_file_new_for_path (path);
-
   breakpoints = g_hash_table_lookup (self->breakpoints, file);
-  if (breakpoints != NULL)
-    ide_debugger_breakpoints_set_line (breakpoints, line, IDE_DEBUGGER_BREAK_NONE);
+  if (breakpoints == NULL)
+    return;
+
+  _ide_debugger_breakpoints_remove (breakpoints, breakpoint);
 }
 
 static void
@@ -488,3 +480,135 @@ ide_debug_manager_get_debugger (IdeDebugManager *self)
 
   return self->debugger;
 }
+
+/**
+ * ide_debug_manager_get_breakpoints_for_file:
+ *
+ * This returns an #IdeDebuggerBreakpoints that represents the breakpoints
+ * within a given file.
+ *
+ * This inderect breakpoints container provides a very fast way to check if
+ * a line has a breakpoint set. You want to use this when performance really
+ * matters such as from the gutter of the source editor.
+ *
+ * Breakpoints contained in the resulting structure will automatically
+ * propagate to the debugger when the debugger has been successfully spawned.
+ *
+ * Returns: (transfer full): An #IdeDebuggerBreakpoints
+ */
+IdeDebuggerBreakpoints *
+ide_debug_manager_get_breakpoints_for_file (IdeDebugManager *self,
+                                            GFile           *file)
+{
+  IdeDebuggerBreakpoints *breakpoints;
+
+  g_return_val_if_fail (IDE_IS_DEBUG_MANAGER (self), NULL);
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  breakpoints = g_hash_table_lookup (self->breakpoints, file);
+
+  if (breakpoints == NULL)
+    {
+      breakpoints = g_object_new (IDE_TYPE_DEBUGGER_BREAKPOINTS,
+                                  "file", file,
+                                  NULL);
+      g_hash_table_insert (self->breakpoints, g_object_ref (file), breakpoints);
+    }
+
+  return g_object_ref (breakpoints);
+}
+
+/**
+ * _ide_debug_manager_add_breakpoint:
+ * @self: An #IdeDebugManager
+ * @breakpoint: An #IdeDebuggerBreakpoint
+ *
+ * This adds a new breakpoint. If the debugger has been started, it
+ * is done by notifying the debugger to add the breakpoint. If there is
+ * not an active debugger, then it is done by caching the breakpoint
+ * until the debugger is next started.
+ *
+ * Since: 3.26
+ */
+void
+_ide_debug_manager_add_breakpoint (IdeDebugManager       *self,
+                                   IdeDebuggerBreakpoint *breakpoint)
+{
+  g_autoptr(IdeDebuggerBreakpoints) breakpoints = NULL;
+  g_autoptr(GFile) file = NULL;
+  const gchar *path;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_DEBUG_MANAGER (self));
+  g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
+
+  if (self->debugger != NULL)
+    {
+      ide_debugger_insert_breakpoint_async (self->debugger, breakpoint, NULL, NULL, NULL);
+      IDE_EXIT;
+    }
+
+  path = ide_debugger_breakpoint_get_file (breakpoint);
+
+  if (path == NULL)
+    {
+      /* We don't know where this breakpoint is because it's either an
+       * address, function, expression, etc. So we just need to queue
+       * it until the debugger starts.
+       */
+TODO:
+      IDE_EXIT;
+    }
+
+  file = g_file_new_for_path (path);
+  breakpoints = ide_debug_manager_get_breakpoints_for_file (self, file);
+  _ide_debugger_breakpoints_add (breakpoints, breakpoint);
+
+  IDE_EXIT;
+}
+
+/**
+ * _ide_debug_manager_remove_breakpoint:
+ * @self: An #IdeDebugManager
+ * @breakpoint: An #IdeDebuggerBreakpoint
+ *
+ * This removes an exiting breakpoint. If the debugger has been started, it
+ * is done by notifying the debugger to remove the breakpoint. If there is
+ * not an active debugger, then it is done by removing the cached breakpoint.
+ *
+ * Since: 3.26
+ */
+void
+_ide_debug_manager_remove_breakpoint (IdeDebugManager       *self,
+                                      IdeDebuggerBreakpoint *breakpoint)
+{
+  g_autoptr(GFile) file = NULL;
+  IdeDebuggerBreakpoints *breakpoints;
+  const gchar *path;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_DEBUG_MANAGER (self));
+  g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
+
+  if (self->debugger != NULL)
+    {
+      /* Just ask the debugger to remove it, we'll update the breakpoints
+       * list when we get the #IdeDebugger::breakpoint-removed signal.
+       */
+      ide_debugger_remove_breakpoint_async (self->debugger, breakpoint, NULL, NULL, NULL);
+      IDE_EXIT;
+    }
+
+  /* Nothing we can do if this is a memory address-based breakpoint */
+  if (NULL == (path = ide_debugger_breakpoint_get_file (breakpoint)))
+    IDE_EXIT;
+
+  file = g_file_new_for_path (path);
+  breakpoints = g_hash_table_lookup (self->breakpoints, file);
+  if (breakpoints != NULL)
+    _ide_debugger_breakpoints_remove (breakpoints, breakpoint);
+
+  IDE_EXIT;
+}
diff --git a/libide/debugger/ide-debug-manager.h b/libide/debugger/ide-debug-manager.h
index 076d4df..be7e0ec 100644
--- a/libide/debugger/ide-debug-manager.h
+++ b/libide/debugger/ide-debug-manager.h
@@ -20,7 +20,7 @@
 
 #include "ide-object.h"
 
-#include "ide-debugger-breakpoints.h"
+#include "debugger/ide-debugger-breakpoints.h"
 
 G_BEGIN_DECLS
 
diff --git a/libide/debugger/ide-debugger-breakpoint.c b/libide/debugger/ide-debugger-breakpoint.c
index bbe57ea..27cbdbf 100644
--- a/libide/debugger/ide-debugger-breakpoint.c
+++ b/libide/debugger/ide-debugger-breakpoint.c
@@ -386,6 +386,9 @@ ide_debugger_breakpoint_class_init (IdeDebuggerBreakpointClass *klass)
 static void
 ide_debugger_breakpoint_init (IdeDebuggerBreakpoint *self)
 {
+  IdeDebuggerBreakpointPrivate *priv = ide_debugger_breakpoint_get_instance_private (self);
+
+  priv->mode = IDE_DEBUGGER_BREAK_BREAKPOINT;
 }
 
 IdeDebuggerBreakpoint *
diff --git a/libide/debugger/ide-debugger-breakpoints.c b/libide/debugger/ide-debugger-breakpoints.c
index 07a7e91..74f3021 100644
--- a/libide/debugger/ide-debugger-breakpoints.c
+++ b/libide/debugger/ide-debugger-breakpoints.c
@@ -23,6 +23,7 @@
 #include "ide-debug.h"
 
 #include "debugger/ide-debugger-breakpoints.h"
+#include "debugger/ide-debugger-private.h"
 
 /**
  * SECTION:ide-debugger-breakpoints
@@ -184,10 +185,44 @@ ide_debugger_breakpoints_init (IdeDebuggerBreakpoints *self)
 {
 }
 
-IdeDebuggerBreakMode
+/**
+ * ide_debugger_breakpoints_get_line:
+ * @self: An #IdeDebuggerBreakpoints
+ * @line: The line number
+ *
+ * Gets the breakpoint that has been registered at a given line, or %NULL
+ * if no breakpoint is registered there.
+ *
+ * Returns: (nullable) (transfer none): An #IdeDebuggerBreakpoint or %NULL
+ *
+ * Since: 3.26
+ */
+IdeDebuggerBreakpoint *
 ide_debugger_breakpoints_get_line (IdeDebuggerBreakpoints *self,
                                    guint                   line)
 {
+  g_return_val_if_fail (IDE_IS_DEBUGGER_BREAKPOINTS (self), NULL);
+
+  if (self->lines != NULL)
+    {
+      LineInfo info = { line, 0 };
+      LineInfo *ret;
+
+      ret = bsearch (&info, (gpointer)self->lines->data,
+                     self->lines->len, sizeof (LineInfo),
+                     line_info_compare);
+
+      if (ret)
+        return ret->breakpoint;
+    }
+
+  return NULL;
+}
+
+IdeDebuggerBreakMode
+ide_debugger_breakpoints_get_line_mode (IdeDebuggerBreakpoints *self,
+                                        guint                   line)
+{
   g_return_val_if_fail (IDE_IS_DEBUGGER_BREAKPOINTS (self), 0);
 
   if (self->lines != NULL)
@@ -206,14 +241,18 @@ ide_debugger_breakpoints_get_line (IdeDebuggerBreakpoints *self,
   return 0;
 }
 
-void
+static void
 ide_debugger_breakpoints_set_line (IdeDebuggerBreakpoints *self,
                                    guint                   line,
-                                   IdeDebuggerBreakMode    mode)
+                                   IdeDebuggerBreakMode    mode,
+                                   IdeDebuggerBreakpoint  *breakpoint)
 {
   LineInfo info;
 
-  g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINTS (self));
+  g_assert (IDE_IS_DEBUGGER_BREAKPOINTS (self));
+  g_assert (IDE_IS_DEBUGGER_BREAK_MODE (mode));
+  g_assert (!breakpoint || IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
+  g_assert (mode == IDE_DEBUGGER_BREAK_NONE || breakpoint != NULL);
 
   if (self->lines != NULL)
     {
@@ -223,15 +262,20 @@ ide_debugger_breakpoints_set_line (IdeDebuggerBreakpoints *self,
 
           if (ele->line == line)
             {
-              if (mode != 0)
-                ele->mode = mode;
+              if (mode != IDE_DEBUGGER_BREAK_NONE)
+                {
+                  ele->mode = mode;
+                  g_set_object (&ele->breakpoint, breakpoint);
+                }
               else
                 g_array_remove_index (self->lines, i);
+
               goto emit_signal;
             }
         }
     }
 
+  /* Nothing to do here */
   if (mode == IDE_DEBUGGER_BREAK_NONE)
     return;
 
@@ -243,6 +287,7 @@ ide_debugger_breakpoints_set_line (IdeDebuggerBreakpoints *self,
 
   info.line = line;
   info.mode = mode;
+  info.breakpoint = g_object_ref (breakpoint);
 
   g_array_append_val (self->lines, info);
   g_array_sort (self->lines, line_info_compare);
@@ -250,3 +295,64 @@ ide_debugger_breakpoints_set_line (IdeDebuggerBreakpoints *self,
 emit_signal:
   g_signal_emit (self, signals [CHANGED], 0);
 }
+
+void
+_ide_debugger_breakpoints_add (IdeDebuggerBreakpoints *self,
+                               IdeDebuggerBreakpoint  *breakpoint)
+{
+  IdeDebuggerBreakMode mode;
+  guint line;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINTS (self));
+  g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
+
+  line = ide_debugger_breakpoint_get_line (breakpoint);
+  mode = ide_debugger_breakpoint_get_mode (breakpoint);
+
+  IDE_TRACE_MSG ("tracking breakpoint at line %d [breakpoints=%p]",
+                 line, self);
+
+  ide_debugger_breakpoints_set_line (self, line, mode, breakpoint);
+
+  IDE_EXIT;
+}
+
+void
+_ide_debugger_breakpoints_remove (IdeDebuggerBreakpoints *self,
+                                  IdeDebuggerBreakpoint  *breakpoint)
+{
+  guint line;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINTS (self));
+  g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
+
+  line = ide_debugger_breakpoint_get_line (breakpoint);
+
+  IDE_TRACE_MSG ("removing breakpoint at line %d [breakpoints=%p]",
+                 line, self);
+
+  ide_debugger_breakpoints_set_line (self, line, IDE_DEBUGGER_BREAK_NONE, NULL);
+
+  IDE_EXIT;
+}
+
+/**
+ * ide_debugger_breakpoints_get_file:
+ * @self: An #IdeDebuggerBreakpoints
+ *
+ * Gets the "file" property, which is the file that breakpoints within
+ * this container belong to.
+ *
+ * Returns: (transfer none): A #GFile
+ */
+GFile *
+ide_debugger_breakpoints_get_file (IdeDebuggerBreakpoints *self)
+{
+  g_return_val_if_fail (IDE_IS_DEBUGGER_BREAKPOINTS (self), NULL);
+
+  return self->file;
+}
diff --git a/libide/debugger/ide-debugger-breakpoints.h b/libide/debugger/ide-debugger-breakpoints.h
index 1db82c4..d15bb03 100644
--- a/libide/debugger/ide-debugger-breakpoints.h
+++ b/libide/debugger/ide-debugger-breakpoints.h
@@ -20,6 +20,7 @@
 
 #include <glib-object.h>
 
+#include "ide-debugger-breakpoint.h"
 #include "ide-debugger-types.h"
 
 G_BEGIN_DECLS
@@ -28,10 +29,10 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeDebuggerBreakpoints, ide_debugger_breakpoints, IDE, DEBUGGER_BREAKPOINTS, GObject)
 
-IdeDebuggerBreakMode ide_debugger_breakpoints_get_line (IdeDebuggerBreakpoints *self,
-                                                        guint                   line);
-void                 ide_debugger_breakpoints_set_line (IdeDebuggerBreakpoints *self,
-                                                        guint                   line,
-                                                        IdeDebuggerBreakMode    mode);
+GFile                 *ide_debugger_breakpoints_get_file      (IdeDebuggerBreakpoints *self);
+IdeDebuggerBreakMode   ide_debugger_breakpoints_get_line_mode (IdeDebuggerBreakpoints *self,
+                                                               guint                   line);
+IdeDebuggerBreakpoint *ide_debugger_breakpoints_get_line      (IdeDebuggerBreakpoints *self,
+                                                               guint                   line);
 
 G_END_DECLS
diff --git a/libide/debugger/ide-debugger-editor-view-addin.c 
b/libide/debugger/ide-debugger-editor-view-addin.c
index 38762b0..da21d5d 100644
--- a/libide/debugger/ide-debugger-editor-view-addin.c
+++ b/libide/debugger/ide-debugger-editor-view-addin.c
@@ -18,8 +18,14 @@
 
 #define G_LOG_DOMAIN "ide-debugger-editor-view-addin"
 
+#include "ide-context.h"
+#include "ide-debug.h"
+
+#include "debugger/ide-debug-manager.h"
 #include "debugger/ide-debugger-editor-view-addin.h"
 #include "debugger/ide-debugger-gutter-renderer.h"
+#include "files/ide-file.h"
+#include "util/ide-gtk.h"
 
 struct _IdeDebuggerEditorViewAddin
 {
@@ -35,25 +41,42 @@ ide_debugger_editor_view_addin_load (IdeEditorViewAddin *addin,
 {
   IdeDebuggerEditorViewAddin *self = (IdeDebuggerEditorViewAddin *)addin;
   g_autoptr(IdeDebuggerBreakpoints) breakpoints = NULL;
+  IdeDebugManager *debug_manager;
   IdeSourceView *source_view;
   GtkSourceGutter *gutter;
+  IdeContext *context;
+  IdeBuffer *buffer;
+  IdeFile *file;
+  GFile *gfile;
+
+  IDE_ENTRY;
 
   g_assert (IDE_IS_DEBUGGER_EDITOR_VIEW_ADDIN (self));
   g_assert (IDE_IS_EDITOR_VIEW (view));
 
   self->view = view;
 
-  /* TODO: Wire up breakpoints to debugger instance for this file */
-  breakpoints = g_object_new (IDE_TYPE_DEBUGGER_BREAKPOINTS, NULL);
+  context = ide_widget_get_context (GTK_WIDGET (view));
+  debug_manager = ide_context_get_debug_manager (context);
+
+  buffer = ide_editor_view_get_buffer (view);
+  file = ide_buffer_get_file (buffer);
+  gfile = ide_file_get_file (file);
 
   /* Install the breakpoints gutter */
+  breakpoints = ide_debug_manager_get_breakpoints_for_file (debug_manager, gfile);
   source_view = ide_editor_view_get_view (view);
   gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (source_view), GTK_TEXT_WINDOW_LEFT);
   self->renderer = g_object_new (IDE_TYPE_DEBUGGER_GUTTER_RENDERER,
+                                 "debug-manager", debug_manager,
+                                 "breakpoints", breakpoints,
                                  "size", 16,
                                  NULL);
-  ide_debugger_gutter_renderer_set_breakpoints (self->renderer, breakpoints);
   gtk_source_gutter_insert (gutter, GTK_SOURCE_GUTTER_RENDERER (self->renderer), -100);
+
+  /* TODO: Monitor IdeBuffer:file? */
+
+  IDE_EXIT;
 }
 
 static void
@@ -64,6 +87,8 @@ ide_debugger_editor_view_addin_unload (IdeEditorViewAddin *addin,
   IdeSourceView *source_view;
   GtkSourceGutter *gutter;
 
+  IDE_ENTRY;
+
   g_assert (IDE_IS_DEBUGGER_EDITOR_VIEW_ADDIN (self));
   g_assert (IDE_IS_EDITOR_VIEW (view));
 
@@ -73,6 +98,8 @@ ide_debugger_editor_view_addin_unload (IdeEditorViewAddin *addin,
 
   self->renderer = NULL;
   self->view = NULL;
+
+  IDE_EXIT;
 }
 
 static void
diff --git a/libide/debugger/ide-debugger-gutter-renderer.c b/libide/debugger/ide-debugger-gutter-renderer.c
index 89d3aac..ae1aa27 100644
--- a/libide/debugger/ide-debugger-gutter-renderer.c
+++ b/libide/debugger/ide-debugger-gutter-renderer.c
@@ -22,13 +22,28 @@
 
 #include "ide-debug.h"
 
-#include "debugger/ide-debugger-gutter-renderer.h"
+#include "debugger/ide-debug-manager.h"
 #include "debugger/ide-debugger-breakpoints.h"
+#include "debugger/ide-debugger-gutter-renderer.h"
+#include "debugger/ide-debugger-private.h"
+
+/**
+ * SECTION:ide-debugger-gutter-renderer
+ * @title: IdeDebuggerGutterRenderer
+ * @short_description: A gutter for debugger breakpoints
+ *
+ * The #IdeDebuggerGutterRenderer is used to show the breakpoints
+ * within the gutter of a source editor. When clicking on a row, you
+ * can set a breakpoint on the line as well.
+ *
+ * Since: 3.26
+ */
 
 struct _IdeDebuggerGutterRenderer
 {
   GtkSourceGutterRendererPixbuf  parent_instance;
   IdeDebuggerBreakpoints        *breakpoints;
+  IdeDebugManager               *debug_manager;
   gulong                         breakpoints_changed_handler;
 };
 
@@ -37,6 +52,7 @@ G_DEFINE_TYPE (IdeDebuggerGutterRenderer, ide_debugger_gutter_renderer, GTK_SOUR
 enum {
   PROP_0,
   PROP_BREAKPOINTS,
+  PROP_DEBUG_MANAGER,
   N_PROPS
 };
 
@@ -48,40 +64,65 @@ ide_debugger_gutter_renderer_activate (IdeDebuggerGutterRenderer *self,
                                        GdkRectangle              *area,
                                        GdkEvent                  *event)
 {
-  IdeDebuggerBreakMode break_type;
+  IdeDebuggerBreakpoint *breakpoint;
+  IdeDebuggerBreakMode break_type = IDE_DEBUGGER_BREAK_NONE;
+  g_autofree gchar *path = NULL;
+  GFile *file;
   guint line;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_DEBUGGER_GUTTER_RENDERER (self));
+  g_assert (self->breakpoints != NULL);
+  g_assert (self->debug_manager != NULL);
   g_assert (iter != NULL);
   g_assert (area != NULL);
   g_assert (event != NULL);
 
   line = gtk_text_iter_get_line (iter) + 1;
+  file = ide_debugger_breakpoints_get_file (self->breakpoints);
+  path = g_file_get_path (file);
 
-  IDE_TRACE_MSG ("Toggle breakpoint on line %u", line);
+  /* TODO: Should we show a Popover here to select the type? */
+  IDE_TRACE_MSG ("Toggle breakpoint on line %u [breakpoints=%p]",
+                 line, self->breakpoints);
 
-  break_type = ide_debugger_breakpoints_get_line (self->breakpoints, line);
+  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:
-      /* TOOD: Register with real debug manager */
-      ide_debugger_breakpoints_set_line (self->breakpoints, line, IDE_DEBUGGER_BREAK_BREAKPOINT);
+      {
+        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_debug_manager_add_breakpoint (self->debug_manager, to_insert);
+      }
       break;
 
     case IDE_DEBUGGER_BREAK_BREAKPOINT:
     case IDE_DEBUGGER_BREAK_COUNTPOINT:
     case IDE_DEBUGGER_BREAK_WATCHPOINT:
-      /* TOOD: Register with real debug manager */
-      ide_debugger_breakpoints_set_line (self->breakpoints, line, 0);
+      if (breakpoint != NULL)
+        _ide_debug_manager_remove_breakpoint (self->debug_manager, breakpoint);
       break;
 
     default:
-      break;
+      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;
 }
 
@@ -96,7 +137,7 @@ ide_debugger_gutter_renderer_query_activatable (IdeDebuggerGutterRenderer *self,
   g_assert (area != NULL);
   g_assert (event != NULL);
 
-  return TRUE;
+  return self->breakpoints != NULL && self->debug_manager != NULL;
 }
 
 static void
@@ -116,7 +157,7 @@ ide_debugger_gutter_renderer_query_data (IdeDebuggerGutterRenderer    *self,
     return;
 
   line = gtk_text_iter_get_line (begin) + 1;
-  break_type = ide_debugger_breakpoints_get_line (self->breakpoints, line);
+  break_type = ide_debugger_breakpoints_get_line_mode (self->breakpoints, line);
 
   /*
    * These are very much a miss-appropriation of the icon, but it works
@@ -129,24 +170,29 @@ ide_debugger_gutter_renderer_query_data (IdeDebuggerGutterRenderer    *self,
   switch (break_type)
     {
     case IDE_DEBUGGER_BREAK_BREAKPOINT:
-      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self), 
BREAKPOINT_ICON_NAME);
+      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self),
+                                                       BREAKPOINT_ICON_NAME);
       break;
 
     case IDE_DEBUGGER_BREAK_COUNTPOINT:
-      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self), 
COUNTPOINT_ICON_NAME);
+      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self),
+                                                       COUNTPOINT_ICON_NAME);
       break;
 
     case IDE_DEBUGGER_BREAK_WATCHPOINT:
-      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self), 
WATCHPOINT_ICON_NAME);
+      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self),
+                                                       WATCHPOINT_ICON_NAME);
       break;
 
     case IDE_DEBUGGER_BREAK_NONE:
-    default:
       /* Setting pixbuf to NULL via g_object_set() seems to be
        * the only way to clear this without g_warning()s.
        */
       g_object_set (self, "pixbuf", NULL, NULL);
       break;
+
+    default:
+      g_return_if_reached ();
     }
 
 #undef BREAKPOINT_ICON_NAME
@@ -168,8 +214,8 @@ void
 ide_debugger_gutter_renderer_set_breakpoints (IdeDebuggerGutterRenderer *self,
                                               IdeDebuggerBreakpoints    *breakpoints)
 {
-  g_return_if_fail (IDE_IS_DEBUGGER_GUTTER_RENDERER (self));
-  g_return_if_fail (!breakpoints || IDE_IS_DEBUGGER_BREAKPOINTS (breakpoints));
+  g_assert (IDE_IS_DEBUGGER_GUTTER_RENDERER (self));
+  g_assert (!breakpoints || IDE_IS_DEBUGGER_BREAKPOINTS (breakpoints));
 
   if (self->breakpoints != breakpoints)
     {
@@ -196,13 +242,14 @@ ide_debugger_gutter_renderer_set_breakpoints (IdeDebuggerGutterRenderer *self,
 }
 
 static void
-ide_debugger_gutter_renderer_finalize (GObject *object)
+ide_debugger_gutter_renderer_dispose (GObject *object)
 {
   IdeDebuggerGutterRenderer *self = (IdeDebuggerGutterRenderer *)object;
 
-  g_clear_object (&self->breakpoints);
+  ide_debugger_gutter_renderer_set_breakpoints (self, NULL);
+  g_clear_object (&self->debug_manager);
 
-  G_OBJECT_CLASS (ide_debugger_gutter_renderer_parent_class)->finalize (object);
+  G_OBJECT_CLASS (ide_debugger_gutter_renderer_parent_class)->dispose (object);
 }
 
 static void
@@ -219,6 +266,10 @@ ide_debugger_gutter_renderer_get_property (GObject    *object,
       g_value_set_object (value, self->breakpoints);
       break;
 
+    case PROP_DEBUG_MANAGER:
+      g_value_set_object (value, self->debug_manager);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -238,6 +289,10 @@ ide_debugger_gutter_renderer_set_property (GObject      *object,
       ide_debugger_gutter_renderer_set_breakpoints (self, g_value_get_object (value));
       break;
 
+    case PROP_DEBUG_MANAGER:
+      self->debug_manager = g_value_dup_object (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -248,10 +303,19 @@ ide_debugger_gutter_renderer_class_init (IdeDebuggerGutterRendererClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  object_class->finalize = ide_debugger_gutter_renderer_finalize;
+  object_class->dispose = ide_debugger_gutter_renderer_dispose;
   object_class->get_property = ide_debugger_gutter_renderer_get_property;
   object_class->set_property = ide_debugger_gutter_renderer_set_property;
 
+  /**
+   * IdeDebuggerGutterRenderer:breakpoints:
+   *
+   * The "breakpoints" property is an #IdeDebuggerBreakpoints that can be
+   * used to quickly determine if a row has a breakpoint set, and what
+   * type of breakpoint that is.
+   *
+   * Since: 3.26
+   */
   properties [PROP_BREAKPOINTS] =
     g_param_spec_object ("breakpoints",
                          "Breakpoints",
@@ -259,6 +323,21 @@ ide_debugger_gutter_renderer_class_init (IdeDebuggerGutterRendererClass *klass)
                          IDE_TYPE_DEBUGGER_BREAKPOINTS,
                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  /**
+   * IdeDebuggerGutterRenderer:debug-manager:
+   *
+   * The "debug-manager" property is the #IdeDebugManager that can be
+   * used to alter breakpoints in the debugger.
+   *
+   * Since: 3.26
+   */
+  properties [PROP_DEBUG_MANAGER] =
+    g_param_spec_object ("debug-manager",
+                         "Debug Manager",
+                         "Debug Manager",
+                         IDE_TYPE_DEBUG_MANAGER,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
@@ -281,8 +360,27 @@ ide_debugger_gutter_renderer_init (IdeDebuggerGutterRenderer *self)
                     NULL);
 }
 
+/**
+ * ide_debugger_gutter_renderer_new:
+ * @debug_manager: An #IdeDebugManager
+ *
+ * Creates a new #IdeDebuggerGutterRenderer.
+ *
+ * @debug_manager should be the #IdeDebugManager for the #IdeContext of the
+ * current project. This is used to manipulate breakpoints whether or not
+ * the debugger is currently active. This allows for breakpoints to be synced
+ * after the debugger instance is spawned.
+ *
+ * Returns: (transfer full): A new #IdeDebuggerGutterRenderer.
+ *
+ * Since: 3.26
+ */
 GtkSourceGutterRenderer *
-ide_debugger_gutter_renderer_new (void)
+ide_debugger_gutter_renderer_new (IdeDebugManager *debug_manager)
 {
-  return g_object_new (IDE_TYPE_DEBUGGER_GUTTER_RENDERER, NULL);
+  g_return_val_if_fail (IDE_IS_DEBUG_MANAGER (debug_manager), NULL);
+
+  return g_object_new (IDE_TYPE_DEBUGGER_GUTTER_RENDERER,
+                       "debug-manager", debug_manager,
+                       NULL);
 }
diff --git a/libide/debugger/ide-debugger-gutter-renderer.h b/libide/debugger/ide-debugger-gutter-renderer.h
index dd11d35..07c0bcf 100644
--- a/libide/debugger/ide-debugger-gutter-renderer.h
+++ b/libide/debugger/ide-debugger-gutter-renderer.h
@@ -22,6 +22,7 @@
 
 #include "ide-types.h"
 
+#include "debugger/ide-debug-manager.h"
 #include "debugger/ide-debugger-breakpoints.h"
 
 G_BEGIN_DECLS
@@ -30,7 +31,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeDebuggerGutterRenderer, ide_debugger_gutter_renderer, IDE, 
DEBUGGER_GUTTER_RENDERER, GtkSourceGutterRendererPixbuf)
 
-GtkSourceGutterRenderer *ide_debugger_gutter_renderer_new             (void);
+GtkSourceGutterRenderer *ide_debugger_gutter_renderer_new             (IdeDebugManager           
*debug_manager);
 void                     ide_debugger_gutter_renderer_set_breakpoints (IdeDebuggerGutterRenderer *self,
                                                                        IdeDebuggerBreakpoints    
*breakpoints);
 
diff --git a/libide/debugger/ide-debugger-private.h b/libide/debugger/ide-debugger-private.h
index fd20f5b..bc2a39b 100644
--- a/libide/debugger/ide-debugger-private.h
+++ b/libide/debugger/ide-debugger-private.h
@@ -24,8 +24,14 @@
 
 G_BEGIN_DECLS
 
-IdeDebuggerBreakpoints *_ide_debug_manager_get_breakpoints          (IdeDebugManager                *self,
-                                                                     GFile                          *file);
+void                    _ide_debug_manager_add_breakpoint           (IdeDebugManager                *self,
+                                                                     IdeDebuggerBreakpoint          
*breakpoint);
+void                    _ide_debug_manager_remove_breakpoint        (IdeDebugManager                *self,
+                                                                     IdeDebuggerBreakpoint          
*breakpoint);
+void                    _ide_debugger_breakpoints_add               (IdeDebuggerBreakpoints         *self,
+                                                                     IdeDebuggerBreakpoint          
*breakpoint);
+void                    _ide_debugger_breakpoints_remove            (IdeDebuggerBreakpoints         *self,
+                                                                     IdeDebuggerBreakpoint          
*breakpoint);
 void                    _ide_debugger_class_init_actions            (GActionGroupInterface          *iface);
 void                    _ide_debugger_update_actions                (IdeDebugger                    *self);
 gboolean                _ide_debugger_get_has_started               (IdeDebugger                    *self);
diff --git a/libide/ide.h b/libide/ide.h
index 7727364..8fc7a54 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -64,6 +64,7 @@ G_BEGIN_DECLS
 #include "buildsystem/ide-environment.h"
 #include "debugger/ide-debug-manager.h"
 #include "debugger/ide-debugger-breakpoint.h"
+#include "debugger/ide-debugger-breakpoints.h"
 #include "debugger/ide-debugger-frame.h"
 #include "debugger/ide-debugger-instruction.h"
 #include "debugger/ide-debugger-library.h"
diff --git a/libide/meson.build b/libide/meson.build
index a6f73a6..c12c4f2 100644
--- a/libide/meson.build
+++ b/libide/meson.build
@@ -87,6 +87,7 @@ libide_public_headers = [
   'buildsystem/ide-environment.h',
   'debugger/ide-debug-manager.h',
   'debugger/ide-debugger-breakpoint.h',
+  'debugger/ide-debugger-breakpoints.h',
   'debugger/ide-debugger-frame.h',
   'debugger/ide-debugger-instruction.h',
   'debugger/ide-debugger-library.h',
@@ -303,6 +304,7 @@ libide_public_sources = [
   'buildsystem/ide-environment.c',
   'debugger/ide-debug-manager.c',
   'debugger/ide-debugger-breakpoint.c',
+  'debugger/ide-debugger-breakpoints.c',
   'debugger/ide-debugger-frame.c',
   'debugger/ide-debugger-instruction.c',
   'debugger/ide-debugger-library.c',
@@ -524,8 +526,6 @@ libide_sources = libide_generated_headers + libide_public_sources + [
   'debugger/ide-debugger-editor-view-addin.c',
   'debugger/ide-debugger-editor-view-addin.h',
   'debugger/ide-debugger-fallbacks.c',
-  'debugger/ide-debugger-breakpoints.c',
-  'debugger/ide-debugger-breakpoints.h',
   'debugger/ide-debugger-gutter-renderer.c',
   'debugger/ide-debugger-gutter-renderer.h',
   'debugger/ide-debugger-libraries-view.c',


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