[gnome-builder/wip/chergert/debugger] debugger: track debugger location in debugger view
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/debugger] debugger: track debugger location in debugger view
- Date: Thu, 13 Apr 2017 08:16:48 +0000 (UTC)
commit d1875f5038b4c9a52f6921fb1db1ff049de08551
Author: Christian Hergert <chergert redhat com>
Date: Mon Apr 10 12:53:03 2017 -0700
debugger: track debugger location in debugger view
This still needs lots of work, but it does some really basic plumbing that
we can iterate on from here.
libide/Makefile.am | 2 +
libide/debugger/ide-breakpoint.c | 149 +++++++++++++++-
libide/debugger/ide-breakpoint.h | 35 +++--
libide/debugger/ide-debug-manager.c | 14 +-
libide/debugger/ide-debugger-gutter-renderer.c | 2 +-
libide/debugger/ide-debugger-gutter-renderer.h | 7 +-
libide/debugger/ide-debugger-perspective.c | 112 +++++++++++-
libide/debugger/ide-debugger-perspective.h | 8 +-
libide/debugger/ide-debugger-view.c | 185 ++++++++++++++++++
libide/debugger/ide-debugger-view.h | 39 ++++
libide/debugger/ide-debugger-view.ui | 20 ++
libide/debugger/ide-debugger-workbench-addin.c | 97 +----------
libide/debugger/ide-debugger.c | 240 +++++++++++++++++++++++-
libide/debugger/ide-debugger.h | 70 +++++---
libide/ide-types.h | 1 +
libide/ide.h | 1 +
libide/resources/libide.gresource.xml | 1 +
plugins/gdb/gbp-gdb-debugger.c | 35 ++--
po/POTFILES.in | 1 +
19 files changed, 852 insertions(+), 167 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 2d24811..8dc9ee0 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -57,6 +57,7 @@ libide_1_0_la_public_headers = \
debugger/ide-debugger-perspective.h \
debugger/ide-debugger-workbench-addin.h \
debugger/ide-debugger-gutter-renderer.h \
+ debugger/ide-debugger-view.h \
devices/ide-device-manager.h \
devices/ide-device-provider.h \
devices/ide-device.h \
@@ -246,6 +247,7 @@ libide_1_0_la_public_sources = \
debugger/ide-debugger-perspective.c \
debugger/ide-debugger-workbench-addin.c \
debugger/ide-debugger-gutter-renderer.c \
+ debugger/ide-debugger-view.c \
devices/ide-device-manager.c \
devices/ide-device-provider.c \
devices/ide-device.c \
diff --git a/libide/debugger/ide-breakpoint.c b/libide/debugger/ide-breakpoint.c
index adaaa54..0b9a9de 100644
--- a/libide/debugger/ide-breakpoint.c
+++ b/libide/debugger/ide-breakpoint.c
@@ -23,17 +23,23 @@
typedef struct
{
gchar *id;
+ gchar *address;
GFile *file;
guint line;
+ guint line_offset;
guint enabled : 1;
+ guint transient : 1;
} IdeBreakpointPrivate;
enum {
PROP_0,
+ PROP_ADDRESS,
PROP_ENABLED,
PROP_FILE,
PROP_ID,
PROP_LINE,
+ PROP_LINE_OFFSET,
+ PROP_TRANSIENT,
N_PROPS
};
@@ -47,6 +53,7 @@ ide_breakpoint_finalize (GObject *object)
IdeBreakpoint *self = (IdeBreakpoint *)object;
IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+ g_clear_pointer (&priv->address, g_free);
g_clear_object (&priv->file);
g_clear_pointer (&priv->id, g_free);
@@ -63,6 +70,10 @@ ide_breakpoint_get_property (GObject *object,
switch (prop_id)
{
+ case PROP_ADDRESS:
+ g_value_set_string (value, ide_breakpoint_get_address (self));
+ break;
+
case PROP_ENABLED:
g_value_set_boolean (value, ide_breakpoint_get_enabled (self));
break;
@@ -79,6 +90,14 @@ ide_breakpoint_get_property (GObject *object,
g_value_set_uint (value, ide_breakpoint_get_line (self));
break;
+ case PROP_LINE_OFFSET:
+ g_value_set_uint (value, ide_breakpoint_get_line_offset (self));
+ break;
+
+ case PROP_TRANSIENT:
+ g_value_set_boolean (value, ide_breakpoint_get_transient (self));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -94,6 +113,10 @@ ide_breakpoint_set_property (GObject *object,
switch (prop_id)
{
+ case PROP_ADDRESS:
+ ide_breakpoint_set_address (self, g_value_get_string (value));
+ break;
+
case PROP_ENABLED:
ide_breakpoint_set_enabled (self, g_value_get_boolean (value));
break;
@@ -110,6 +133,14 @@ ide_breakpoint_set_property (GObject *object,
ide_breakpoint_set_line (self, g_value_get_uint (value));
break;
+ case PROP_LINE_OFFSET:
+ ide_breakpoint_set_line_offset (self, g_value_get_uint (value));
+ break;
+
+ case PROP_TRANSIENT:
+ ide_breakpoint_set_transient (self, g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -124,6 +155,28 @@ ide_breakpoint_class_init (IdeBreakpointClass *klass)
object_class->get_property = ide_breakpoint_get_property;
object_class->set_property = ide_breakpoint_set_property;
+ /**
+ * IdeBreakpoint:address:
+ *
+ * The "address" property is used to denote the position of the program
+ * counter for this breakpoint. Typically, this is only need if the debugger
+ * cannot represent the breakpoint with the #IdeBreakpoint:file and
+ * #IdeBreakpoint:line properties.
+ *
+ * The #IdeDebugger might use this address to disassemble as necessary from
+ * ide_debugger_load_source_async() to retrieve the source.
+ *
+ * The address is a string, so that architectures different from the current
+ * system may be addressed, as those may be outside of the addressable range
+ * on the debugging host.
+ */
+ properties [PROP_ADDRESS] =
+ g_param_spec_string ("address",
+ "Address",
+ "Address of the program counter if no source is available",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
properties [PROP_ID] =
g_param_spec_string ("id",
"Id",
@@ -145,7 +198,16 @@ ide_breakpoint_class_init (IdeBreakpointClass *klass)
0,
G_MAXUINT,
0,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_LINE_OFFSET] =
+ g_param_spec_uint ("line-offset",
+ "Line Offset",
+ "The line offset, starting from 0",
+ 0,
+ G_MAXUINT,
+ 0,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
properties [PROP_ENABLED] =
g_param_spec_boolean ("enabled",
@@ -154,6 +216,13 @@ ide_breakpoint_class_init (IdeBreakpointClass *klass)
FALSE,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+ properties [PROP_TRANSIENT] =
+ g_param_spec_boolean ("transient",
+ "Transient",
+ "If the breakpoint is transient, and will go away upon continuing debugging",
+ FALSE,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_properties (object_class, N_PROPS, properties);
}
@@ -268,3 +337,81 @@ ide_breakpoint_set_enabled (IdeBreakpoint *self,
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENABLED]);
}
}
+
+gboolean
+ide_breakpoint_get_transient (IdeBreakpoint *self)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_BREAKPOINT (self), FALSE);
+
+ return priv->transient;
+}
+
+void
+ide_breakpoint_set_transient (IdeBreakpoint *self,
+ gboolean transient)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_BREAKPOINT (self));
+
+ transient = !!transient;
+
+ if (priv->transient != transient)
+ {
+ priv->transient = transient;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TRANSIENT]);
+ }
+}
+
+guint
+ide_breakpoint_get_line_offset (IdeBreakpoint *self)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_BREAKPOINT (self), 0);
+
+ return priv->line_offset;
+}
+
+void
+ide_breakpoint_set_line_offset (IdeBreakpoint *self,
+ guint line_offset)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_BREAKPOINT (self));
+
+ if (priv->line_offset != line_offset)
+ {
+ priv->line_offset = line_offset;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LINE_OFFSET]);
+ }
+}
+
+const gchar *
+ide_breakpoint_get_address (IdeBreakpoint *self)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_BREAKPOINT (self), NULL);
+
+ return priv->address;
+}
+
+void
+ide_breakpoint_set_address (IdeBreakpoint *self,
+ const gchar *address)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_BREAKPOINT (self));
+
+ if (g_strcmp0 (priv->address, address) != 0)
+ {
+ g_free (priv->address);
+ priv->address = g_strdup (address);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ADDRESS]);
+ }
+}
diff --git a/libide/debugger/ide-breakpoint.h b/libide/debugger/ide-breakpoint.h
index 72cd7c2..e3636dd 100644
--- a/libide/debugger/ide-breakpoint.h
+++ b/libide/debugger/ide-breakpoint.h
@@ -43,19 +43,28 @@ struct _IdeBreakpointClass
gpointer _reserved8;
};
-IdeBreakpoint *ide_breakpoint_new (void);
-const gchar *ide_breakpoint_get_id (IdeBreakpoint *self);
-void ide_breakpoint_set_id (IdeBreakpoint *self,
- const gchar *id);
-GFile *ide_breakpoint_get_file (IdeBreakpoint *self);
-void ide_breakpoint_set_file (IdeBreakpoint *self,
- GFile *file);
-guint ide_breakpoint_get_line (IdeBreakpoint *self);
-void ide_breakpoint_set_line (IdeBreakpoint *self,
- guint line);
-gboolean ide_breakpoint_get_enabled (IdeBreakpoint *self);
-void ide_breakpoint_set_enabled (IdeBreakpoint *self,
- gboolean enabled);
+IdeBreakpoint *ide_breakpoint_new (void);
+const gchar *ide_breakpoint_get_id (IdeBreakpoint *self);
+void ide_breakpoint_set_id (IdeBreakpoint *self,
+ const gchar *id);
+const gchar *ide_breakpoint_get_address (IdeBreakpoint *self);
+void ide_breakpoint_set_address (IdeBreakpoint *self,
+ const gchar *address);
+GFile *ide_breakpoint_get_file (IdeBreakpoint *self);
+void ide_breakpoint_set_file (IdeBreakpoint *self,
+ GFile *file);
+guint ide_breakpoint_get_line (IdeBreakpoint *self);
+void ide_breakpoint_set_line (IdeBreakpoint *self,
+ guint line);
+guint ide_breakpoint_get_line_offset (IdeBreakpoint *self);
+void ide_breakpoint_set_line_offset (IdeBreakpoint *self,
+ guint line);
+gboolean ide_breakpoint_get_enabled (IdeBreakpoint *self);
+void ide_breakpoint_set_enabled (IdeBreakpoint *self,
+ gboolean enabled);
+gboolean ide_breakpoint_get_transient (IdeBreakpoint *self);
+void ide_breakpoint_set_transient (IdeBreakpoint *self,
+ gboolean transient);
G_END_DECLS
diff --git a/libide/debugger/ide-debug-manager.c b/libide/debugger/ide-debug-manager.c
index 59906f5..3bb8a11 100644
--- a/libide/debugger/ide-debug-manager.c
+++ b/libide/debugger/ide-debug-manager.c
@@ -192,12 +192,13 @@ ide_debug_manager_action_continue (GSimpleAction *action,
static void
ide_debug_manager_debugger_stopped (IdeDebugManager *self,
IdeDebuggerStopReason reason,
- IdeSourceLocation *location,
+ IdeBreakpoint *breakpoint,
IdeDebugger *debugger)
{
IDE_ENTRY;
g_assert (IDE_IS_DEBUG_MANAGER (self));
+ g_assert (!breakpoint || IDE_IS_BREAKPOINT (breakpoint));
g_assert (IDE_IS_DEBUGGER (debugger));
switch (reason)
@@ -209,12 +210,19 @@ ide_debug_manager_debugger_stopped (IdeDebugManager *self,
ide_runner_force_quit (self->runner);
break;
- case IDE_DEBUGGER_STOP_UNDEFINED:
case IDE_DEBUGGER_STOP_BREAKPOINT:
case IDE_DEBUGGER_STOP_WATCHPOINT:
+ case IDE_DEBUGGER_STOP_UNDEFINED:
case IDE_DEBUGGER_STOP_SIGNALED:
- default:
+ if (breakpoint != NULL)
+ {
+ IDE_TRACE_MSG ("Emitting breakpoint-reached");
+ g_signal_emit (self, signals [BREAKPOINT_REACHED], 0, breakpoint);
+ }
break;
+
+ default:
+ g_assert_not_reached ();
}
IDE_EXIT;
diff --git a/libide/debugger/ide-debugger-gutter-renderer.c b/libide/debugger/ide-debugger-gutter-renderer.c
index 6a1bb3d..052de69 100644
--- a/libide/debugger/ide-debugger-gutter-renderer.c
+++ b/libide/debugger/ide-debugger-gutter-renderer.c
@@ -156,7 +156,7 @@ ide_debugger_gutter_renderer_breakpoints_changed (IdeDebuggerGutterRenderer *sel
gtk_source_gutter_renderer_queue_draw (GTK_SOURCE_GUTTER_RENDERER (self));
}
-static void
+void
ide_debugger_gutter_renderer_set_breakpoints (IdeDebuggerGutterRenderer *self,
IdeDebuggerBreakpoints *breakpoints)
{
diff --git a/libide/debugger/ide-debugger-gutter-renderer.h b/libide/debugger/ide-debugger-gutter-renderer.h
index e3780ff..e14a68e 100644
--- a/libide/debugger/ide-debugger-gutter-renderer.h
+++ b/libide/debugger/ide-debugger-gutter-renderer.h
@@ -20,7 +20,8 @@
#define IDE_DEBUGGER_GUTTER_RENDERER_H
#include <gtksourceview/gtksource.h>
-#include <ide.h>
+
+#include "ide-types.h"
G_BEGIN_DECLS
@@ -28,7 +29,9 @@ 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 (void);
+void ide_debugger_gutter_renderer_set_breakpoints (IdeDebuggerGutterRenderer *self,
+ IdeDebuggerBreakpoints
*breakpoints);
G_END_DECLS
diff --git a/libide/debugger/ide-debugger-perspective.c b/libide/debugger/ide-debugger-perspective.c
index 992fc3e..a8b6511 100644
--- a/libide/debugger/ide-debugger-perspective.c
+++ b/libide/debugger/ide-debugger-perspective.c
@@ -21,9 +21,14 @@
#include <egg-signal-group.h>
#include <glib/gi18n.h>
+#include "ide-debug.h"
+
#include "debugger/ide-debugger.h"
#include "debugger/ide-debugger-perspective.h"
+#include "debugger/ide-debugger-view.h"
#include "util/ide-pango.h"
+#include "workbench/ide-layout-grid.h"
+#include "workbench/ide-perspective.h"
struct _IdeDebuggerPerspective
{
@@ -36,6 +41,7 @@ struct _IdeDebuggerPerspective
GtkTextBuffer *log_buffer;
GtkTextView *log_text_view;
+ IdeLayoutGrid *layout_grid;
};
enum {
@@ -98,10 +104,12 @@ on_debugger_log (IdeDebuggerPerspective *self,
gtk_text_view_scroll_to_iter (self->log_text_view, &iter, 0.0, FALSE, 1.0, 1.0);
}
-static void
+void
ide_debugger_perspective_set_debugger (IdeDebuggerPerspective *self,
IdeDebugger *debugger)
{
+ IDE_ENTRY;
+
g_return_if_fail (IDE_IS_DEBUGGER_PERSPECTIVE (self));
g_return_if_fail (!debugger || IDE_IS_DEBUGGER (debugger));
@@ -111,6 +119,8 @@ ide_debugger_perspective_set_debugger (IdeDebuggerPerspective *self,
gtk_text_buffer_set_text (self->log_buffer, "", 0);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUGGER]);
}
+
+ IDE_EXIT;
}
static void
@@ -147,6 +157,24 @@ log_panel_changed_font_name (IdeDebuggerPerspective *self,
}
static void
+on_debugger_stopped (IdeDebuggerPerspective *self,
+ IdeDebuggerStopReason reason,
+ IdeBreakpoint *breakpoint,
+ IdeDebugger *debugger)
+{
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEBUGGER_PERSPECTIVE (self));
+ g_assert (!breakpoint || IDE_IS_BREAKPOINT (breakpoint));
+ g_assert (IDE_IS_DEBUGGER (debugger));
+
+ if (breakpoint != NULL)
+ ide_debugger_perspective_navigate_to_breakpoint (self, breakpoint);
+
+ IDE_EXIT;
+}
+
+static void
ide_debugger_perspective_finalize (GObject *object)
{
IdeDebuggerPerspective *self = (IdeDebuggerPerspective *)object;
@@ -217,7 +245,7 @@ ide_debugger_perspective_class_init (IdeDebuggerPerspectiveClass *klass)
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/builder/ui/ide-debugger-perspective.ui");
-
+ gtk_widget_class_bind_template_child (widget_class, IdeDebuggerPerspective, layout_grid);
gtk_widget_class_bind_template_child (widget_class, IdeDebuggerPerspective, log_text_view);
gtk_widget_class_bind_template_child (widget_class, IdeDebuggerPerspective, log_buffer);
}
@@ -237,6 +265,12 @@ ide_debugger_perspective_init (IdeDebuggerPerspective *self)
self,
G_CONNECT_SWAPPED);
+ egg_signal_group_connect_object (self->debugger_signals,
+ "stopped",
+ G_CALLBACK (on_debugger_stopped),
+ self,
+ G_CONNECT_SWAPPED);
+
self->log_css = gtk_css_provider_new ();
context = gtk_widget_get_style_context (GTK_WIDGET (self->log_text_view));
gtk_style_context_add_provider (context,
@@ -251,3 +285,77 @@ ide_debugger_perspective_init (IdeDebuggerPerspective *self)
G_CONNECT_SWAPPED);
log_panel_changed_font_name (self, "font-name", self->terminal_settings);
}
+
+static void
+ide_debugger_perspective_load_source_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeDebugger *debugger = (IdeDebugger *)object;
+ g_autoptr(IdeDebuggerPerspective) self = user_data;
+ g_autoptr(GtkSourceBuffer) buffer = NULL;
+ g_autoptr(GError) error = NULL;
+ IdeLayoutView *view;
+ GtkWidget *stack;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEBUGGER (debugger));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_DEBUGGER_PERSPECTIVE (self));
+
+ buffer = ide_debugger_load_source_finish (debugger, result, &error);
+
+ if (buffer == NULL)
+ {
+ g_warning ("%s", error->message);
+ IDE_GOTO (failure);
+ }
+
+ view = g_object_new (IDE_TYPE_DEBUGGER_VIEW,
+ "buffer", buffer,
+ "visible", TRUE,
+ NULL);
+
+ stack = ide_layout_grid_get_last_focus (self->layout_grid);
+ gtk_container_add (GTK_CONTAINER (stack), GTK_WIDGET (view));
+
+failure:
+ IDE_EXIT;
+}
+
+void
+ide_debugger_perspective_navigate_to_breakpoint (IdeDebuggerPerspective *self,
+ IdeBreakpoint *breakpoint)
+{
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_DEBUGGER_PERSPECTIVE (self));
+ g_return_if_fail (IDE_IS_BREAKPOINT (breakpoint));
+ g_return_if_fail (IDE_IS_DEBUGGER (self->debugger));
+
+ /*
+ * To display the source for the breakpoint, first we need to discover what
+ * file contains the source. If there is no file, then we need to ask the
+ * IdeDebugger to retrieve the disassembly for us so that we can show
+ * something "useful" to the developer.
+ *
+ * If we also fail to get the disassembly for the current breakpoint, we
+ * need to load some dummy text into a buffer to denote to the developer
+ * that technically they can click forward, but the behavior is rather
+ * undefined.
+ *
+ * If the file on disk is out of date (due to changes behind the scenes) we
+ * will likely catch that with a CRC check. We will show the file, but the
+ * user will have an infobar displayed that denotes that the file is not
+ * longer in sync with the debugged executable.
+ */
+
+ ide_debugger_load_source_async (self->debugger,
+ breakpoint,
+ NULL,
+ ide_debugger_perspective_load_source_cb,
+ g_object_ref (self));
+
+ IDE_EXIT;
+}
diff --git a/libide/debugger/ide-debugger-perspective.h b/libide/debugger/ide-debugger-perspective.h
index 18ee206..c03ce73 100644
--- a/libide/debugger/ide-debugger-perspective.h
+++ b/libide/debugger/ide-debugger-perspective.h
@@ -19,7 +19,8 @@
#ifndef IDE_DEBUGGER_PERSPECTIVE_H
#define IDE_DEBUGGER_PERSPECTIVE_H
-#include <ide.h>
+#include "debugger/ide-breakpoint.h"
+#include "workbench/ide-layout.h"
G_BEGIN_DECLS
@@ -27,6 +28,11 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeDebuggerPerspective, ide_debugger_perspective, IDE, DEBUGGER_PERSPECTIVE, IdeLayout)
+void ide_debugger_perspective_set_debugger (IdeDebuggerPerspective *self,
+ IdeDebugger *debugger);
+void ide_debugger_perspective_navigate_to_breakpoint (IdeDebuggerPerspective *self,
+ IdeBreakpoint *breakpoint);
+
G_END_DECLS
#endif /* IDE_DEBUGGER_PERSPECTIVE_H */
diff --git a/libide/debugger/ide-debugger-view.c b/libide/debugger/ide-debugger-view.c
new file mode 100644
index 0000000..34ad3df
--- /dev/null
+++ b/libide/debugger/ide-debugger-view.c
@@ -0,0 +1,185 @@
+/* ide-debugger-view.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-debugger-view"
+
+#include "ide-debug.h"
+
+#include "debugger/ide-debugger-breakpoints.h"
+#include "debugger/ide-debugger-gutter-renderer.h"
+#include "debugger/ide-debugger-view.h"
+#include "sourceview/ide-source-view.h"
+
+struct _IdeDebuggerView
+{
+ IdeLayoutView parent_instance;
+
+ IdeSourceView *source_view;
+ IdeDebuggerBreakpoints *breakpoints;
+ IdeDebuggerGutterRenderer *breakpoints_gutter;
+};
+
+enum {
+ PROP_0,
+ PROP_BUFFER,
+ N_PROPS
+};
+
+G_DEFINE_TYPE (IdeDebuggerView, ide_debugger_view, IDE_TYPE_LAYOUT_VIEW)
+
+static GParamSpec *properties [N_PROPS];
+
+static gchar *
+ide_debugger_view_get_title (IdeLayoutView *view)
+{
+ IdeDebuggerView *self = (IdeDebuggerView *)view;
+ const gchar *title;
+ IdeBuffer *buffer;
+
+ g_assert (IDE_IS_DEBUGGER_VIEW (self));
+
+ buffer = IDE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view)));
+ title = ide_buffer_get_title (buffer);
+
+ return g_strdup (title);
+}
+
+static void
+ide_debugger_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeDebuggerView *self = IDE_DEBUGGER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER:
+ g_value_set_object (value, ide_debugger_view_get_buffer (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_debugger_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeDebuggerView *self = IDE_DEBUGGER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER:
+ ide_debugger_view_set_buffer (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_debugger_view_class_init (IdeDebuggerViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ IdeLayoutViewClass *view_class = IDE_LAYOUT_VIEW_CLASS (klass);
+
+ object_class->get_property = ide_debugger_view_get_property;
+ object_class->set_property = ide_debugger_view_set_property;
+
+ view_class->get_title = ide_debugger_view_get_title;
+
+ properties [PROP_BUFFER] =
+ g_param_spec_object ("buffer",
+ "Buffer",
+ "The buffer for the view",
+ IDE_TYPE_BUFFER,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/ide-debugger-view.ui");
+ gtk_widget_class_bind_template_child (widget_class, IdeDebuggerView, source_view);
+}
+
+static void
+ide_debugger_view_init (IdeDebuggerView *self)
+{
+ GtkSourceGutter *gutter;
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (self->source_view),
+ GTK_TEXT_WINDOW_LEFT);
+ self->breakpoints_gutter = g_object_new (IDE_TYPE_DEBUGGER_GUTTER_RENDERER,
+ "visible", TRUE,
+ NULL);
+ gtk_source_gutter_insert (gutter, GTK_SOURCE_GUTTER_RENDERER (self->breakpoints_gutter), -100);
+}
+
+GtkWidget *
+ide_debugger_view_new (void)
+{
+ return g_object_new (IDE_TYPE_DEBUGGER_VIEW, NULL);
+}
+
+/**
+ * ide_debugger_view_get_buffer:
+ * @self: a #IdeDebuggerView
+ *
+ * Gets the buffer for the view.
+ *
+ * Returns: (transfer none): A #GtkSourceBuffer
+ */
+GtkSourceBuffer *
+ide_debugger_view_get_buffer (IdeDebuggerView *self)
+{
+ g_return_val_if_fail (IDE_IS_DEBUGGER_VIEW (self), NULL);
+
+ return GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view)));
+}
+
+void
+ide_debugger_view_set_buffer (IdeDebuggerView *self,
+ GtkSourceBuffer *buffer)
+{
+ g_return_if_fail (IDE_IS_DEBUGGER_VIEW (self));
+ g_return_if_fail (GTK_SOURCE_IS_BUFFER (buffer));
+
+ if (buffer != ide_debugger_view_get_buffer (self))
+ {
+ GtkSourceStyleScheme *scheme;
+ GtkSourceLanguage *language;
+
+ scheme = gtk_source_style_scheme_manager_get_scheme (gtk_source_style_scheme_manager_get_default (),
"builder-dark");
+ gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (buffer), scheme);
+
+ language = gtk_source_language_manager_get_language (gtk_source_language_manager_get_default (), "c");
+ gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language);
+
+ gtk_source_view_set_background_pattern (GTK_SOURCE_VIEW (self->source_view),
GTK_SOURCE_BACKGROUND_PATTERN_TYPE_GRID);
+
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->source_view), GTK_TEXT_BUFFER (buffer));
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUFFER]);
+ }
+}
diff --git a/libide/debugger/ide-debugger-view.h b/libide/debugger/ide-debugger-view.h
new file mode 100644
index 0000000..c311e08
--- /dev/null
+++ b/libide/debugger/ide-debugger-view.h
@@ -0,0 +1,39 @@
+/* ide-debugger-view.h
+ *
+ * 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/>.
+ */
+
+#ifndef IDE_DEBUGGER_VIEW_H
+#define IDE_DEBUGGER_VIEW_H
+
+#include <gtksourceview/gtksource.h>
+
+#include "workbench/ide-layout-view.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_DEBUGGER_VIEW (ide_debugger_view_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeDebuggerView, ide_debugger_view, IDE, DEBUGGER_VIEW, IdeLayoutView)
+
+GtkWidget *ide_debugger_view_new (void);
+GtkSourceBuffer *ide_debugger_view_get_buffer (IdeDebuggerView *self);
+void ide_debugger_view_set_buffer (IdeDebuggerView *self,
+ GtkSourceBuffer *buffer);
+
+G_END_DECLS
+
+#endif /* IDE_DEBUGGER_VIEW_H */
diff --git a/libide/debugger/ide-debugger-view.ui b/libide/debugger/ide-debugger-view.ui
new file mode 100644
index 0000000..b5c5d43
--- /dev/null
+++ b/libide/debugger/ide-debugger-view.ui
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<interface>
+ <template class="IdeDebuggerView" parent="IdeLayoutView">
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="expand">true</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="IdeSourceView" id="source_view">
+ <property name="highlight-current-line">true</property>
+ <property name="show-line-numbers">true</property>
+ <property name="monospace">true</property>
+ <property name="editable">false</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/libide/debugger/ide-debugger-workbench-addin.c b/libide/debugger/ide-debugger-workbench-addin.c
index 037c0b4..da35100 100644
--- a/libide/debugger/ide-debugger-workbench-addin.c
+++ b/libide/debugger/ide-debugger-workbench-addin.c
@@ -23,6 +23,8 @@
#include <egg-signal-group.h>
#include <gtksourceview/gtksource.h>
+#include "ide-debug.h"
+
#include "debugger/ide-breakpoint.h"
#include "debugger/ide-debug-manager.h"
#include "debugger/ide-debugger-controls.h"
@@ -112,36 +114,6 @@ controls_notify_child_revealed (IdeDebuggerWorkbenchAddin *self,
}
static void
-debug_manager_breakpoint_reached (IdeDebuggerWorkbenchAddin *self,
- IdeBreakpoint *breakpoint,
- IdeDebugger *debugger)
-{
- g_autoptr(IdeUri) uri = NULL;
- GFile *file;
- guint line;
-
- g_assert (IDE_IS_DEBUGGER_WORKBENCH_ADDIN (self));
- g_assert (IDE_IS_BREAKPOINT (breakpoint));
- g_assert (IDE_IS_DEBUGGER (debugger));
-
- if (NULL == (file = ide_breakpoint_get_file (breakpoint)) ||
- NULL == (uri = ide_uri_new_from_file (file)))
- return;
-
- if (0 != (line = ide_breakpoint_get_line (breakpoint)))
- {
- g_autofree gchar *fragment = g_strdup_printf ("L%u", line);
- ide_uri_set_fragment (uri, fragment);
- }
-
- ide_workbench_addin_open_async (IDE_WORKBENCH_ADDIN (self),
- uri,
- NULL,
- IDE_WORKBENCH_OPEN_FLAGS_NONE,
- NULL, NULL, NULL);
-}
-
-static void
ide_debugger_workbench_addin_load (IdeWorkbenchAddin *addin,
IdeWorkbench *workbench)
{
@@ -174,12 +146,6 @@ ide_debugger_workbench_addin_load (IdeWorkbenchAddin *addin,
self,
G_CONNECT_SWAPPED);
- egg_signal_group_connect_object (self->debug_manager_signals,
- "breakpoint-reached",
- G_CALLBACK (debug_manager_breakpoint_reached),
- self,
- G_CONNECT_SWAPPED);
-
egg_signal_group_set_target (self->debug_manager_signals, debug_manager);
self->controls = g_object_new (IDE_TYPE_DEBUGGER_CONTROLS,
@@ -256,69 +222,10 @@ ide_debugger_workbench_addin_unload (IdeWorkbenchAddin *addin,
}
static void
-ide_debugger_workbench_addin_open_async (IdeWorkbenchAddin *addin,
- IdeUri *uri,
- const gchar *content_type,
- IdeWorkbenchOpenFlags flags,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- IdeDebuggerWorkbenchAddin *self = (IdeDebuggerWorkbenchAddin *)addin;
- g_autoptr(GtkSourceFileLoader) loader = NULL;
- g_autoptr(GtkSourceBuffer) buffer = NULL;
- g_autoptr(GtkSourceFile) sfile = NULL;
- g_autoptr(GTask) task = NULL;
- g_autoptr(GFile) file = NULL;
- GtkSourceView *view;
-
- g_assert (IDE_IS_DEBUGGER_WORKBENCH_ADDIN (self));
- g_assert (uri != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, ide_debugger_workbench_addin_open_async);
-
- file = ide_uri_to_file (uri);
-
- buffer = gtk_source_buffer_new (NULL);
- view = g_object_new (GTK_SOURCE_TYPE_VIEW,
- "buffer", buffer,
- "visible", TRUE,
- NULL);
-
- sfile = gtk_source_file_new ();
- gtk_source_file_set_location (sfile, file);
-
- loader = gtk_source_file_loader_new (buffer, sfile);
- gtk_source_file_loader_load_async (loader,
- G_PRIORITY_LOW,
- cancellable,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL);
-}
-
-static gboolean
-ide_debugger_workbench_addin_open_finish (IdeWorkbenchAddin *addin,
- GAsyncResult *result,
- GError **error)
-{
- g_assert (IDE_IS_DEBUGGER_WORKBENCH_ADDIN (addin));
- g_assert (G_IS_TASK (result));
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
{
iface->load = ide_debugger_workbench_addin_load;
iface->unload = ide_debugger_workbench_addin_unload;
- iface->open_async = ide_debugger_workbench_addin_open_async;
- iface->open_finish = ide_debugger_workbench_addin_open_finish;
}
G_DEFINE_TYPE_WITH_CODE (IdeDebuggerWorkbenchAddin, ide_debugger_workbench_addin, G_TYPE_OBJECT,
diff --git a/libide/debugger/ide-debugger.c b/libide/debugger/ide-debugger.c
index 27f0077..bbab4de 100644
--- a/libide/debugger/ide-debugger.c
+++ b/libide/debugger/ide-debugger.c
@@ -18,11 +18,15 @@
#define G_LOG_DOMAIN "ide-debugger"
+#include <glib/gi18n.h>
+
#include "ide-enums.h"
#include "ide-debug.h"
+#include "buffers/ide-buffer.h"
+#include "files/ide-file.h"
+#include "debugger/ide-breakpoint.h"
#include "debugger/ide-debugger.h"
-#include "diagnostics/ide-source-location.h"
#include "runner/ide-runner.h"
G_DEFINE_INTERFACE (IdeDebugger, ide_debugger, IDE_TYPE_OBJECT)
@@ -50,10 +54,151 @@ ide_debugger_real_supports_runner (IdeDebugger *self,
}
static void
+ide_debugger_real_load_source_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GtkSourceFileLoader *loader = (GtkSourceFileLoader *)object;
+ g_autoptr(GTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ GtkSourceBuffer *buffer;
+ IdeBreakpoint *breakpoint;
+ GtkTextIter iter;
+ guint line;
+ guint line_offset;
+
+ IDE_ENTRY;
+
+ g_assert (GTK_SOURCE_IS_FILE_LOADER (loader));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (G_IS_TASK (task));
+
+ if (!gtk_source_file_loader_load_finish (loader, result, &error))
+ {
+ IDE_TRACE_MSG ("Failed to load buffer: %s", error->message);
+ g_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
+ }
+
+ buffer = gtk_source_file_loader_get_buffer (loader);
+ g_assert (IDE_IS_BUFFER (buffer));
+
+ breakpoint = g_task_get_task_data (task);
+ g_assert (IDE_IS_BREAKPOINT (breakpoint));
+
+ line = ide_breakpoint_get_line (breakpoint);
+ line_offset = ide_breakpoint_get_line_offset (breakpoint);
+
+ gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (buffer),
+ &iter,
+ line,
+ line_offset);
+
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &iter, &iter);
+
+ g_task_return_pointer (task, g_object_ref (buffer), g_object_unref);
+
+ IDE_EXIT;
+}
+
+static void
+ide_debugger_real_load_source_async (IdeDebugger *self,
+ IdeBreakpoint *breakpoint,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GtkSourceFileLoader) loader = NULL;
+ g_autoptr(GtkSourceFile) source_file = NULL;
+ g_autoptr(IdeBuffer) buffer = NULL;
+ g_autoptr(IdeFile) ifile = NULL;
+ IdeContext *context;
+ GFile *file;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEBUGGER (self));
+ g_assert (IDE_IS_BREAKPOINT (breakpoint));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_task_data (task, g_object_ref (breakpoint), g_object_unref);
+ g_task_set_source_tag (task, ide_debugger_real_load_source_async);
+
+ file = ide_breakpoint_get_file (breakpoint);
+
+ if (file == NULL)
+ {
+ const gchar *address = ide_breakpoint_get_address (breakpoint);
+
+ if (address != NULL)
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ /* translators: %s will be replaced with the address */
+ _("Cannot locate source for address ā%sā"),
+ address);
+ else
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Failed to locate source for breakpoint"));
+
+ IDE_EXIT;
+ }
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+
+ source_file = gtk_source_file_new ();
+ gtk_source_file_set_location (source_file, file);
+
+ ifile = g_object_new (IDE_TYPE_FILE,
+ "context", context,
+ "file", file,
+ NULL);
+
+ buffer = g_object_new (IDE_TYPE_BUFFER,
+ "file", ifile,
+ "context", context,
+ NULL);
+
+ loader = gtk_source_file_loader_new (GTK_SOURCE_BUFFER (buffer), source_file);
+
+ gtk_source_file_loader_load_async (loader,
+ G_PRIORITY_LOW,
+ NULL, NULL, NULL, NULL,
+ ide_debugger_real_load_source_cb,
+ g_steal_pointer (&task));
+
+ IDE_EXIT;
+}
+
+static IdeBuffer *
+ide_debugger_real_load_source_finish (IdeDebugger *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ IdeBuffer *ret;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEBUGGER (self));
+ g_assert (G_IS_TASK (result));
+
+ ret = g_task_propagate_pointer (G_TASK (result), error);
+ g_assert (!ret || IDE_IS_BUFFER (ret));
+
+ IDE_RETURN (ret);
+}
+
+static void
ide_debugger_default_init (IdeDebuggerInterface *iface)
{
iface->get_name = ide_debugger_real_get_name;
iface->supports_runner = ide_debugger_real_supports_runner;
+ iface->load_source_async = ide_debugger_real_load_source_async;
+ iface->load_source_finish = ide_debugger_real_load_source_finish;
g_object_interface_install_property (iface,
g_param_spec_boolean ("can-step-in",
@@ -96,11 +241,11 @@ ide_debugger_default_init (IdeDebuggerInterface *iface)
* IdeDebugger::stopped:
* @self: An #IdeDebugger
* @reason: An #IdeDebuggerStopReason for why the stop occurred
- * @location: An #IdeSourceLocation of where the debugger has stopped
+ * @breakpoint: An #IdeBreakpoint
*
* The "stopped" signal should be emitted when the debugger has stopped at a
- * new location. @reason indicates the reson for the stop, and @location is
- * the location where the stop has occurred.
+ * new location. @reason indicates the reson for the stop, and @breakpoint
+ * describes the current location within the appliation.
*/
signals [STOPPED] =
g_signal_new ("stopped",
@@ -108,8 +253,7 @@ ide_debugger_default_init (IdeDebuggerInterface *iface)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (IdeDebuggerInterface, stopped),
NULL, NULL, NULL,
- G_TYPE_NONE,
- 2, IDE_TYPE_DEBUGGER_STOP_REASON, IDE_TYPE_SOURCE_LOCATION);
+ G_TYPE_NONE, 2, IDE_TYPE_DEBUGGER_STOP_REASON, IDE_TYPE_BREAKPOINT);
}
/**
@@ -169,14 +313,47 @@ ide_debugger_get_name (IdeDebugger *self)
return ret;
}
+/**
+ * ide_debugger_emit_stopped:
+ * @self: A #IdeDebugger
+ * @reason: the reason for the stop
+ * @breakpoint: (nullable): an optional breakpoint that is reached
+ *
+ * This signal should be emitted when the debugger has stopped executing.
+ *
+ * If the stop is not related to the application exiting for any reason, then
+ * you should provide a @breakpoint describing the stop location. That
+ * breakpoint may be transient (see #IdeDebugger:transient) meaning that it is
+ * only created for this stop event.
+ */
void
ide_debugger_emit_stopped (IdeDebugger *self,
IdeDebuggerStopReason reason,
- IdeSourceLocation *location)
+ IdeBreakpoint *breakpoint)
{
g_return_if_fail (IDE_IS_DEBUGGER (self));
+ g_return_if_fail (!breakpoint || IDE_IS_BREAKPOINT (breakpoint));
+
+#ifdef IDE_ENABLE_TRACE
+ if (breakpoint != NULL)
+ {
+ g_autofree gchar *uri = NULL;
+ const gchar *address;
+ GFile *file;
+
+ address = ide_breakpoint_get_address (breakpoint);
+ file = ide_breakpoint_get_file (breakpoint);
+
+ if (file != NULL)
+ uri = g_file_get_uri (file);
+
+ IDE_TRACE_MSG ("Stopped at breakpoint \"%s\" with address \"%s\"",
+ uri ? uri : "<none>",
+ address ? address : "<none>");
+ }
+#endif
- g_signal_emit (self, signals [STOPPED], 0, reason, location);
+ g_signal_emit (self, signals [STOPPED], 0, reason, breakpoint);
}
void
@@ -209,3 +386,50 @@ ide_debugger_emit_log (IdeDebugger *self,
if (message != NULL)
g_signal_emit (self, signals [LOG], 0, message);
}
+
+void
+ide_debugger_load_source_async (IdeDebugger *self,
+ IdeBreakpoint *breakpoint,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_DEBUGGER (self));
+ g_return_if_fail (IDE_IS_BREAKPOINT (breakpoint));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ IDE_DEBUGGER_GET_IFACE (self)->load_source_async (self, breakpoint, cancellable, callback, user_data);
+
+ IDE_EXIT;
+}
+
+/**
+ * ide_debugger_load_source_finish:
+ * @self: a #IdeDebugger
+ * @result: a #GAsyncResult
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to ide_debugger_load_source_async().
+ *
+ * Returns: (nullable) (transfer full): An #IdeBuffer or %NULL
+ */
+IdeBuffer *
+ide_debugger_load_source_finish (IdeDebugger *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ IdeBuffer *ret;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+ ret = IDE_DEBUGGER_GET_IFACE (self)->load_source_finish (self, result, error);
+
+ g_return_val_if_fail (!ret || IDE_IS_BUFFER (ret), NULL);
+
+ IDE_RETURN (ret);
+}
diff --git a/libide/debugger/ide-debugger.h b/libide/debugger/ide-debugger.h
index 843920a..7b5e557 100644
--- a/libide/debugger/ide-debugger.h
+++ b/libide/debugger/ide-debugger.h
@@ -19,6 +19,8 @@
#ifndef IDE_DEBUGGER_H
#define IDE_DEBUGGER_H
+#include <gtksourceview/gtksource.h>
+
#include "ide-object.h"
G_BEGIN_DECLS
@@ -48,34 +50,50 @@ struct _IdeDebuggerInterface
{
GTypeInterface parent_iface;
- gchar *(*get_name) (IdeDebugger *self);
- gboolean (*supports_runner) (IdeDebugger *self,
- IdeRunner *runner,
- gint *priority);
- void (*stopped) (IdeDebugger *self,
- IdeDebuggerStopReason reason,
- IdeSourceLocation *location);
- void (*prepare) (IdeDebugger *debugger,
- IdeRunner *runner);
- void (*run) (IdeDebugger *self,
- IdeDebuggerRunType run_type);
- void (*log) (IdeDebugger *self,
- const gchar *message);
+ gchar *(*get_name) (IdeDebugger *self);
+ gboolean (*supports_runner) (IdeDebugger *self,
+ IdeRunner *runner,
+ gint *priority);
+ void (*stopped) (IdeDebugger *self,
+ IdeDebuggerStopReason reason,
+ IdeBreakpoint *breakpoint);
+ void (*prepare) (IdeDebugger *debugger,
+ IdeRunner *runner);
+ void (*run) (IdeDebugger *self,
+ IdeDebuggerRunType run_type);
+ void (*log) (IdeDebugger *self,
+ const gchar *message);
+ void (*load_source_async) (IdeDebugger *self,
+ IdeBreakpoint *breakpoint,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ IdeBuffer *(*load_source_finish) (IdeDebugger *self,
+ GAsyncResult *result,
+ GError **error);
};
-gchar *ide_debugger_get_name (IdeDebugger *self);
-gboolean ide_debugger_supports_runner (IdeDebugger *self,
- IdeRunner *runner,
- gint *priority);
-void ide_debugger_prepare (IdeDebugger *self,
- IdeRunner *runner);
-void ide_debugger_run (IdeDebugger *self,
- IdeDebuggerRunType run_type);
-void ide_debugger_emit_log (IdeDebugger *self,
- const gchar *message);
-void ide_debugger_emit_stopped (IdeDebugger *self,
- IdeDebuggerStopReason reason,
- IdeSourceLocation *location);
+gchar *ide_debugger_get_name (IdeDebugger *self);
+gboolean ide_debugger_supports_runner (IdeDebugger *self,
+ IdeRunner *runner,
+ gint *priority);
+void ide_debugger_prepare (IdeDebugger *self,
+ IdeRunner *runner);
+void ide_debugger_run (IdeDebugger *self,
+ IdeDebuggerRunType run_type);
+void ide_debugger_emit_log (IdeDebugger *self,
+ const gchar *message);
+void ide_debugger_emit_stopped (IdeDebugger *self,
+ IdeDebuggerStopReason reason,
+ IdeBreakpoint *breakpoint);
+void ide_debugger_load_source_async (IdeDebugger *self,
+ IdeBreakpoint *breakpoint,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IdeBuffer *ide_debugger_load_source_finish (IdeDebugger *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/libide/ide-types.h b/libide/ide-types.h
index 206d78d..abe79a1 100644
--- a/libide/ide-types.h
+++ b/libide/ide-types.h
@@ -51,6 +51,7 @@ typedef struct _IdeConfigurationManager IdeConfigurationManager;
typedef struct _IdeContext IdeContext;
typedef struct _IdeDebugger IdeDebugger;
+typedef struct _IdeDebuggerBreakpoints IdeDebuggerBreakpoints;
typedef struct _IdeBreakpoint IdeBreakpoint;
typedef struct _IdeDebugManager IdeDebugManager;
diff --git a/libide/ide.h b/libide/ide.h
index 7067844..27c8031 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -53,6 +53,7 @@ G_BEGIN_DECLS
#include "buildsystem/ide-configuration-provider.h"
#include "buildsystem/ide-environment-variable.h"
#include "buildsystem/ide-environment.h"
+#include "debugger/ide-breakpoint.h"
#include "debugger/ide-debug-manager.h"
#include "debugger/ide-debugger.h"
#include "devices/ide-device-manager.h"
diff --git a/libide/resources/libide.gresource.xml b/libide/resources/libide.gresource.xml
index 8d4d916..10668ba 100644
--- a/libide/resources/libide.gresource.xml
+++ b/libide/resources/libide.gresource.xml
@@ -53,6 +53,7 @@
<gresource prefix="/org/gnome/builder/ui">
<file compressed="true" alias="ide-debugger-controls.ui">../debugger/ide-debugger-controls.ui</file>
<file compressed="true"
alias="ide-debugger-perspective.ui">../debugger/ide-debugger-perspective.ui</file>
+ <file compressed="true" alias="ide-debugger-view.ui">../debugger/ide-debugger-view.ui</file>
<file compressed="true" alias="ide-editor-frame.ui">../editor/ide-editor-frame.ui</file>
<file compressed="true"
alias="ide-editor-layout-stack-controls.ui">../editor/ide-editor-layout-stack-controls.ui</file>
<file compressed="true" alias="ide-editor-perspective.ui">../editor/ide-editor-perspective.ui</file>
diff --git a/plugins/gdb/gbp-gdb-debugger.c b/plugins/gdb/gbp-gdb-debugger.c
index f183674..d4e592c 100644
--- a/plugins/gdb/gbp-gdb-debugger.c
+++ b/plugins/gdb/gbp-gdb-debugger.c
@@ -327,8 +327,8 @@ gbp_gdb_debugger_on_client_stopped (GbpGdbDebugger *self,
Mi2EventMessage *message,
Mi2Client *client)
{
+ g_autoptr(IdeBreakpoint) breakpoint = NULL;
IdeDebuggerStopReason translated;
- g_autoptr(IdeSourceLocation) location = NULL;
GVariant *fra;
IDE_ENTRY;
@@ -359,32 +359,37 @@ gbp_gdb_debugger_on_client_stopped (GbpGdbDebugger *self,
break;
}
- if (NULL != (fra = mi2_message_get_param (MI2_MESSAGE (message), "frame")) &&
- g_variant_is_of_type (fra, G_VARIANT_TYPE ("a{sv}")))
+ fra = mi2_message_get_param (MI2_MESSAGE (message), "frame");
+
+ if (fra != NULL && g_variant_is_of_type (fra, G_VARIANT_TYPE ("a{sv}")))
{
- GVariantDict dict;
+ const gchar *address = NULL;
const gchar *filename = NULL;
- const gchar *line = NULL;
+ const gchar *linestr = NULL;
+ GVariantDict dict;
g_variant_dict_init (&dict, fra);
g_variant_dict_lookup (&dict, "fullname", "&s", &filename);
- g_variant_dict_lookup (&dict, "line", "&s", &line);
+ g_variant_dict_lookup (&dict, "line", "&s", &linestr);
+ g_variant_dict_lookup (&dict, "addr", "&s", &address);
- if (filename != NULL && line != NULL)
+ if (filename != NULL && linestr != NULL)
{
- IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
- g_autoptr(GFile) gfile = g_file_new_for_path (filename);
- g_autoptr(IdeFile) ifile = ide_file_new (context, gfile);
-
- location = ide_source_location_new (ifile,
- g_ascii_strtoll (line, NULL, 10),
- 0, 0);
+ g_autoptr(GFile) file = g_file_new_for_path (filename);
+ guint line = g_ascii_strtoll (linestr, NULL, 10);
+
+ breakpoint = g_object_new (IDE_TYPE_BREAKPOINT,
+ "address", address,
+ "file", file,
+ "line", line,
+ "line-offset", 0,
+ NULL);
}
}
gbp_gdb_debugger_notify_properties (self);
- ide_debugger_emit_stopped (IDE_DEBUGGER (self), translated, NULL);
+ ide_debugger_emit_stopped (IDE_DEBUGGER (self), translated, breakpoint);
IDE_EXIT;
}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b911211..1910c16 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -54,6 +54,7 @@ libide/buildui/ide-build-panel.ui
libide/buildui/ide-build-perspective.c
libide/buildui/ide-build-tool.c
libide/buildui/ide-environment-editor.c
+libide/debugger/ide-debugger.c
libide/devices/ide-device-manager.c
libide/directory/ide-directory-vcs.c
libide/editorconfig/ide-editorconfig-file-settings.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]