[gnome-builder/wip/chergert/debugger: 4/5] debugger: stub out debugger API



commit b781886b6aee1f0d86b4ab68b22ff8ff754a7fd1
Author: Christian Hergert <chergert redhat com>
Date:   Thu Sep 1 17:51:58 2016 -0700

    debugger: stub out debugger API

 configure.ac                                      |    2 +
 plugins/Makefile.am                               |    1 +
 plugins/debugger/Makefile.am                      |   46 ++++
 plugins/debugger/OVERVIEW.md                      |   63 +++++
 plugins/debugger/configure.ac                     |   12 +
 plugins/debugger/debugger.gresource.xml           |    7 +
 plugins/debugger/debugger.plugin                  |    9 +
 plugins/debugger/gbp-debugger-breakpoints.c       |  293 ++++++++++++++++++++
 plugins/debugger/gbp-debugger-breakpoints.h       |   49 ++++
 plugins/debugger/gbp-debugger-editor-view-addin.c |  161 +++++++++++
 plugins/debugger/gbp-debugger-editor-view-addin.h |   32 +++
 plugins/debugger/gbp-debugger-gutter-renderer.c   |  281 ++++++++++++++++++++
 plugins/debugger/gbp-debugger-gutter-renderer.h   |   35 +++
 plugins/debugger/gbp-debugger-perspective.c       |  126 +++++++++
 plugins/debugger/gbp-debugger-perspective.h       |   32 +++
 plugins/debugger/gbp-debugger-perspective.ui      |    5 +
 plugins/debugger/gbp-debugger-plugin.c            |   36 +++
 plugins/debugger/gbp-debugger-service.c           |  153 +++++++++++
 plugins/debugger/gbp-debugger-service.h           |   37 +++
 plugins/debugger/gbp-debugger-workbench-addin.c   |  295 +++++++++++++++++++++
 plugins/debugger/gbp-debugger-workbench-addin.h   |   32 +++
 plugins/debugger/gtk/menus.ui                     |    3 +
 po/POTFILES.in                                    |    4 +
 23 files changed, 1714 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d862d57..c539a5a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -287,6 +287,7 @@ m4_include([plugins/comment-code/configure.ac])
 m4_include([plugins/contributing/configure.ac])
 m4_include([plugins/create-project/configure.ac])
 m4_include([plugins/ctags/configure.ac])
+m4_include([plugins/debugger/configure.ac])
 m4_include([plugins/devhelp/configure.ac])
 m4_include([plugins/file-search/configure.ac])
 m4_include([plugins/flatpak/configure.ac])
@@ -576,6 +577,7 @@ echo "  Command Bar .......................... : ${enable_command_bar_plugin}"
 echo "  Comment Code.......................... : ${enable_comment_code_plugin}"
 echo "  Contribute ........................... : ${enable_contributing_plugin}"
 echo "  Ctags ................................ : ${enable_ctags_plugin}"
+echo "  Debugger ............................. : ${enable_debugger_plugin}"
 echo "  Devhelp .............................. : ${enable_devhelp_plugin}"
 echo "  Editorconfig ......................... : ${enable_editorconfig}"
 echo "  Fpaste.org ........................... : ${enable_fpaste_plugin}"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 21ed04b..2a80e6b 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -10,6 +10,7 @@ SUBDIRS = \
        contributing \
        create-project \
        ctags \
+       debugger \
        devhelp \
        file-search \
        flatpak \
diff --git a/plugins/debugger/Makefile.am b/plugins/debugger/Makefile.am
new file mode 100644
index 0000000..9ccf523
--- /dev/null
+++ b/plugins/debugger/Makefile.am
@@ -0,0 +1,46 @@
+if ENABLE_SYSPROF_PLUGIN
+
+DISTCLEANFILES =
+BUILT_SOURCES =
+CLEANFILES =
+EXTRA_DIST = $(plugin_DATA)
+
+plugindir = $(libdir)/gnome-builder/plugins
+plugin_LTLIBRARIES = libdebugger-plugin.la
+dist_plugin_DATA = debugger.plugin
+
+libdebugger_plugin_la_SOURCES = \
+       gbp-debugger-breakpoints.c \
+       gbp-debugger-breakpoints.h \
+       gbp-debugger-editor-view-addin.c \
+       gbp-debugger-editor-view-addin.h \
+       gbp-debugger-gutter-renderer.c \
+       gbp-debugger-gutter-renderer.h \
+       gbp-debugger-perspective.c \
+       gbp-debugger-perspective.h \
+       gbp-debugger-plugin.c \
+       gbp-debugger-service.c \
+       gbp-debugger-service.h \
+       gbp-debugger-workbench-addin.c \
+       gbp-debugger-workbench-addin.h \
+       $(NULL)
+
+nodist_libdebugger_plugin_la_SOURCES = \
+       gbp-debugger-resources.c \
+       gbp-debugger-resources.h
+
+libdebugger_plugin_la_CFLAGS = $(PLUGIN_CFLAGS) $(SYSPROF_CFLAGS)
+libdebugger_plugin_la_LIBADD = $(PLUGIN_LIBS) $(SYSPROF_LIBS)
+libdebugger_plugin_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(SYSPROF_LDFLAGS)
+
+glib_resources_c = gbp-debugger-resources.c
+glib_resources_h = gbp-debugger-resources.h
+glib_resources_xml = debugger.gresource.xml
+glib_resources_namespace = gbp_debugger
+include $(top_srcdir)/build/autotools/Makefile.am.gresources
+
+include $(top_srcdir)/plugins/Makefile.plugin
+
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/debugger/OVERVIEW.md b/plugins/debugger/OVERVIEW.md
new file mode 100644
index 0000000..9b36250
--- /dev/null
+++ b/plugins/debugger/OVERVIEW.md
@@ -0,0 +1,63 @@
+# Debugger Overview
+
+The goal of this plugin is to reuse as much of the Nemiver codebase as we can
+to implement a debugger in Builder. Rather than abstract debugger
+implementations in Builder, we will rely on Nemiver's debugger abstraction.
+That means to add a new debugger to Builder, you need to add a new debugger
+module to Nemiver. This is completely a reasonable request as it allows for
+Nemiver to be more generally useful as a standalone debugger for those that
+prefer standalone tools.
+
+## Debugger Service
+
+This `IService` implementation bridges the Nemiver IDebugger implementation
+with Builder. It provides the API calls necessary to make progress on the
+debugger as well register breakpoints, watchpoints, countpoints, etc. These API
+calls are used by the `EditorViewAddin` (and associated GutterRenderer) to
+toggle breakpoints on a given line. Additionally, the service provides
+information on the current position of the debug cycle, so that we can show an
+arrow for the current position in the gutter.
+
+To simplify interaction with UI elements, the Debugger service also exposes
+a `GActionGroup` with actions that can be activated from Gtk widgetry. The
+enabled-state of the actions are automatically updated based on the bridged
+`IDebugger`s ability to perform the action.
+
+## Debugger Perspective
+
+The debugger perspective imports the widgetry from Nemiver into a layout
+suitable for debugging in Builder. It includes a location for read-only
+editors (of the file for the current debugged line) as well as the panels
+such as memory, threads, breakpoints, etc.
+
+## Debugger EditorViewAddin
+
+This addin hooks into the `IdeEditorView` to add the debugger gutter to sources
+that can have breakpoints added to them. Such an example would be C and C++
+files. As additional debugger backends are added, this will need to be
+extended to enable other language ids.
+
+## Debugger GutterRenderer
+
+This is a `GtkSourceGutterRenderer` that allows toggling breakpoints (as well
+as countpoints) for a given line in a source file.
+
+## Debugger WorkbenchAddin
+
+The `IdeWorkbenchAddin` is used to add the perspective to the workbench. Also,
+it adds the Debugger service to the toplevel as an action group so that buttons
+can be attached to the actions. The debugger controls are added to the UI here
+as well, and this class manages their visibility (based on the debugger service
+actively debugging).
+
+This also registers the `IdeRunHandler` for the debugger. When activated, it
+requests the debugger service to start the debugger using the `IdeRunner` for
+the run operation.
+
+## Debugger Breakpoints
+
+Because GtkSourceGutterRenderers do not have their contents cached, we need a
+*very* fast way to determine if a breakpoint is on a given source line. The
+`GbpDebuggerBreakpoints` provides that feature by caching what lines have
+breakpoints. This allows the gutter renderer to quickly check for every line
+rendered as well as invalidating the window when breakpoints change.
diff --git a/plugins/debugger/configure.ac b/plugins/debugger/configure.ac
new file mode 100644
index 0000000..fcc26cb
--- /dev/null
+++ b/plugins/debugger/configure.ac
@@ -0,0 +1,12 @@
+# --enable-debugger-plugin=yes/no
+AC_ARG_ENABLE([debugger-plugin],
+              [AS_HELP_STRING([--enable-debugger-plugin=@<:@yes/no@:>@],
+                              [Build with support for the integrated debugger.])],
+              [enable_debugger_plugin=$enableval],
+              [enable_debugger_plugin=yes])
+
+# for if ENABLE_DEBUGGER_PLUGIN in Makefile.am
+AM_CONDITIONAL(ENABLE_DEBUGGER_PLUGIN, [test x$enable_debugger_plugin = xyes])
+
+# Ensure our makefile is generated by autoconf
+AC_CONFIG_FILES([plugins/debugger/Makefile])
diff --git a/plugins/debugger/debugger.gresource.xml b/plugins/debugger/debugger.gresource.xml
new file mode 100644
index 0000000..9787f0c
--- /dev/null
+++ b/plugins/debugger/debugger.gresource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/builder/plugins/debugger-plugin">
+    <file>gtk/menus.ui</file>
+    <file>gbp-debugger-perspective.ui</file>
+  </gresource>
+</gresources>
diff --git a/plugins/debugger/debugger.plugin b/plugins/debugger/debugger.plugin
new file mode 100644
index 0000000..2b7bac4
--- /dev/null
+++ b/plugins/debugger/debugger.plugin
@@ -0,0 +1,9 @@
+[Plugin]
+Module=debugger-plugin
+Name=Debugger
+Description=Integrates the Nemiver debugger
+Authors=Christian Hergert <christian hergert me>
+Copyright=Copyright © 2016 Christian Hergert
+Depends=editor
+Builtin=true
+Hidden=true
diff --git a/plugins/debugger/gbp-debugger-breakpoints.c b/plugins/debugger/gbp-debugger-breakpoints.c
new file mode 100644
index 0000000..75bf47f
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-breakpoints.c
@@ -0,0 +1,293 @@
+/* gbp-debugger-breakpoints.c
+ *
+ * Copyright (C) 2016 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 "gbp-debugger-breakpoints"
+
+#include "gbp-debugger-breakpoints.h"
+#include "gbp-debugger-service.h"
+
+/**
+ * SECTION:gbp-debugger-breakpoints
+ * @title: GbpDebuggerBreakpoints
+ *
+ * This object is used to track breakpoints within a certain file.
+ * This is necessary so that we can draw the gutter for breakpoints
+ * very fast by reducing our breakpoint lookup cost to simply a line
+ * number in a hashtable.
+ *
+ * To do this, the #GbpDebuggerBreakpoints object will track changes
+ * to breakpoints (and watchpoints) in the GbpDebuggerService. If the
+ * breakpoint is part to the current #GbpDebuggerBreakpoints:file, then
+ * it will cache the value. The #GbpDebuggerGutterRenderer is assigned
+ * a #GbpDebuggerBreakpoints which it will use to determine what icon
+ * to render on the gutter.
+ */
+
+struct _GbpDebuggerBreakpoints
+{
+  IdeObject   parent_instance;
+  GHashTable *cache;
+  GFile      *file;
+};
+
+enum {
+  PROP_0,
+  PROP_FILE,
+  N_PROPS
+};
+
+enum {
+  CHANGED,
+  N_SIGNALS
+};
+
+G_DEFINE_TYPE (GbpDebuggerBreakpoints, gbp_debugger_breakpoints, IDE_TYPE_OBJECT)
+
+static GParamSpec *properties [N_PROPS];
+static guint signals [N_SIGNALS];
+
+static void
+on_breakpoint_added (GbpDebuggerBreakpoints *self,
+                     GFile                  *file,
+                     guint                   line,
+                     GbpDebuggerBreakType    break_type,
+                     GbpDebuggerService     *service)
+{
+  GbpDebuggerBreakType type;
+  gpointer key = GUINT_TO_POINTER (line);
+
+  g_assert (GBP_IS_DEBUGGER_BREAKPOINTS (self));
+  g_assert (G_IS_FILE (file));
+
+  if (!g_file_equal (file, self->file))
+    return;
+
+  type = GPOINTER_TO_UINT (g_hash_table_lookup (self->cache, key)) | break_type;
+  g_hash_table_insert (self->cache, key, GUINT_TO_POINTER (type));
+
+  g_signal_emit (self, signals [CHANGED], 0);
+}
+
+static void
+on_breakpoint_removed (GbpDebuggerBreakpoints *self,
+                       GFile                  *file,
+                       guint                   line,
+                       GbpDebuggerBreakType    break_type,
+                       GbpDebuggerService     *service)
+{
+  GbpDebuggerBreakType type;
+  gpointer key = GUINT_TO_POINTER (line);
+
+  g_assert (GBP_IS_DEBUGGER_BREAKPOINTS (self));
+  g_assert (G_IS_FILE (file));
+
+  if (!g_file_equal (file, self->file))
+    return;
+
+  type = GPOINTER_TO_UINT (g_hash_table_lookup (self->cache, key));
+  type = type & ~break_type;
+
+  if (type == 0)
+    g_hash_table_remove (self->cache, key);
+  else
+    g_hash_table_replace (self->cache, key, GUINT_TO_POINTER (type));
+
+  g_signal_emit (self, signals [CHANGED], 0);
+}
+
+static void
+gbp_debugger_breakpoints_constructed (GObject *object)
+{
+  GbpDebuggerBreakpoints *self = (GbpDebuggerBreakpoints *)object;
+  GbpDebuggerService *service;
+  IdeContext *context;
+
+  g_assert (GBP_IS_DEBUGGER_BREAKPOINTS (self));
+
+  G_OBJECT_CLASS (gbp_debugger_breakpoints_parent_class)->constructed (object);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  service = ide_context_get_service_typed (context, GBP_TYPE_DEBUGGER_SERVICE);
+
+  g_signal_connect_object (service,
+                           "breakpoint-added",
+                           G_CALLBACK (on_breakpoint_added),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (service,
+                           "breakpoint-removed",
+                           G_CALLBACK (on_breakpoint_removed),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+gbp_debugger_breakpoints_finalize (GObject *object)
+{
+  GbpDebuggerBreakpoints *self = (GbpDebuggerBreakpoints *)object;
+
+  g_clear_object (&self->file);
+  g_clear_pointer (&self->cache, g_hash_table_unref);
+
+  G_OBJECT_CLASS (gbp_debugger_breakpoints_parent_class)->finalize (object);
+}
+
+static void
+gbp_debugger_breakpoints_get_property (GObject    *object,
+                                       guint       prop_id,
+                                       GValue     *value,
+                                       GParamSpec *pspec)
+{
+  GbpDebuggerBreakpoints *self = GBP_DEBUGGER_BREAKPOINTS (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      g_value_set_object (value, self->file);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_breakpoints_set_property (GObject      *object,
+                                       guint         prop_id,
+                                       const GValue *value,
+                                       GParamSpec   *pspec)
+{
+  GbpDebuggerBreakpoints *self = GBP_DEBUGGER_BREAKPOINTS (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      self->file = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_breakpoints_class_init (GbpDebuggerBreakpointsClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed = gbp_debugger_breakpoints_constructed;
+  object_class->finalize = gbp_debugger_breakpoints_finalize;
+  object_class->get_property = gbp_debugger_breakpoints_get_property;
+  object_class->set_property = gbp_debugger_breakpoints_set_property;
+
+  properties [PROP_FILE] =
+    g_param_spec_object ("file",
+                         "File",
+                         "File",
+                         G_TYPE_FILE,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  /**
+   * GbpDebuggerBreakpoints::changed:
+   *
+   * This signal is emitted when a breakpoint has changed with in the file
+   * indicated by GbpDebuggerBreakpoints:file.
+   */
+  signals [CHANGED] =
+    g_signal_new ("changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+}
+
+static void
+gbp_debugger_breakpoints_init (GbpDebuggerBreakpoints *self)
+{
+  self->cache = g_hash_table_new (NULL, NULL);
+}
+
+/**
+ * gbp_debugger_breakpoints_get_file:
+ *
+ * Returns: (transfer none): A #GFile.
+ */
+GFile *
+gbp_debugger_breakpoints_get_file (GbpDebuggerBreakpoints *self)
+{
+  g_return_val_if_fail (GBP_IS_DEBUGGER_BREAKPOINTS (self), NULL);
+
+  return self->file;
+}
+
+void
+gbp_debugger_breakpoints_add (GbpDebuggerBreakpoints *self,
+                              guint                   line,
+                              GbpDebuggerBreakType    break_type)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_DEBUGGER_BREAKPOINTS (self));
+  g_assert (line > 0);
+  g_assert (break_type > GBP_DEBUGGER_BREAK_NONE);
+
+  /*
+   * TODO: Propagate request for breakpoint via debugger service.
+   *       Instead, for testing, we will just add the breakpoint
+   *       locally to our cache. However, a real implementation
+   *       should possibly set a pending bit on the entry and the
+   *       remove the pending bit once it has been added by the
+   *       debugger (since that could involve a round trip over
+   *       IPC and we don't want to show a full breakpoint before
+   *       its actually available).
+   */
+
+  g_hash_table_insert (self->cache, GUINT_TO_POINTER (line), GUINT_TO_POINTER (break_type));
+  g_signal_emit (self, signals [CHANGED], 0);
+
+  IDE_EXIT;
+}
+
+void
+gbp_debugger_breakpoints_remove (GbpDebuggerBreakpoints *self,
+                                 guint                   line)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_DEBUGGER_BREAKPOINTS (self));
+  g_assert (line > 0);
+
+  /*
+   * TODO: Propagate request to remove breakpoint via debugger service.
+   *       For testing, we can just remove the debugger from cache.
+   */
+
+  g_hash_table_remove (self->cache, GUINT_TO_POINTER (line));
+  g_signal_emit (self, signals [CHANGED], 0);
+
+  IDE_EXIT;
+}
+
+GbpDebuggerBreakType
+gbp_debugger_breakpoints_lookup (GbpDebuggerBreakpoints *self,
+                                 guint                   line)
+{
+  return GPOINTER_TO_UINT (g_hash_table_lookup (self->cache, GUINT_TO_POINTER (line)));
+}
diff --git a/plugins/debugger/gbp-debugger-breakpoints.h b/plugins/debugger/gbp-debugger-breakpoints.h
new file mode 100644
index 0000000..c5a481a
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-breakpoints.h
@@ -0,0 +1,49 @@
+/* gbp-debugger-breakpoints.h
+ *
+ * Copyright (C) 2016 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 GBP_DEBUGGER_BREAKPOINTS_H
+#define GBP_DEBUGGER_BREAKPOINTS_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_DEBUGGER_BREAKPOINTS (gbp_debugger_breakpoints_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpDebuggerBreakpoints, gbp_debugger_breakpoints, GBP, DEBUGGER_BREAKPOINTS, IdeObject)
+
+typedef enum
+{
+  GBP_DEBUGGER_BREAK_NONE       = 0,
+  GBP_DEBUGGER_BREAK_BREAKPOINT = 1 << 0,
+  GBP_DEBUGGER_BREAK_COUNTPOINT = 1 << 1,
+  GBP_DEBUGGER_BREAK_WATCHPOINT = 1 << 2,
+} GbpDebuggerBreakType;
+
+GFile                *gbp_debugger_breakpoints_get_file (GbpDebuggerBreakpoints *self);
+void                  gbp_debugger_breakpoints_add      (GbpDebuggerBreakpoints *self,
+                                                         guint                   line,
+                                                         GbpDebuggerBreakType    break_type);
+void                  gbp_debugger_breakpoints_remove   (GbpDebuggerBreakpoints *self,
+                                                         guint                   line);
+GbpDebuggerBreakType  gbp_debugger_breakpoints_lookup   (GbpDebuggerBreakpoints *self,
+                                                         guint                   line);
+
+G_END_DECLS
+
+#endif /* GBP_DEBUGGER_BREAKPOINTS_H */
diff --git a/plugins/debugger/gbp-debugger-editor-view-addin.c 
b/plugins/debugger/gbp-debugger-editor-view-addin.c
new file mode 100644
index 0000000..0ccb836
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-editor-view-addin.c
@@ -0,0 +1,161 @@
+/* gbp-debugger-editor-view-addin.c
+ *
+ * Copyright (C) 2016 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 "gbp-debugger-editor-view-addin"
+
+#include "gbp-debugger-breakpoints.h"
+#include "gbp-debugger-editor-view-addin.h"
+#include "gbp-debugger-gutter-renderer.h"
+
+static GHashTable *supported_languages;
+
+struct _GbpDebuggerEditorViewAddin
+{
+  GObject    parent_instance;
+  GPtrArray *renderers;
+};
+
+static void
+gbp_debugger_editor_view_addin_load_source_view (IdeEditorViewAddin *addin,
+                                                 IdeSourceView      *source_view)
+{
+  GbpDebuggerEditorViewAddin *self = (GbpDebuggerEditorViewAddin *)addin;
+  g_autoptr(GbpDebuggerBreakpoints) breakpoints = NULL;
+  GtkSourceGutterRenderer *renderer;
+  GtkSourceGutter *gutter;
+  IdeContext *context;
+  IdeBuffer *buffer;
+  IdeFile *file;
+  GFile *gfile;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_DEBUGGER_EDITOR_VIEW_ADDIN (addin));
+  g_assert (IDE_IS_SOURCE_VIEW (source_view));
+
+  context = ide_widget_get_context (GTK_WIDGET (source_view));
+  buffer = IDE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view)));
+  file = ide_buffer_get_file (buffer);
+  gfile = ide_file_get_file (file);
+
+  breakpoints = g_object_new (GBP_TYPE_DEBUGGER_BREAKPOINTS,
+                              "context", context,
+                              "file", gfile,
+                              NULL);
+
+  gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (source_view), GTK_TEXT_WINDOW_LEFT);
+  renderer = g_object_new (GBP_TYPE_DEBUGGER_GUTTER_RENDERER,
+                           "alignment-mode", GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST,
+                           "breakpoints", breakpoints,
+                           "size", 16,
+                           "visible", TRUE,
+                           "xalign", 0.5f,
+                           NULL);
+  g_ptr_array_add (self->renderers, g_object_ref (renderer));
+  gtk_source_gutter_insert (gutter, renderer, -1000);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_debugger_editor_view_addin_unload_source_view (IdeEditorViewAddin *addin,
+                                                   IdeSourceView      *source_view)
+{
+  GbpDebuggerEditorViewAddin *self = (GbpDebuggerEditorViewAddin *)addin;
+  GtkSourceGutter *gutter;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_DEBUGGER_EDITOR_VIEW_ADDIN (addin));
+  g_assert (IDE_IS_SOURCE_VIEW (source_view));
+
+  gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (source_view), GTK_TEXT_WINDOW_LEFT);
+
+  for (guint i = self->renderers->len; i > 0; i--)
+    {
+      GtkSourceGutterRenderer *renderer = g_ptr_array_index (self->renderers, i - 1);
+
+      if ((gpointer)source_view == (gpointer)gtk_source_gutter_renderer_get_view (renderer))
+        {
+          gtk_source_gutter_remove (gutter, renderer);
+          g_ptr_array_remove_index (self->renderers, i - 1);
+        }
+    }
+
+  IDE_EXIT;
+}
+
+static void
+gbp_debugger_editor_view_addin_language_changed (IdeEditorViewAddin *addin,
+                                                 const gchar        *lang_id)
+{
+  GbpDebuggerEditorViewAddin *self = (GbpDebuggerEditorViewAddin *)addin;
+  gboolean visible = FALSE;
+
+  g_assert (GBP_IS_DEBUGGER_EDITOR_VIEW_ADDIN (self));
+
+  visible = lang_id && g_hash_table_contains (supported_languages, lang_id);
+
+  for (guint i = 0; i < self->renderers->len; i++)
+    {
+      GtkSourceGutterRenderer *renderer = g_ptr_array_index (self->renderers, i);
+
+      gtk_source_gutter_renderer_set_visible (renderer, visible);
+    }
+}
+
+static void
+editor_view_addin_iface_init (IdeEditorViewAddinInterface *iface)
+{
+  iface->load_source_view = gbp_debugger_editor_view_addin_load_source_view;
+  iface->unload_source_view = gbp_debugger_editor_view_addin_unload_source_view;
+  iface->language_changed = gbp_debugger_editor_view_addin_language_changed;
+}
+
+G_DEFINE_TYPE_EXTENDED (GbpDebuggerEditorViewAddin, gbp_debugger_editor_view_addin, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_EDITOR_VIEW_ADDIN, editor_view_addin_iface_init))
+
+static void
+gbp_debugger_editor_view_addin_finalize (GObject *object)
+{
+  GbpDebuggerEditorViewAddin *self = (GbpDebuggerEditorViewAddin *)object;
+
+  g_clear_pointer (&self->renderers, g_ptr_array_unref);
+
+  G_OBJECT_CLASS (gbp_debugger_editor_view_addin_parent_class)->finalize (object);
+}
+
+static void
+gbp_debugger_editor_view_addin_class_init (GbpDebuggerEditorViewAddinClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_debugger_editor_view_addin_finalize;
+
+  supported_languages = g_hash_table_new (g_str_hash, g_str_equal);
+  g_hash_table_insert (supported_languages, (gchar *)"c", NULL);
+  g_hash_table_insert (supported_languages, (gchar *)"chdr", NULL);
+  g_hash_table_insert (supported_languages, (gchar *)"cpp", NULL);
+  g_hash_table_insert (supported_languages, (gchar *)"cpphdr", NULL);
+}
+
+static void
+gbp_debugger_editor_view_addin_init (GbpDebuggerEditorViewAddin *self)
+{
+  self->renderers = g_ptr_array_new_with_free_func (g_object_unref);
+}
diff --git a/plugins/debugger/gbp-debugger-editor-view-addin.h 
b/plugins/debugger/gbp-debugger-editor-view-addin.h
new file mode 100644
index 0000000..8626f88
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-editor-view-addin.h
@@ -0,0 +1,32 @@
+/* gbp-debugger-editor-view-addin.h
+ *
+ * Copyright (C) 2016 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 GBP_DEBUGGER_EDITOR_VIEW_ADDIN_H
+#define GBP_DEBUGGER_EDITOR_VIEW_ADDIN_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_DEBUGGER_EDITOR_VIEW_ADDIN (gbp_debugger_editor_view_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpDebuggerEditorViewAddin, gbp_debugger_editor_view_addin, GBP, 
DEBUGGER_EDITOR_VIEW_ADDIN, GObject)
+
+G_END_DECLS
+
+#endif /* GBP_DEBUGGER_EDITOR_VIEW_ADDIN_H */
diff --git a/plugins/debugger/gbp-debugger-gutter-renderer.c b/plugins/debugger/gbp-debugger-gutter-renderer.c
new file mode 100644
index 0000000..855d22d
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-gutter-renderer.c
@@ -0,0 +1,281 @@
+/* gbp-debugger-gutter-renderer.c
+ *
+ * Copyright (C) 2016 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 "gbp-debugger-gutter-renderer"
+
+#include <glib/gi18n.h>
+
+#include "gbp-debugger-gutter-renderer.h"
+#include "gbp-debugger-breakpoints.h"
+#include "gbp-debugger-service.h"
+
+struct _GbpDebuggerGutterRenderer
+{
+  GtkSourceGutterRendererPixbuf  parent_instance;
+  GbpDebuggerBreakpoints        *breakpoints;
+  gulong                         breakpoints_changed_handler;
+};
+
+G_DEFINE_TYPE (GbpDebuggerGutterRenderer, gbp_debugger_gutter_renderer, 
GTK_SOURCE_TYPE_GUTTER_RENDERER_PIXBUF)
+
+enum {
+  PROP_0,
+  PROP_BREAKPOINTS,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_debugger_gutter_renderer_activate (GbpDebuggerGutterRenderer *self,
+                                       const GtkTextIter         *iter,
+                                       GdkRectangle              *area,
+                                       GdkEvent                  *event)
+{
+  GbpDebuggerBreakType break_type;
+  guint line;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_DEBUGGER_GUTTER_RENDERER (self));
+  g_assert (iter != NULL);
+  g_assert (area != NULL);
+  g_assert (event != NULL);
+
+  line = gtk_text_iter_get_line (iter) + 1;
+
+  IDE_TRACE_MSG ("Toggle breakpoint on line %u", line);
+
+  break_type = gbp_debugger_breakpoints_lookup (self->breakpoints, line);
+
+  switch (break_type)
+    {
+    case GBP_DEBUGGER_BREAK_NONE:
+      gbp_debugger_breakpoints_add (self->breakpoints, line, GBP_DEBUGGER_BREAK_BREAKPOINT);
+      break;
+
+    case GBP_DEBUGGER_BREAK_BREAKPOINT:
+    case GBP_DEBUGGER_BREAK_COUNTPOINT:
+    case GBP_DEBUGGER_BREAK_WATCHPOINT:
+      gbp_debugger_breakpoints_remove (self->breakpoints, line);
+      break;
+
+    default:
+      break;
+    }
+
+  IDE_EXIT;
+}
+
+static gboolean
+gbp_debugger_gutter_renderer_query_activatable (GbpDebuggerGutterRenderer *self,
+                                                const GtkTextIter         *begin,
+                                                const GdkRectangle        *area,
+                                                GdkEvent                  *event)
+{
+  g_assert (GBP_IS_DEBUGGER_GUTTER_RENDERER (self));
+  g_assert (begin != NULL);
+  g_assert (area != NULL);
+  g_assert (event != NULL);
+
+  return TRUE;
+}
+
+static void
+gbp_debugger_gutter_renderer_query_data (GbpDebuggerGutterRenderer    *self,
+                                         const GtkTextIter            *begin,
+                                         const GtkTextIter            *end,
+                                         GtkSourceGutterRendererState  state)
+{
+  GbpDebuggerBreakType break_type;
+  guint line;
+
+  g_assert (GBP_IS_DEBUGGER_GUTTER_RENDERER (self));
+  g_assert (begin != NULL);
+  g_assert (end != NULL);
+
+  if (self->breakpoints == NULL)
+    return;
+
+  line = gtk_text_iter_get_line (begin) + 1;
+  break_type = gbp_debugger_breakpoints_lookup (self->breakpoints, line);
+
+  /*
+   * These are very much a miss-appropriation of the icon, but it works
+   * well enough for now until we get real symbolic icons for these.
+   */
+#define BREAKPOINT_ICON_NAME "edit-clear-symbolic-rtl"
+#define COUNTPOINT_ICON_NAME "edit-clear-symbolic-rtl"
+#define WATCHPOINT_ICON_NAME "edit-clear-symbolic-rtl"
+
+  switch (break_type)
+    {
+    case GBP_DEBUGGER_BREAK_BREAKPOINT:
+      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self), 
BREAKPOINT_ICON_NAME);
+      break;
+
+    case GBP_DEBUGGER_BREAK_COUNTPOINT:
+      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self), 
COUNTPOINT_ICON_NAME);
+      break;
+
+    case GBP_DEBUGGER_BREAK_WATCHPOINT:
+      gtk_source_gutter_renderer_pixbuf_set_icon_name (GTK_SOURCE_GUTTER_RENDERER_PIXBUF (self), 
WATCHPOINT_ICON_NAME);
+      break;
+
+    case GBP_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;
+    }
+}
+
+static void
+gbp_debugger_gutter_renderer_breakpoints_changed (GbpDebuggerGutterRenderer *self,
+                                                  GbpDebuggerBreakpoints    *breakpoints)
+{
+  g_assert (GBP_IS_DEBUGGER_GUTTER_RENDERER (self));
+  g_assert (GBP_IS_DEBUGGER_BREAKPOINTS (breakpoints));
+
+  gtk_source_gutter_renderer_queue_draw (GTK_SOURCE_GUTTER_RENDERER (self));
+}
+
+static void
+gbp_debugger_gutter_renderer_set_breakpoints (GbpDebuggerGutterRenderer *self,
+                                              GbpDebuggerBreakpoints    *breakpoints)
+{
+  g_return_if_fail (GBP_IS_DEBUGGER_GUTTER_RENDERER (self));
+  g_return_if_fail (!breakpoints || GBP_IS_DEBUGGER_BREAKPOINTS (breakpoints));
+
+  if (self->breakpoints != breakpoints)
+    {
+      if (self->breakpoints != NULL)
+        {
+          g_signal_handler_disconnect (self->breakpoints, self->breakpoints_changed_handler);
+          self->breakpoints_changed_handler = 0;
+          g_clear_object (&self->breakpoints);
+        }
+
+      if (breakpoints != NULL)
+        {
+          self->breakpoints = g_object_ref (breakpoints);
+          self->breakpoints_changed_handler =
+            g_signal_connect_object (breakpoints,
+                                     "changed",
+                                     G_CALLBACK (gbp_debugger_gutter_renderer_breakpoints_changed),
+                                     self,
+                                     G_CONNECT_SWAPPED);
+        }
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BREAKPOINTS]);
+    }
+}
+
+static void
+gbp_debugger_gutter_renderer_finalize (GObject *object)
+{
+  GbpDebuggerGutterRenderer *self = (GbpDebuggerGutterRenderer *)object;
+
+  g_clear_object (&self->breakpoints);
+
+  G_OBJECT_CLASS (gbp_debugger_gutter_renderer_parent_class)->finalize (object);
+}
+
+static void
+gbp_debugger_gutter_renderer_get_property (GObject    *object,
+                                           guint       prop_id,
+                                           GValue     *value,
+                                           GParamSpec *pspec)
+{
+  GbpDebuggerGutterRenderer *self = GBP_DEBUGGER_GUTTER_RENDERER (object);
+
+  switch (prop_id)
+    {
+    case PROP_BREAKPOINTS:
+      g_value_set_object (value, self->breakpoints);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_gutter_renderer_set_property (GObject      *object,
+                                           guint         prop_id,
+                                           const GValue *value,
+                                           GParamSpec   *pspec)
+{
+  GbpDebuggerGutterRenderer *self = GBP_DEBUGGER_GUTTER_RENDERER (object);
+
+  switch (prop_id)
+    {
+    case PROP_BREAKPOINTS:
+      gbp_debugger_gutter_renderer_set_breakpoints (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_gutter_renderer_class_init (GbpDebuggerGutterRendererClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_debugger_gutter_renderer_finalize;
+  object_class->get_property = gbp_debugger_gutter_renderer_get_property;
+  object_class->set_property = gbp_debugger_gutter_renderer_set_property;
+
+  properties [PROP_BREAKPOINTS] =
+    g_param_spec_object ("breakpoints",
+                         "Breakpoints",
+                         "Breakpoints",
+                         GBP_TYPE_DEBUGGER_BREAKPOINTS,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_debugger_gutter_renderer_init (GbpDebuggerGutterRenderer *self)
+{
+  g_signal_connect (self,
+                    "activate",
+                    G_CALLBACK (gbp_debugger_gutter_renderer_activate),
+                    NULL);
+
+  g_signal_connect (self,
+                    "query-activatable",
+                    G_CALLBACK (gbp_debugger_gutter_renderer_query_activatable),
+                    NULL);
+
+  g_signal_connect (self,
+                    "query-data",
+                    G_CALLBACK (gbp_debugger_gutter_renderer_query_data),
+                    NULL);
+}
+
+GtkSourceGutterRenderer *
+gbp_debugger_gutter_renderer_new (void)
+{
+  return g_object_new (GBP_TYPE_DEBUGGER_GUTTER_RENDERER, NULL);
+}
diff --git a/plugins/debugger/gbp-debugger-gutter-renderer.h b/plugins/debugger/gbp-debugger-gutter-renderer.h
new file mode 100644
index 0000000..1a33297
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-gutter-renderer.h
@@ -0,0 +1,35 @@
+/* gbp-debugger-gutter-renderer.h
+ *
+ * Copyright (C) 2016 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 GBP_DEBUGGER_GUTTER_RENDERER_H
+#define GBP_DEBUGGER_GUTTER_RENDERER_H
+
+#include <gtksourceview/gtksource.h>
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_DEBUGGER_GUTTER_RENDERER (gbp_debugger_gutter_renderer_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpDebuggerGutterRenderer, gbp_debugger_gutter_renderer, GBP, 
DEBUGGER_GUTTER_RENDERER, GtkSourceGutterRendererPixbuf)
+
+GtkSourceGutterRenderer *gbp_debugger_gutter_renderer_new (void);
+
+G_END_DECLS
+
+#endif /* GBP_DEBUGGER_GUTTER_RENDERER_H */
diff --git a/plugins/debugger/gbp-debugger-perspective.c b/plugins/debugger/gbp-debugger-perspective.c
new file mode 100644
index 0000000..4a494dd
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-perspective.c
@@ -0,0 +1,126 @@
+/* gbp-debugger-perspective.c
+ *
+ * Copyright (C) 2016 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 "gbp-debugger-perspective"
+
+#include <glib/gi18n.h>
+
+#include "gbp-debugger-perspective.h"
+
+struct _GbpDebuggerPerspective
+{
+  IdeLayout parent_instance;
+};
+
+enum {
+  PROP_0,
+  N_PROPS
+};
+
+static gchar *
+gbp_debugger_perspective_get_title (IdePerspective *perspective)
+{
+  return g_strdup (_("Debugger"));
+}
+
+static gchar *
+gbp_debugger_perspective_get_id (IdePerspective *perspective)
+{
+  return g_strdup ("debugger");
+}
+
+static gchar *
+gbp_debugger_perspective_get_icon_name (IdePerspective *perspective)
+{
+  return g_strdup ("nemiver-symbolic");
+}
+
+static gchar *
+gbp_debugger_perspective_get_accelerator (IdePerspective *perspective)
+{
+  return g_strdup ("<Alt>2");
+}
+
+static void
+perspective_iface_init (IdePerspectiveInterface *iface)
+{
+  iface->get_accelerator = gbp_debugger_perspective_get_accelerator;
+  iface->get_icon_name = gbp_debugger_perspective_get_icon_name;
+  iface->get_id = gbp_debugger_perspective_get_id;
+  iface->get_title = gbp_debugger_perspective_get_title;
+}
+
+G_DEFINE_TYPE_EXTENDED (GbpDebuggerPerspective, gbp_debugger_perspective, IDE_TYPE_LAYOUT, 0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_PERSPECTIVE, perspective_iface_init))
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_debugger_perspective_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gbp_debugger_perspective_parent_class)->finalize (object);
+}
+
+static void
+gbp_debugger_perspective_get_property (GObject    *object,
+                                       guint       prop_id,
+                                       GValue     *value,
+                                       GParamSpec *pspec)
+{
+  GbpDebuggerPerspective *self = GBP_DEBUGGER_PERSPECTIVE (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_perspective_set_property (GObject      *object,
+                                       guint         prop_id,
+                                       const GValue *value,
+                                       GParamSpec   *pspec)
+{
+  GbpDebuggerPerspective *self = GBP_DEBUGGER_PERSPECTIVE (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_perspective_class_init (GbpDebuggerPerspectiveClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gbp_debugger_perspective_finalize;
+  object_class->get_property = gbp_debugger_perspective_get_property;
+  object_class->set_property = gbp_debugger_perspective_set_property;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/debugger-plugin/gbp-debugger-perspective.ui");
+}
+
+static void
+gbp_debugger_perspective_init (GbpDebuggerPerspective *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
diff --git a/plugins/debugger/gbp-debugger-perspective.h b/plugins/debugger/gbp-debugger-perspective.h
new file mode 100644
index 0000000..1abf8da
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-perspective.h
@@ -0,0 +1,32 @@
+/* gbp-debugger-perspective.h
+ *
+ * Copyright (C) 2016 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 GBP_DEBUGGER_PERSPECTIVE_H
+#define GBP_DEBUGGER_PERSPECTIVE_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_DEBUGGER_PERSPECTIVE (gbp_debugger_perspective_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpDebuggerPerspective, gbp_debugger_perspective, GBP, DEBUGGER_PERSPECTIVE, IdeLayout)
+
+G_END_DECLS
+
+#endif /* GBP_DEBUGGER_PERSPECTIVE_H */
diff --git a/plugins/debugger/gbp-debugger-perspective.ui b/plugins/debugger/gbp-debugger-perspective.ui
new file mode 100644
index 0000000..9f66b98
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-perspective.ui
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpDebuggerPerspective" parent="IdeLayout">
+  </template>
+</interface>
diff --git a/plugins/debugger/gbp-debugger-plugin.c b/plugins/debugger/gbp-debugger-plugin.c
new file mode 100644
index 0000000..58ba703
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-plugin.c
@@ -0,0 +1,36 @@
+/* gbp-debugger-plugin.c
+ *
+ * Copyright (C) 2016 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 "gbp-debugger-plugin"
+
+#include <libpeas/peas.h>
+#include <ide.h>
+
+#include "gbp-debugger-editor-view-addin.h"
+#include "gbp-debugger-workbench-addin.h"
+
+void
+peas_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_EDITOR_VIEW_ADDIN,
+                                              GBP_TYPE_DEBUGGER_EDITOR_VIEW_ADDIN);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_WORKBENCH_ADDIN,
+                                              GBP_TYPE_DEBUGGER_WORKBENCH_ADDIN);
+}
diff --git a/plugins/debugger/gbp-debugger-service.c b/plugins/debugger/gbp-debugger-service.c
new file mode 100644
index 0000000..498a70d
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-service.c
@@ -0,0 +1,153 @@
+/* gbp-debugger-service.c
+ *
+ * Copyright (C) 2016 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 "gbp-debugger-service"
+
+#include "gbp-debugger-service.h"
+
+struct _GbpDebuggerService
+{
+  IdeObject parent_instance;
+};
+
+enum {
+  PROP_0,
+  N_PROPS
+};
+
+enum {
+  BREAKPOINT_ADDED,
+  BREAKPOINT_REMOVED,
+  N_SIGNALS
+};
+
+static void
+service_iface_init (IdeServiceInterface *iface)
+{
+}
+
+G_DEFINE_TYPE_EXTENDED (GbpDebuggerService, gbp_debugger_service, IDE_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_SERVICE, service_iface_init))
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_debugger_service_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gbp_debugger_service_parent_class)->finalize (object);
+}
+
+static void
+gbp_debugger_service_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GbpDebuggerService *self = GBP_DEBUGGER_SERVICE (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_service_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  GbpDebuggerService *self = GBP_DEBUGGER_SERVICE (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_debugger_service_class_init (GbpDebuggerServiceClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_debugger_service_finalize;
+  object_class->get_property = gbp_debugger_service_get_property;
+  object_class->set_property = gbp_debugger_service_set_property;
+}
+
+static void
+gbp_debugger_service_init (GbpDebuggerService *self)
+{
+}
+
+/**
+ * gbp_debugger_service_get_breakpoints_for_file:
+ *
+ * Gets a #GbpDebuggerBreakpoints for a given #GFile.
+ *
+ * This is useful for gutter renderers that need very fast access to whether or
+ * not a line has a breakpoint on it.
+ *
+ * Returns: (transfer full): A #GbpDebuggerBreakpoints
+ */
+GbpDebuggerBreakpoints *
+gbp_debugger_service_get_breakpoints_for_file (GbpDebuggerService *self,
+                                               GFile              *file)
+{
+  GbpDebuggerBreakpoints *ret;
+  IdeContext *context;
+
+  g_return_val_if_fail (GBP_IS_DEBUGGER_SERVICE (self), NULL);
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+
+  ret = g_object_new (GBP_TYPE_DEBUGGER_BREAKPOINTS,
+                      "context", context,
+                      "file", file,
+                      NULL);
+
+  /* TODO: Load breakpoints from current IDebugger */
+
+  return ret;
+}
+
+void
+gbp_debugger_service_begin (GbpDebuggerService *self,
+                            IdeRunner          *runner)
+{
+  g_return_if_fail (GBP_IS_DEBUGGER_SERVICE (self));
+  g_return_if_fail (IDE_IS_RUNNER (runner));
+
+  g_warning ("TODO: hook in GDB into runner execution");
+
+}
+
+void
+gbp_debugger_service_toggle_breakpoint (GbpDebuggerService *self,
+                                        GFile              *file,
+                                        guint               line)
+{
+  g_return_if_fail (GBP_IS_DEBUGGER_SERVICE (self));
+  g_return_if_fail (G_IS_FILE (file));
+
+  g_warning ("TODO: toggle breakpoint for debugger instance");
+
+}
diff --git a/plugins/debugger/gbp-debugger-service.h b/plugins/debugger/gbp-debugger-service.h
new file mode 100644
index 0000000..b0b5145
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-service.h
@@ -0,0 +1,37 @@
+/* gbp-debugger-service.h
+ *
+ * Copyright (C) 2016 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 GBP_DEBUGGER_SERVICE_H
+#define GBP_DEBUGGER_SERVICE_H
+
+#include <ide.h>
+
+#include "gbp-debugger-breakpoints.h"
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_DEBUGGER_SERVICE (gbp_debugger_service_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpDebuggerService, gbp_debugger_service, GBP, DEBUGGER_SERVICE, IdeObject)
+
+void gbp_debugger_service_begin (GbpDebuggerService   *self,
+                                 IdeRunner            *runner);
+
+G_END_DECLS
+
+#endif /* GBP_DEBUGGER_SERVICE_H */
diff --git a/plugins/debugger/gbp-debugger-workbench-addin.c b/plugins/debugger/gbp-debugger-workbench-addin.c
new file mode 100644
index 0000000..3417d04
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-workbench-addin.c
@@ -0,0 +1,295 @@
+/* gbp-debugger-workbench-addin.c
+ *
+ * Copyright (C) 2016 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 "gbp-debugger-workbench-addin"
+
+#include <glib/gi18n.h>
+
+#include "gbp-debugger-perspective.h"
+#include "gbp-debugger-workbench-addin.h"
+
+struct _GbpDebuggerWorkbenchAddin
+{
+  GObject                 parent_instance;
+
+  IdeWorkbench           *workbench;
+  GbpDebuggerPerspective *perspective;
+  GSimpleActionGroup     *actions;
+
+  GtkBox                 *exec_controls;
+  GtkBox                 *step_controls;
+};
+
+static void
+gbp_debugger_workbench_addin_runner_exited (GbpDebuggerWorkbenchAddin *self,
+                                            IdeRunner                 *runner)
+{
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_RUNNER (runner));
+
+  gtk_widget_hide (GTK_WIDGET (self->exec_controls));
+  gtk_widget_hide (GTK_WIDGET (self->step_controls));
+
+  ide_workbench_set_visible_perspective_name (self->workbench, "editor");
+}
+
+static void
+debugger_run_handler (IdeRunManager *run_manager,
+                      IdeRunner     *runner,
+                      gpointer       user_data)
+{
+  GbpDebuggerWorkbenchAddin *self = user_data;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_RUN_MANAGER (run_manager));
+  g_assert (IDE_IS_RUNNER (runner));
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+
+  ide_workbench_set_visible_perspective_name (self->workbench, "debugger");
+
+  g_signal_connect_object (runner,
+                           "exited",
+                           G_CALLBACK (gbp_debugger_workbench_addin_runner_exited),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  gtk_widget_show (GTK_WIDGET (self->exec_controls));
+  gtk_widget_show (GTK_WIDGET (self->step_controls));
+
+#if 0
+  ide_runner_prepend_argv (runner, "--args");
+  ide_runner_prepend_argv (runner, "run");
+  ide_runner_prepend_argv (runner, "-ex");
+  ide_runner_prepend_argv (runner, "gdb");
+#endif
+
+  IDE_EXIT;
+}
+
+static void
+gbp_debugger_workbench_addin_load (IdeWorkbenchAddin *addin,
+                                   IdeWorkbench      *workbench)
+{
+  GbpDebuggerWorkbenchAddin *self = (GbpDebuggerWorkbenchAddin *)addin;
+  IdeWorkbenchHeaderBar *headerbar;
+  IdeRunManager *run_manager;
+  IdeContext *context;
+  GtkBox *box;
+
+  g_assert (IDE_IS_WORKBENCH_ADDIN (addin));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  self->workbench = workbench;
+
+  gtk_widget_insert_action_group (GTK_WIDGET (workbench),
+                                  "debugger",
+                                  G_ACTION_GROUP (self->actions));
+
+  headerbar = ide_workbench_get_headerbar (workbench);
+
+  context = ide_workbench_get_context (workbench);
+
+  run_manager = ide_context_get_run_manager (context);
+  ide_run_manager_add_handler (run_manager,
+                               "debugger",
+                               _("Run with Debugger"),
+                               "nemiver-symbolic",
+                               "F5",
+                               debugger_run_handler,
+                               g_object_ref (self),
+                               g_object_unref);
+
+  self->perspective = g_object_new (GBP_TYPE_DEBUGGER_PERSPECTIVE,
+                                    "visible", TRUE,
+                                    NULL);
+  ide_workbench_add_perspective (workbench, IDE_PERSPECTIVE (self->perspective));
+
+  self->exec_controls = g_object_new (GTK_TYPE_BOX,
+                                      "orientation", GTK_ORIENTATION_HORIZONTAL,
+                                      NULL);
+  ide_widget_add_style_class (GTK_WIDGET (self->exec_controls), "linked");
+  ide_workbench_header_bar_insert_left (headerbar, GTK_WIDGET (self->exec_controls), GTK_PACK_START, 100);
+
+#define ADD_BUTTON(action_name, icon_name, tooltip_text) \
+  G_STMT_START { \
+    GtkButton *button; \
+    button = g_object_new (GTK_TYPE_BUTTON, \
+                           "action-name", action_name, \
+                           "child", g_object_new (GTK_TYPE_IMAGE, \
+                                                  "icon-name", icon_name, \
+                                                  "visible", TRUE, \
+                                                  NULL), \
+                           "tooltip-text", tooltip_text, \
+                           "visible", TRUE, \
+                           NULL); \
+    gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (button)); \
+  } G_STMT_END
+
+  box = self->exec_controls;
+  ADD_BUTTON ("debugger.continue",            "debug-continue-symbolic",            _("Continue"));
+  ADD_BUTTON ("debugger.execute-from-cursor", "debug-execute-to-cursor-symbolic",   _("Execute to cursor"));
+  ADD_BUTTON ("debugger.execute-to-cursor",   "debug-execute-from-cursor-symbolic", _("Execute from 
cursor"));
+
+  self->step_controls = g_object_new (GTK_TYPE_BOX,
+                                      "orientation", GTK_ORIENTATION_HORIZONTAL,
+                                      NULL);
+  ide_widget_add_style_class (GTK_WIDGET (self->step_controls), "linked");
+  ide_workbench_header_bar_insert_left (headerbar, GTK_WIDGET (self->step_controls), GTK_PACK_START, 110);
+
+  box = self->step_controls;
+  ADD_BUTTON ("debugger.step-in",   "debug-step-in-symbolic",   _("Step in"));
+  ADD_BUTTON ("debugger.step-out",  "debug-step-out-symbolic",  _("Step out"));
+  ADD_BUTTON ("debugger.step-over", "debug-step-over-symbolic", _("Step over"));
+}
+
+static void
+gbp_debugger_workbench_addin_unload (IdeWorkbenchAddin *addin,
+                                     IdeWorkbench      *workbench)
+{
+  GbpDebuggerWorkbenchAddin *self = (GbpDebuggerWorkbenchAddin *)addin;
+  IdeRunManager *run_manager;
+  IdeContext *context;
+
+  g_assert (IDE_IS_WORKBENCH_ADDIN (addin));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  context = ide_workbench_get_context (workbench);
+  run_manager = ide_context_get_run_manager (context);
+  ide_run_manager_remove_handler (run_manager, "debugger");
+
+  gtk_widget_insert_action_group (GTK_WIDGET (workbench), "debugger", NULL);
+
+  ide_workbench_remove_perspective (workbench, IDE_PERSPECTIVE (self->perspective));
+  self->perspective = NULL;
+
+  self->workbench = NULL;
+}
+
+static void
+workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
+{
+  iface->load = gbp_debugger_workbench_addin_load;
+  iface->unload = gbp_debugger_workbench_addin_unload;
+}
+
+G_DEFINE_TYPE_EXTENDED (GbpDebuggerWorkbenchAddin, gbp_debugger_workbench_addin, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKBENCH_ADDIN, workbench_addin_iface_init))
+
+static void
+gbp_debugger_workbench_addin_finalize (GObject *object)
+{
+  GbpDebuggerWorkbenchAddin *self = (GbpDebuggerWorkbenchAddin *)object;
+
+  g_clear_object (&self->actions);
+
+  G_OBJECT_CLASS (gbp_debugger_workbench_addin_parent_class)->finalize (object);
+}
+
+static void
+gbp_debugger_workbench_addin_class_init (GbpDebuggerWorkbenchAddinClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_debugger_workbench_addin_finalize;
+}
+
+static void
+step_in_activate (GSimpleAction *action,
+                  GVariant      *param,
+                  gpointer       user_data)
+{
+  GbpDebuggerWorkbenchAddin *self = user_data;
+
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+
+}
+
+static void
+step_out_activate (GSimpleAction *action,
+                   GVariant      *param,
+                   gpointer       user_data)
+{
+  GbpDebuggerWorkbenchAddin *self = user_data;
+
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+
+}
+
+static void
+step_over_activate (GSimpleAction *action,
+                    GVariant      *param,
+                    gpointer       user_data)
+{
+  GbpDebuggerWorkbenchAddin *self = user_data;
+
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+
+}
+
+static void
+continue_action (GSimpleAction *action,
+                 GVariant      *param,
+                 gpointer       user_data)
+{
+  GbpDebuggerWorkbenchAddin *self = user_data;
+
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+
+}
+
+static void
+execute_to_cursor_action (GSimpleAction *action,
+                          GVariant      *param,
+                          gpointer       user_data)
+{
+  GbpDebuggerWorkbenchAddin *self = user_data;
+
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+
+}
+
+static void
+execute_from_cursor_action (GSimpleAction *action,
+                            GVariant      *param,
+                            gpointer       user_data)
+{
+  GbpDebuggerWorkbenchAddin *self = user_data;
+
+  g_assert (GBP_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+
+}
+
+static GActionEntry action_entries[] = {
+  { "continue", continue_action },
+  { "step-in", step_in_activate },
+  { "step-out", step_out_activate },
+  { "step-over", step_over_activate },
+  { "execute-from-cursor", execute_from_cursor_action },
+  { "execute-to-cursor", execute_to_cursor_action },
+};
+
+static void
+gbp_debugger_workbench_addin_init (GbpDebuggerWorkbenchAddin *self)
+{
+  self->actions = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+                                   action_entries,
+                                   G_N_ELEMENTS (action_entries),
+                                   self);
+}
diff --git a/plugins/debugger/gbp-debugger-workbench-addin.h b/plugins/debugger/gbp-debugger-workbench-addin.h
new file mode 100644
index 0000000..2e95623
--- /dev/null
+++ b/plugins/debugger/gbp-debugger-workbench-addin.h
@@ -0,0 +1,32 @@
+/* gbp-debugger-workbench-addin.h
+ *
+ * Copyright (C) 2016 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 GBP_DEBUGGER_WORKBENCH_ADDIN_H
+#define GBP_DEBUGGER_WORKBENCH_ADDIN_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_DEBUGGER_WORKBENCH_ADDIN (gbp_debugger_workbench_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpDebuggerWorkbenchAddin, gbp_debugger_workbench_addin, GBP, 
DEBUGGER_WORKBENCH_ADDIN, GObject)
+
+G_END_DECLS
+
+#endif /* GBP_DEBUGGER_WORKBENCH_ADDIN_H */
diff --git a/plugins/debugger/gtk/menus.ui b/plugins/debugger/gtk/menus.ui
new file mode 100644
index 0000000..b2e03ef
--- /dev/null
+++ b/plugins/debugger/gtk/menus.ui
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bc25d34..86029e0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -133,6 +133,10 @@ plugins/create-project/gbp-create-project-genesis-addin.c
 plugins/create-project/gbp-create-project-tool.c
 plugins/create-project/gbp-create-project-widget.c
 plugins/create-project/gbp-create-project-widget.ui
+plugins/debugger/gbp-debugger-perspective.c
+plugins/debugger/gbp-debugger-perspective.ui
+plugins/debugger/gbp-debugger-service.c
+plugins/debugger/gbp-debugger-workbench-addin.c
 plugins/devhelp/gbp-devhelp-panel.c
 plugins/file-search/gb-file-search-provider.c
 plugins/fpaste/fpaste_plugin/gtk/menus.ui


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