[gnome-builder: 26/139] buildui: move and refactor buildui into plugins



commit b6bb69161f82e20adfda5997e1b531d22a62ce2d
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 9 15:26:13 2019 -0800

    buildui: move and refactor buildui into plugins
    
    This rather large commit moves the buildui components into the plugins
    directory. It always was a plugin, but previously was embedded into
    libide which is no longer necessary.
    
    Also, the build preferences has been abstracted into using addins so that
    plugins can extend what can be toggled for a given build configuration.

 src/libide/buildui/OVERVIEW.md                     |   8 -
 src/libide/buildui/buildui.plugin                  |  10 -
 src/libide/buildui/ide-build-configuration-row.c   | 184 -------
 src/libide/buildui/ide-build-configuration-row.ui  |  82 ----
 src/libide/buildui/ide-build-configuration-view.c  | 483 -------------------
 src/libide/buildui/ide-build-configuration-view.h  |  36 --
 src/libide/buildui/ide-build-configuration-view.ui | 282 -----------
 src/libide/buildui/ide-build-perspective.c         | 478 -------------------
 src/libide/buildui/ide-build-perspective.h         |  36 --
 src/libide/buildui/ide-build-perspective.ui        |  46 --
 src/libide/buildui/ide-build-plugin.c              |  36 --
 src/libide/buildui/ide-build-workbench-addin.c     | 291 -----------
 src/libide/buildui/ide-environment-editor-row.c    | 280 -----------
 src/libide/buildui/ide-environment-editor-row.h    |  37 --
 src/libide/buildui/ide-environment-editor-row.ui   |  49 --
 src/libide/buildui/ide-environment-editor.c        | 319 -------------
 src/libide/buildui/ide-environment-editor.h        |  37 --
 src/libide/buildui/meson.build                     |  24 -
 src/plugins/buildui/buildui-plugin.c               |  45 ++
 src/plugins/buildui/buildui.gresource.xml          |  13 +
 src/plugins/buildui/buildui.plugin                 |  11 +
 src/plugins/buildui/gbp-buildui-config-surface.c   | 335 +++++++++++++
 src/plugins/buildui/gbp-buildui-config-surface.h   |  35 ++
 src/plugins/buildui/gbp-buildui-config-surface.ui  |  28 ++
 .../buildui/gbp-buildui-config-view-addin.c        | 517 ++++++++++++++++++++
 .../buildui/gbp-buildui-config-view-addin.h        |  31 ++
 .../buildui/gbp-buildui-log-pane.c}                | 163 +++----
 .../buildui/gbp-buildui-log-pane.h}                |  15 +-
 .../buildui/gbp-buildui-log-pane.ui}               |   3 +-
 src/plugins/buildui/gbp-buildui-omni-bar-section.c | 367 ++++++++++++++
 src/plugins/buildui/gbp-buildui-omni-bar-section.h |  35 ++
 .../buildui/gbp-buildui-omni-bar-section.ui        | 530 +++++++++++++++++++++
 .../buildui/gbp-buildui-pane.c}                    | 271 +++++------
 .../buildui/gbp-buildui-pane.h}                    |  13 +-
 .../buildui/gbp-buildui-pane.ui}                   |   3 +-
 .../buildui/gbp-buildui-runtime-categories.c       | 251 ++++++++++
 .../buildui/gbp-buildui-runtime-categories.h       |  38 ++
 src/plugins/buildui/gbp-buildui-runtime-row.c      | 137 ++++++
 .../buildui/gbp-buildui-runtime-row.h}             |  15 +-
 .../buildui/gbp-buildui-stage-row.c}               |  68 +--
 .../buildui/gbp-buildui-stage-row.h}               |  13 +-
 .../buildui/gbp-buildui-stage-row.ui}              |   2 +-
 src/plugins/buildui/gbp-buildui-tree-addin.c       | 381 +++++++++++++++
 .../buildui/gbp-buildui-tree-addin.h}              |  10 +-
 src/plugins/buildui/gbp-buildui-workspace-addin.c  | 428 +++++++++++++++++
 .../buildui/gbp-buildui-workspace-addin.h}         |  10 +-
 src/plugins/buildui/gtk/menus.ui                   |  41 ++
 src/plugins/buildui/meson.build                    |  21 +
 src/plugins/buildui/themes/shared.css              |   9 +
 49 files changed, 3543 insertions(+), 3014 deletions(-)
---
diff --git a/src/plugins/buildui/buildui-plugin.c b/src/plugins/buildui/buildui-plugin.c
new file mode 100644
index 000000000..cf395308f
--- /dev/null
+++ b/src/plugins/buildui/buildui-plugin.c
@@ -0,0 +1,45 @@
+/* buildui-plugin.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "buildui-plugin"
+
+#include "config.h"
+
+#include <libpeas/peas.h>
+#include <libide-gui.h>
+#include <libide-tree.h>
+
+#include "gbp-buildui-config-view-addin.h"
+#include "gbp-buildui-workspace-addin.h"
+#include "gbp-buildui-tree-addin.h"
+
+_IDE_EXTERN void
+_gbp_buildui_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_CONFIG_VIEW_ADDIN,
+                                              GBP_TYPE_BUILDUI_CONFIG_VIEW_ADDIN);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_WORKSPACE_ADDIN,
+                                              GBP_TYPE_BUILDUI_WORKSPACE_ADDIN);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_TREE_ADDIN,
+                                              GBP_TYPE_BUILDUI_TREE_ADDIN);
+}
diff --git a/src/plugins/buildui/buildui.gresource.xml b/src/plugins/buildui/buildui.gresource.xml
new file mode 100644
index 000000000..71dc36377
--- /dev/null
+++ b/src/plugins/buildui/buildui.gresource.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/plugins/buildui">
+    <file>buildui.plugin</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-config-surface.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-log-pane.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-omni-bar-section.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-pane.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-stage-row.ui</file>
+    <file preprocess="xml-stripblanks">gtk/menus.ui</file>
+    <file>themes/shared.css</file>
+  </gresource>
+</gresources>
diff --git a/src/plugins/buildui/buildui.plugin b/src/plugins/buildui/buildui.plugin
new file mode 100644
index 000000000..e5b4cc3a7
--- /dev/null
+++ b/src/plugins/buildui/buildui.plugin
@@ -0,0 +1,11 @@
+[Plugin]
+Authors=Christian Hergert <christian hergert me>
+Builtin=true
+Copyright=Copyright © 2015-2018 Christian Hergert
+Depends=editor;project-tree;
+Description=Provides user interface components to display the build settings.
+Embedded=_gbp_buildui_register_types
+Hidden=true
+Module=buildui
+Name=Build user interface components
+X-Workspace-Kind=primary;
diff --git a/src/plugins/buildui/gbp-buildui-config-surface.c 
b/src/plugins/buildui/gbp-buildui-config-surface.c
new file mode 100644
index 000000000..df3646dbf
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-config-surface.c
@@ -0,0 +1,335 @@
+/* gbp-buildui-config-surface.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-config-surface"
+
+#include "config.h"
+
+#include <dazzle.h>
+#include <glib/gi18n.h>
+#include <libpeas/peas.h>
+#include <libide-gui.h>
+#include <libide-foundry.h>
+
+#include "gbp-buildui-config-surface.h"
+
+struct _GbpBuilduiConfigSurface
+{
+  IdeSurface               parent_instance;
+
+  IdeConfigurationManager *config_manager;
+
+  GtkListBox              *config_list_box;
+  GtkPaned                *paned;
+  DzlPreferences          *preferences;
+
+  /* raw pointer, only use for comparison */
+  GtkListBoxRow           *last;
+};
+
+typedef struct
+{
+  DzlPreferences   *view;
+  IdeConfiguration *config;
+} AddinState;
+
+G_DEFINE_TYPE (GbpBuilduiConfigSurface, gbp_buildui_config_surface, IDE_TYPE_SURFACE)
+
+enum {
+  PROP_0,
+  PROP_CONFIG_MANAGER,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_buildui_config_surface_foreach_cb (PeasExtensionSet *set,
+                                       PeasPluginInfo   *plugin_info,
+                                       PeasExtension    *exten,
+                                       gpointer          user_data)
+{
+  IdeConfigViewAddin *addin = (IdeConfigViewAddin *)exten;
+  AddinState *state = user_data;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_CONFIG_VIEW_ADDIN (addin));
+  g_assert (state != NULL);
+
+  ide_config_view_addin_load (addin, state->view, state->config);
+}
+
+static void
+gbp_buildui_config_surface_row_selected_cb (GbpBuilduiConfigSurface *self,
+                                            GtkListBoxRow           *row,
+                                            GtkListBox              *list_box)
+{
+  g_autoptr(PeasExtensionSet) set = NULL;
+  IdeConfiguration *config;
+  AddinState state = {0};
+  GtkWidget *child2;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_CONFIG_SURFACE (self));
+  g_assert (!row || GTK_IS_LIST_BOX_ROW (row));
+  g_assert (GTK_IS_LIST_BOX (list_box));
+
+  /* Prevent double applying settings so we don't lose state */
+  if (row == self->last)
+    return;
+  self->last = row;
+
+  /* Clear out any previous view/empty-state */
+  child2 = gtk_paned_get_child2 (self->paned);
+  if (child2 != NULL)
+    gtk_widget_destroy (child2);
+  g_assert (self->preferences == NULL);
+
+  /* If no row was selected, add empty-state view */
+  if (row == NULL)
+    {
+      GtkWidget *empty;
+
+      /* Add an empty selection state instead of preferences view */
+      empty = g_object_new (DZL_TYPE_EMPTY_STATE,
+                            "icon-name", "builder-build-symbolic",
+                            "title", _("No build configuration"),
+                            "subtitle", _("Select a build configuration from the sidebar to modify."),
+                            "visible", TRUE,
+                            "hexpand", TRUE,
+                            NULL);
+      gtk_container_add (GTK_CONTAINER (self->paned), empty);
+
+      return;
+    }
+
+  /* We have a configuration to display, so do it */
+  self->preferences = g_object_new (DZL_TYPE_PREFERENCES_VIEW,
+                                    "use-sidebar", FALSE,
+                                    "visible", TRUE,
+                                    NULL);
+  g_signal_connect (self->preferences,
+                    "destroy",
+                    G_CALLBACK (gtk_widget_destroyed),
+                    &self->preferences);
+  gtk_container_add (GTK_CONTAINER (self->paned), GTK_WIDGET (self->preferences));
+
+  config = g_object_get_data (G_OBJECT (row), "CONFIG");
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  set = peas_extension_set_new (peas_engine_get_default (),
+                                IDE_TYPE_CONFIG_VIEW_ADDIN,
+                                NULL);
+
+  state.view = self->preferences;
+  state.config = config;
+
+  peas_extension_set_foreach (set,
+                              gbp_buildui_config_surface_foreach_cb,
+                              &state);
+}
+
+static GtkWidget *
+gbp_buildui_config_surface_create_row_cb (gpointer item,
+                                          gpointer user_data)
+{
+  GbpBuilduiConfigSurface *self = user_data;
+  IdeConfiguration *config = item;
+  const gchar *title;
+  GtkWidget *row;
+  GtkWidget *label;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_CONFIG_SURFACE (self));
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  title = ide_configuration_get_display_name (config);
+
+  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
+                      "visible", TRUE,
+                      NULL);
+  label = g_object_new (GTK_TYPE_LABEL,
+                        "visible", TRUE,
+                        "label", title,
+                        "xalign", 0.0f,
+                        "margin", 6,
+                        NULL);
+  gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (label));
+
+  g_object_set_data_full (G_OBJECT (row),
+                          "CONFIG",
+                          g_object_ref (config),
+                          g_object_unref);
+
+  return row;
+}
+
+static void
+gbp_buildui_config_surface_set_config_manager (GbpBuilduiConfigSurface *self,
+                                               IdeConfigurationManager *config_manager)
+{
+  g_assert (GBP_IS_BUILDUI_CONFIG_SURFACE (self));
+  g_assert (IDE_IS_CONFIGURATION_MANAGER (config_manager));
+  g_assert (self->config_manager == NULL);
+
+  g_set_object (&self->config_manager, config_manager);
+
+  gtk_list_box_bind_model (self->config_list_box,
+                           G_LIST_MODEL (config_manager),
+                           gbp_buildui_config_surface_create_row_cb,
+                           g_object_ref (self),
+                           g_object_unref);
+}
+
+static void
+header_func_cb (GtkListBoxRow *row,
+                GtkListBoxRow *before,
+                gpointer       user_data)
+{
+  if (before == NULL)
+    {
+      PangoAttrList *attrs;
+      GtkWidget *header;
+
+      attrs = pango_attr_list_new ();
+      pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+      pango_attr_list_insert (attrs, pango_attr_foreground_alpha_new (.55 * G_MAXUSHORT));
+
+      header = g_object_new (GTK_TYPE_LABEL,
+                             "attributes", attrs,
+                             "label", _("Build Configurations"),
+                             "xalign", 0.0f,
+                             "visible", TRUE,
+                             NULL);
+      dzl_gtk_widget_add_style_class (header, "header");
+
+      gtk_list_box_row_set_header (row, header);
+
+      pango_attr_list_unref (attrs);
+    }
+}
+
+static void
+gbp_buildui_config_surface_get_property (GObject    *object,
+                                         guint       prop_id,
+                                         GValue     *value,
+                                         GParamSpec *pspec)
+{
+  GbpBuilduiConfigSurface *self = GBP_BUILDUI_CONFIG_SURFACE (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONFIG_MANAGER:
+      g_value_set_object (value, self->config_manager);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_buildui_config_surface_set_property (GObject      *object,
+                                         guint         prop_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
+{
+  GbpBuilduiConfigSurface *self = GBP_BUILDUI_CONFIG_SURFACE (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONFIG_MANAGER:
+      gbp_buildui_config_surface_set_config_manager (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_buildui_config_surface_class_init (GbpBuilduiConfigSurfaceClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = gbp_buildui_config_surface_get_property;
+  object_class->set_property = gbp_buildui_config_surface_set_property;
+
+  properties [PROP_CONFIG_MANAGER] =
+    g_param_spec_object ("config-manager",
+                         "Config Manager",
+                         "The configuration manager",
+                         IDE_TYPE_CONFIGURATION_MANAGER,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/buildui/gbp-buildui-config-surface.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiConfigSurface, config_list_box);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiConfigSurface, paned);
+}
+
+static void
+gbp_buildui_config_surface_init (GbpBuilduiConfigSurface *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  gtk_list_box_set_header_func (self->config_list_box, header_func_cb, NULL, NULL);
+
+  g_signal_connect_object (self->config_list_box,
+                           "row-selected",
+                           G_CALLBACK (gbp_buildui_config_surface_row_selected_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+gbp_buildui_config_surface_set_config_cb (GtkWidget *widget,
+                                          gpointer   user_data)
+{
+  IdeConfiguration *config = user_data;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GTK_IS_LIST_BOX_ROW (widget));
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  if (g_object_get_data (G_OBJECT (widget), "CONFIG") == (gpointer)config)
+    {
+      GtkListBox *list_box = GTK_LIST_BOX (gtk_widget_get_parent (widget));
+
+      gtk_list_box_select_row (list_box, GTK_LIST_BOX_ROW (widget));
+    }
+}
+
+void
+gbp_buildui_config_surface_set_config (GbpBuilduiConfigSurface *self,
+                                       IdeConfiguration        *config)
+{
+  g_return_if_fail (IDE_IS_MAIN_THREAD ());
+  g_return_if_fail (GBP_IS_BUILDUI_CONFIG_SURFACE (self));
+  g_return_if_fail (IDE_IS_CONFIGURATION (config));
+
+  gtk_container_foreach (GTK_CONTAINER (self->config_list_box),
+                         gbp_buildui_config_surface_set_config_cb,
+                         config);
+}
diff --git a/src/plugins/buildui/gbp-buildui-config-surface.h 
b/src/plugins/buildui/gbp-buildui-config-surface.h
new file mode 100644
index 000000000..0f931dba2
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-config-surface.h
@@ -0,0 +1,35 @@
+/* gbp-buildui-config-surface.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-foundry.h>
+#include <libide-gui.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_CONFIG_SURFACE (gbp_buildui_config_surface_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpBuilduiConfigSurface, gbp_buildui_config_surface, GBP, BUILDUI_CONFIG_SURFACE, 
IdeSurface)
+
+void gbp_buildui_config_surface_set_config (GbpBuilduiConfigSurface *self,
+                                            IdeConfiguration        *config);
+
+G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-config-surface.ui 
b/src/plugins/buildui/gbp-buildui-config-surface.ui
new file mode 100644
index 000000000..df511de6d
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-config-surface.ui
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpBuilduiConfigSurface" parent="IdeSurface">
+    <style>
+      <class name="buildui"/>
+    </style>
+    <child>
+      <object class="GtkPaned" id="paned">
+        <property name="position">275</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkScrolledWindow">
+            <property name="propagate-natural-width">true</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GtkListBox" id="config_list_box">
+                <property name="visible">true</property>
+                <style>
+                  <class name="sidebar"/>
+                </style>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/plugins/buildui/gbp-buildui-config-view-addin.c 
b/src/plugins/buildui/gbp-buildui-config-view-addin.c
new file mode 100644
index 000000000..97d9da31b
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-config-view-addin.c
@@ -0,0 +1,517 @@
+/* gbp-buildui-config-view-addin.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-config-view-addin"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+
+#include "gbp-buildui-config-view-addin.h"
+#include "gbp-buildui-runtime-categories.h"
+#include "gbp-buildui-runtime-row.h"
+
+struct _GbpBuilduiConfigViewAddin
+{
+  GObject parent_instance;
+};
+
+static gboolean
+treat_null_as_empty (GBinding     *binding,
+                     const GValue *from_value,
+                     GValue       *to_value,
+                     gpointer      user_data)
+{
+  const gchar *str = g_value_get_string (from_value);
+  g_value_set_string (to_value, str ?: "");
+  return TRUE;
+}
+
+static void
+add_description_row (DzlPreferences *preferences,
+                     const gchar    *page,
+                     const gchar    *group,
+                     const gchar    *title,
+                     const gchar    *value,
+                     GtkWidget      *value_widget)
+{
+  GtkWidget *widget;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (DZL_IS_PREFERENCES (preferences));
+
+  widget = g_object_new (GTK_TYPE_LABEL,
+                         "xalign", 0.0f,
+                         "label", title,
+                         "visible", TRUE,
+                         "margin-right", 12,
+                         NULL);
+  dzl_gtk_widget_add_style_class (widget, "dim-label");
+
+  if (value_widget == NULL)
+    value_widget = g_object_new (GTK_TYPE_LABEL,
+                                 "hexpand", TRUE,
+                                 "label", value,
+                                 "xalign", 0.0f,
+                                 "visible", TRUE,
+                                 NULL);
+
+  dzl_preferences_add_table_row (preferences, page, group, widget, value_widget, NULL);
+}
+
+static GtkWidget *
+create_stack_list_row (gpointer item,
+                       gpointer user_data)
+{
+  IdeConfiguration *config = user_data;
+  GtkWidget *row;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  if (IDE_IS_RUNTIME (item))
+    return gbp_buildui_runtime_row_new (item, config);
+
+  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
+                      "visible", TRUE,
+                      NULL);
+  g_object_set_data_full (G_OBJECT (row),
+                          "ITEM",
+                          g_object_ref (item),
+                          g_object_unref);
+
+  if (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (item))
+    {
+      const gchar *category = gbp_buildui_runtime_categories_get_name (item);
+      GtkWidget *label;
+
+      label = g_object_new (GTK_TYPE_LABEL,
+                            "label", category,
+                            "margin", 10,
+                            "use-markup", TRUE,
+                            "visible", TRUE,
+                            "xalign", 0.0f,
+                            NULL);
+      gtk_container_add (GTK_CONTAINER (row), label);
+    }
+  else if (DZL_IS_LIST_MODEL_FILTER (item))
+    {
+      const gchar *category = g_object_get_data (item, "CATEGORY");
+      GtkWidget *label;
+
+      label = g_object_new (GTK_TYPE_LABEL,
+                            "label", category,
+                            "margin", 10,
+                            "use-markup", TRUE,
+                            "visible", TRUE,
+                            "xalign", 0.0f,
+                            NULL);
+      gtk_container_add (GTK_CONTAINER (row), label);
+    }
+
+  return row;
+}
+
+static void
+on_runtime_row_activated_cb (DzlStackList  *stack_list,
+                             GtkListBoxRow *row,
+                             gpointer       user_data)
+{
+  IdeConfiguration *config = user_data;
+  gpointer item;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (DZL_IS_STACK_LIST (stack_list));
+  g_assert (GTK_IS_LIST_BOX_ROW (row));
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  if (GBP_IS_BUILDUI_RUNTIME_ROW (row))
+    {
+      const gchar *id;
+
+      id = gbp_buildui_runtime_row_get_id (GBP_BUILDUI_RUNTIME_ROW (row));
+      ide_configuration_set_runtime_id (config, id);
+
+      {
+        GtkWidget *box;
+
+        if ((box = gtk_widget_get_ancestor (GTK_WIDGET (row), GTK_TYPE_LIST_BOX)))
+          gtk_list_box_unselect_all (GTK_LIST_BOX (box));
+      }
+
+      return;
+    }
+
+  item = g_object_get_data (G_OBJECT (row), "ITEM");
+  g_assert (G_IS_LIST_MODEL (item) || IDE_IS_RUNTIME (item));
+
+  if (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (item))
+    {
+      dzl_stack_list_push (stack_list,
+                           create_stack_list_row (item, config),
+                           G_LIST_MODEL (item),
+                           create_stack_list_row,
+                           g_object_ref (config),
+                           g_object_unref);
+    }
+  else if (G_IS_LIST_MODEL (item))
+    {
+      dzl_stack_list_push (stack_list,
+                           create_stack_list_row (item, config),
+                           G_LIST_MODEL (item),
+                           create_stack_list_row,
+                           g_object_ref (config),
+                           g_object_unref);
+    }
+}
+
+static GtkWidget *
+create_runtime_box (IdeConfiguration  *config,
+                    IdeRuntimeManager *runtime_manager)
+{
+  g_autoptr(GbpBuilduiRuntimeCategories) filter = NULL;
+  DzlStackList *stack;
+  const gchar *category;
+  IdeRuntime *runtime;
+  GtkWidget *header;
+  GtkWidget *frame;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONFIGURATION (config));
+  g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
+
+  filter = gbp_buildui_runtime_categories_new (runtime_manager, NULL);
+
+  frame = g_object_new (GTK_TYPE_FRAME,
+                        "visible", TRUE,
+                        NULL);
+
+  header = g_object_new (GTK_TYPE_LABEL,
+                         "label", _("All Runtimes"),
+                         "margin", 10,
+                         "visible", TRUE,
+                         "xalign", 0.0f,
+                         NULL);
+
+  stack = g_object_new (DZL_TYPE_STACK_LIST,
+                        "visible", TRUE,
+                        NULL);
+  dzl_stack_list_push (stack,
+                       header,
+                       G_LIST_MODEL (filter),
+                       create_stack_list_row,
+                       g_object_ref (config),
+                       g_object_unref);
+  gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (stack));
+
+  g_signal_connect_object (stack,
+                           "row-activated",
+                           G_CALLBACK (on_runtime_row_activated_cb),
+                           config,
+                           0);
+
+  if ((runtime = ide_configuration_get_runtime (config)) &&
+      (category = ide_runtime_get_category (runtime)))
+    {
+      g_autoptr(GString) prefix = g_string_new (NULL);
+      g_auto(GStrv) parts = g_strsplit (category, "/", 0);
+
+      for (guint i = 0; parts[i]; i++)
+        {
+          g_autoptr(GListModel) model = NULL;
+
+          g_string_append (prefix, parts[i]);
+          if (parts[i+1])
+            g_string_append_c (prefix, '/');
+
+          model = gbp_buildui_runtime_categories_create_child_model (filter, prefix->str);
+
+          dzl_stack_list_push (stack,
+                               create_stack_list_row (model, config),
+                               model,
+                               create_stack_list_row,
+                               g_object_ref (config),
+                               g_object_unref);
+        }
+    }
+
+  return GTK_WIDGET (frame);
+}
+
+static void
+notify_toolchain_id (IdeConfiguration *config,
+                     GParamSpec       *pspec,
+                     GtkImage         *image)
+{
+  const gchar *toolchain_id;
+  const gchar *current;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONFIGURATION (config));
+  g_assert (GTK_IS_IMAGE (image));
+
+  toolchain_id = ide_configuration_get_toolchain_id (config);
+  current = g_object_get_data (G_OBJECT (image), "TOOLCHAIN_ID");
+
+  gtk_widget_set_visible (GTK_WIDGET (image), ide_str_equal0 (toolchain_id, current));
+}
+
+static GtkWidget *
+create_toolchain_row (gpointer item,
+                      gpointer user_data)
+{
+  IdeToolchain *toolchain = item;
+  IdeConfiguration *config = user_data;
+  const gchar *toolchain_id;
+  GtkWidget *label;
+  GtkWidget *row;
+  GtkWidget *box;
+  GtkImage *image;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TOOLCHAIN (toolchain));
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  toolchain_id = ide_toolchain_get_id (toolchain);
+
+  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
+                      "visible", TRUE,
+                      NULL);
+  g_object_set_data_full (G_OBJECT (row), "TOOLCHAIN_ID", g_strdup (toolchain_id), g_free);
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "spacing", 6,
+                      "visible", TRUE,
+                      NULL);
+  gtk_container_add (GTK_CONTAINER (row), box);
+
+  label = g_object_new (GTK_TYPE_LABEL,
+                        "label", ide_toolchain_get_display_name (toolchain),
+                        "visible", TRUE,
+                        "xalign", 0.0f,
+                        NULL);
+  gtk_container_add (GTK_CONTAINER (box), label);
+
+  image = g_object_new (GTK_TYPE_IMAGE,
+                        "icon-name", "object-select-symbolic",
+                        "halign", GTK_ALIGN_START,
+                        "hexpand", TRUE,
+                        NULL);
+  g_object_set_data_full (G_OBJECT (image), "TOOLCHAIN_ID", g_strdup (toolchain_id), g_free);
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (image));
+
+  g_signal_connect_object (config,
+                           "notify::toolchain-id",
+                           G_CALLBACK (notify_toolchain_id),
+                           image,
+                           0);
+  notify_toolchain_id (config, NULL, image);
+
+  return row;
+}
+
+static void
+on_toolchain_row_activated_cb (GtkListBox       *list_box,
+                               GtkListBoxRow    *row,
+                               IdeConfiguration *config)
+{
+  const gchar *toolchain_id;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GTK_IS_LIST_BOX (list_box));
+  g_assert (GTK_IS_LIST_BOX_ROW (row));
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  if ((toolchain_id = g_object_get_data (G_OBJECT (row), "TOOLCHAIN_ID")))
+    ide_configuration_set_toolchain_id (config, toolchain_id);
+
+  gtk_list_box_unselect_all (list_box);
+}
+
+static GtkWidget *
+create_toolchain_box (IdeConfiguration    *config,
+                      IdeToolchainManager *toolchain_manager)
+{
+  GtkScrolledWindow *scroller;
+  GtkListBox *list_box;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONFIGURATION (config));
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (toolchain_manager));
+
+  scroller = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+                           "propagate-natural-height", TRUE,
+                           "shadow-type", GTK_SHADOW_IN,
+                           "visible", TRUE,
+                           NULL);
+
+  list_box = g_object_new (GTK_TYPE_LIST_BOX,
+                           "visible", TRUE,
+                           NULL);
+  g_signal_connect_object (list_box,
+                           "row-activated",
+                           G_CALLBACK (on_toolchain_row_activated_cb),
+                           config,
+                           0);
+  gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (list_box));
+
+  gtk_list_box_bind_model (list_box,
+                           G_LIST_MODEL (toolchain_manager),
+                           create_toolchain_row,
+                           g_object_ref (config),
+                           g_object_unref);
+
+  return GTK_WIDGET (scroller);
+}
+
+static void
+gbp_buildui_config_view_addin_load (IdeConfigViewAddin *addin,
+                                    DzlPreferences     *preferences,
+                                    IdeConfiguration   *config)
+{
+  GbpBuilduiConfigViewAddin *self = (GbpBuilduiConfigViewAddin *)addin;
+  IdeToolchainManager *toolchain_manager;
+  IdeRuntimeManager *runtime_manager;
+  g_autoptr(GFile) workdir = NULL;
+  IdeBuildSystem *build_system;
+  IdeEnvironment *environ;
+  IdeContext *context;
+  GtkWidget *box;
+  GtkWidget *entry;
+  static const struct {
+    const gchar *label;
+    const gchar *action;
+    const gchar *tooltip;
+    const gchar *style_class;
+  } actions[] = {
+    { N_("Make active"), "config-manager.current", N_("Select this configuration as the active 
configuration.") },
+    { N_("Duplicate"), "config-manager.duplicate", N_("Duplicating the configuration allows making changes 
without modifying this configuration.") },
+    { N_("Remove"), "config-manager.delete", N_("Removes the configuration and cannot be undone."), 
"destructive-action" },
+  };
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_CONFIG_VIEW_ADDIN (self));
+  g_assert (DZL_IS_PREFERENCES (preferences));
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  /* Get manager objects */
+  context = ide_object_get_context (IDE_OBJECT (config));
+  runtime_manager = ide_runtime_manager_from_context (context);
+  toolchain_manager = ide_toolchain_manager_from_context (context);
+  build_system = ide_build_system_from_context (context);
+  workdir = ide_context_ref_workdir (context);
+
+  /* Add our pages */
+  dzl_preferences_add_page (preferences, "general", _("General"), 0);
+  dzl_preferences_add_page (preferences, "environ", _("Environment"), 20);
+
+  /* Add groups to pages */
+  dzl_preferences_add_list_group (preferences, "general", "general", _("Overview"), GTK_SELECTION_NONE, 0);
+  dzl_preferences_add_group (preferences, "general", "buttons", NULL, 0);
+  dzl_preferences_add_group (preferences, "environ", "build", _("Build Environment"), 0);
+
+  /* actions button box */
+  box = g_object_new (GTK_TYPE_BOX,
+                      "homogeneous", TRUE,
+                      "spacing", 12,
+                      "visible", TRUE,
+                      NULL);
+  for (guint i = 0; i < G_N_ELEMENTS (actions); i++)
+    {
+      GtkWidget *button;
+
+      button = g_object_new (GTK_TYPE_BUTTON,
+                             "visible", TRUE,
+                             "action-name", actions[i].action,
+                             "action-target", g_variant_new_string (ide_configuration_get_id (config)),
+                             "label", g_dgettext (GETTEXT_PACKAGE, actions[i].label),
+                             "tooltip-text", g_dgettext (GETTEXT_PACKAGE, actions[i].tooltip),
+                             NULL);
+      if (actions[i].style_class)
+        dzl_gtk_widget_add_style_class (button, actions[i].style_class);
+      gtk_container_add (GTK_CONTAINER (box), button);
+    }
+
+  /* Add description info */
+  add_description_row (preferences, "general", "general", _("Name"), ide_configuration_get_display_name 
(config), NULL);
+  add_description_row (preferences, "general", "general", _("Source Directory"), g_file_peek_path (workdir), 
NULL);
+  add_description_row (preferences, "general", "general", _("Build System"), 
ide_build_system_get_display_name (build_system), NULL);
+
+  entry = g_object_new (GTK_TYPE_ENTRY,
+                        "visible", TRUE,
+                        "hexpand", TRUE,
+                        NULL);
+  g_object_bind_property_full (config, "prefix", entry, "text",
+                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
+                               treat_null_as_empty, NULL, NULL, NULL);
+  add_description_row (preferences, "general", "general", _("Install Prefix"), NULL, entry);
+
+  entry = g_object_new (GTK_TYPE_ENTRY,
+                        "visible", TRUE,
+                        "hexpand", TRUE,
+                        NULL);
+  g_object_bind_property_full (config, "config-opts", entry, "text",
+                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
+                               treat_null_as_empty, NULL, NULL, NULL);
+  add_description_row (preferences, "general", "general", _("Configure Options"), NULL, entry);
+
+  dzl_preferences_add_custom (preferences, "general", "buttons", box, NULL, 5);
+
+  /* Setup runtime selection */
+  dzl_preferences_add_group (preferences, "general", "runtime", _("Application Runtime"), 10);
+  dzl_preferences_add_custom (preferences, "general", "runtime", create_runtime_box (config, 
runtime_manager), NULL, 10);
+
+  /* Setup toolchain selection */
+  dzl_preferences_add_group (preferences, "general", "toolchain", _("Build Toolchain"), 20);
+  dzl_preferences_add_custom (preferences, "general", "toolchain", create_toolchain_box (config, 
toolchain_manager), NULL, 10);
+
+  /* Add environment selector */
+  environ = ide_configuration_get_environment (config);
+  dzl_preferences_add_custom (preferences, "environ", "build",
+                              g_object_new (GTK_TYPE_FRAME,
+                                            "visible", TRUE,
+                                            "child", g_object_new (IDE_TYPE_ENVIRONMENT_EDITOR,
+                                                                   "environment", environ,
+                                                                   "visible", TRUE,
+                                                                   NULL),
+                                            NULL),
+                              NULL, 0);
+}
+
+static void
+config_view_addin_iface_init (IdeConfigViewAddinInterface *iface)
+{
+  iface->load = gbp_buildui_config_view_addin_load;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpBuilduiConfigViewAddin, gbp_buildui_config_view_addin, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_CONFIG_VIEW_ADDIN, config_view_addin_iface_init))
+
+static void
+gbp_buildui_config_view_addin_class_init (GbpBuilduiConfigViewAddinClass *klass)
+{
+}
+
+static void
+gbp_buildui_config_view_addin_init (GbpBuilduiConfigViewAddin *self)
+{
+}
diff --git a/src/plugins/buildui/gbp-buildui-config-view-addin.h 
b/src/plugins/buildui/gbp-buildui-config-view-addin.h
new file mode 100644
index 000000000..7c8f1d1c4
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-config-view-addin.h
@@ -0,0 +1,31 @@
+/* gbp-buildui-config-view-addin.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_CONFIG_VIEW_ADDIN (gbp_buildui_config_view_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpBuilduiConfigViewAddin, gbp_buildui_config_view_addin, GBP, 
BUILDUI_CONFIG_VIEW_ADDIN, GObject)
+
+G_END_DECLS
diff --git a/src/libide/buildui/ide-build-log-panel.c b/src/plugins/buildui/gbp-buildui-log-pane.c
similarity index 62%
rename from src/libide/buildui/ide-build-log-panel.c
rename to src/plugins/buildui/gbp-buildui-log-pane.c
index 89f6bdbeb..7bdab1908 100644
--- a/src/libide/buildui/ide-build-log-panel.c
+++ b/src/plugins/buildui/gbp-buildui-log-pane.c
@@ -1,4 +1,4 @@
-/* ide-build-log-panel.c
+/* gbp-buildui-log-pane.c
  *
  * Copyright 2015-2019 Christian Hergert <chergert redhat com>
  *
@@ -18,21 +18,20 @@
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
-#define G_LOG_DOMAIN "ide-build-log-panel"
+#define G_LOG_DOMAIN "gbp-buildui-log-pane"
 
 #include "config.h"
 
-#include <dazzle.h>
+#include <libide-terminal.h>
 #include <glib/gi18n.h>
-#include <ide.h>
 
-#include "buildsystem/ide-build-private.h"
-#include "buildui/ide-build-log-panel.h"
-#include "terminal/ide-terminal.h"
+#include "ide-build-private.h"
 
-struct _IdeBuildLogPanel
+#include "gbp-buildui-log-pane.h"
+
+struct _GbpBuilduiLogPane
 {
-  DzlDockWidget      parent_instance;
+  IdePane            parent_instance;
 
   IdeBuildPipeline  *pipeline;
 
@@ -48,27 +47,27 @@ enum {
   N_PROPS
 };
 
-G_DEFINE_TYPE (IdeBuildLogPanel, ide_build_log_panel, DZL_TYPE_DOCK_WIDGET)
+G_DEFINE_TYPE (GbpBuilduiLogPane, gbp_buildui_log_pane, IDE_TYPE_PANE)
 
 static GParamSpec *properties [N_PROPS];
 
 static void
-ide_build_log_panel_reset_view (IdeBuildLogPanel *self)
+gbp_buildui_log_pane_reset_view (GbpBuilduiLogPane *self)
 {
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
 
   vte_terminal_reset (VTE_TERMINAL (self->terminal), TRUE, TRUE);
 }
 
 static void
-ide_build_log_panel_log_observer (IdeBuildLogStream  stream,
-                                  const gchar       *message,
-                                  gssize             message_len,
-                                  gpointer           user_data)
+gbp_buildui_log_pane_log_observer (IdeBuildLogStream  stream,
+                                   const gchar       *message,
+                                   gssize             message_len,
+                                   gpointer           user_data)
 {
-  IdeBuildLogPanel *self = user_data;
+  GbpBuilduiLogPane *self = user_data;
 
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
   g_assert (message != NULL);
   g_assert (message_len >= 0);
   g_assert (message[message_len] == '\0');
@@ -78,11 +77,11 @@ ide_build_log_panel_log_observer (IdeBuildLogStream  stream,
 }
 
 static void
-ide_build_log_panel_notify_pty (IdeBuildLogPanel *self,
-                                GParamSpec       *pspec,
-                                IdeBuildPipeline *pipeline)
+gbp_buildui_log_pane_notify_pty (GbpBuilduiLogPane *self,
+                                 GParamSpec        *pspec,
+                                 IdeBuildPipeline  *pipeline)
 {
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
   g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
   vte_terminal_set_pty (VTE_TERMINAL (self->terminal),
@@ -90,10 +89,10 @@ ide_build_log_panel_notify_pty (IdeBuildLogPanel *self,
 }
 
 void
-ide_build_log_panel_set_pipeline (IdeBuildLogPanel *self,
-                                  IdeBuildPipeline *pipeline)
+gbp_buildui_log_pane_set_pipeline (GbpBuilduiLogPane *self,
+                                   IdeBuildPipeline  *pipeline)
 {
-  g_return_if_fail (IDE_IS_BUILD_LOG_PANEL (self));
+  g_return_if_fail (GBP_IS_BUILDUI_LOG_PANE (self));
   g_return_if_fail (!pipeline || IDE_IS_BUILD_PIPELINE (pipeline));
 
   if (pipeline != self->pipeline)
@@ -101,7 +100,7 @@ ide_build_log_panel_set_pipeline (IdeBuildLogPanel *self,
       if (self->pipeline != NULL)
         {
           g_signal_handlers_disconnect_by_func (self->pipeline,
-                                                G_CALLBACK (ide_build_log_panel_notify_pty),
+                                                G_CALLBACK (gbp_buildui_log_pane_notify_pty),
                                                 self);
           ide_build_pipeline_remove_log_observer (self->pipeline, self->log_observer);
           self->log_observer = 0;
@@ -114,7 +113,7 @@ ide_build_log_panel_set_pipeline (IdeBuildLogPanel *self,
           self->pipeline = g_object_ref (pipeline);
           self->log_observer =
             ide_build_pipeline_add_log_observer (self->pipeline,
-                                                 ide_build_log_panel_log_observer,
+                                                 gbp_buildui_log_pane_log_observer,
                                                  self,
                                                  NULL);
           vte_terminal_reset (VTE_TERMINAL (self->terminal), TRUE, TRUE);
@@ -122,7 +121,7 @@ ide_build_log_panel_set_pipeline (IdeBuildLogPanel *self,
                                 ide_build_pipeline_get_pty (pipeline));
           g_signal_connect_object (pipeline,
                                    "notify::pty",
-                                   G_CALLBACK (ide_build_log_panel_notify_pty),
+                                   G_CALLBACK (gbp_buildui_log_pane_notify_pty),
                                    self,
                                    G_CONNECT_SWAPPED);
         }
@@ -130,10 +129,10 @@ ide_build_log_panel_set_pipeline (IdeBuildLogPanel *self,
 }
 
 static void
-ide_build_log_panel_window_title_changed (IdeBuildLogPanel *self,
-                                          IdeTerminal      *terminal)
+gbp_buildui_log_pane_window_title_changed (GbpBuilduiLogPane *self,
+                                           IdeTerminal       *terminal)
 {
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
   g_assert (VTE_IS_TERMINAL (terminal));
 
   if (self->pipeline != NULL)
@@ -146,43 +145,43 @@ ide_build_log_panel_window_title_changed (IdeBuildLogPanel *self,
 }
 
 static void
-ide_build_log_panel_grab_focus (GtkWidget *widget)
+gbp_buildui_log_pane_grab_focus (GtkWidget *widget)
 {
-  IdeBuildLogPanel *self = (IdeBuildLogPanel *)widget;
+  GbpBuilduiLogPane *self = (GbpBuilduiLogPane *)widget;
 
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
 
   if (self->terminal != NULL)
     gtk_widget_grab_focus (GTK_WIDGET (self->terminal));
 }
 
 static void
-ide_build_log_panel_finalize (GObject *object)
+gbp_buildui_log_pane_finalize (GObject *object)
 {
-  IdeBuildLogPanel *self = (IdeBuildLogPanel *)object;
+  GbpBuilduiLogPane *self = (GbpBuilduiLogPane *)object;
 
   g_clear_object (&self->pipeline);
 
-  G_OBJECT_CLASS (ide_build_log_panel_parent_class)->finalize (object);
+  G_OBJECT_CLASS (gbp_buildui_log_pane_parent_class)->finalize (object);
 }
 
 static void
-ide_build_log_panel_dispose (GObject *object)
+gbp_buildui_log_pane_dispose (GObject *object)
 {
-  IdeBuildLogPanel *self = (IdeBuildLogPanel *)object;
+  GbpBuilduiLogPane *self = (GbpBuilduiLogPane *)object;
 
-  ide_build_log_panel_set_pipeline (self, NULL);
+  gbp_buildui_log_pane_set_pipeline (self, NULL);
 
-  G_OBJECT_CLASS (ide_build_log_panel_parent_class)->dispose (object);
+  G_OBJECT_CLASS (gbp_buildui_log_pane_parent_class)->dispose (object);
 }
 
 static void
-ide_build_log_panel_get_property (GObject    *object,
-                                  guint       prop_id,
-                                  GValue     *value,
-                                  GParamSpec *pspec)
+gbp_buildui_log_pane_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
 {
-  IdeBuildLogPanel *self = IDE_BUILD_LOG_PANEL (object);
+  GbpBuilduiLogPane *self = GBP_BUILDUI_LOG_PANE (object);
 
   switch (prop_id)
     {
@@ -196,17 +195,17 @@ ide_build_log_panel_get_property (GObject    *object,
 }
 
 static void
-ide_build_log_panel_set_property (GObject      *object,
-                                  guint         prop_id,
-                                  const GValue *value,
-                                  GParamSpec   *pspec)
+gbp_buildui_log_pane_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
 {
-  IdeBuildLogPanel *self = IDE_BUILD_LOG_PANEL (object);
+  GbpBuilduiLogPane *self = GBP_BUILDUI_LOG_PANE (object);
 
   switch (prop_id)
     {
     case PROP_PIPELINE:
-      ide_build_log_panel_set_pipeline (self, g_value_get_object (value));
+      gbp_buildui_log_pane_set_pipeline (self, g_value_get_object (value));
       break;
 
     default:
@@ -215,22 +214,22 @@ ide_build_log_panel_set_property (GObject      *object,
 }
 
 static void
-ide_build_log_panel_class_init (IdeBuildLogPanelClass *klass)
+gbp_buildui_log_pane_class_init (GbpBuilduiLogPaneClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  object_class->dispose = ide_build_log_panel_dispose;
-  object_class->finalize = ide_build_log_panel_finalize;
-  object_class->get_property = ide_build_log_panel_get_property;
-  object_class->set_property = ide_build_log_panel_set_property;
+  object_class->dispose = gbp_buildui_log_pane_dispose;
+  object_class->finalize = gbp_buildui_log_pane_finalize;
+  object_class->get_property = gbp_buildui_log_pane_get_property;
+  object_class->set_property = gbp_buildui_log_pane_set_property;
 
-  widget_class->grab_focus = ide_build_log_panel_grab_focus;
+  widget_class->grab_focus = gbp_buildui_log_pane_grab_focus;
 
   gtk_widget_class_set_css_name (widget_class, "buildlogpanel");
-  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/buildui/ide-build-log-panel.ui");
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildLogPanel, scrollbar);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildLogPanel, terminal);
+  gtk_widget_class_set_template_from_resource (widget_class, "/plugins/buildui/gbp-buildui-log-pane.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiLogPane, scrollbar);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiLogPane, terminal);
 
   properties [PROP_PIPELINE] =
     g_param_spec_object ("pipeline",
@@ -243,24 +242,24 @@ ide_build_log_panel_class_init (IdeBuildLogPanelClass *klass)
 }
 
 static void
-ide_build_log_panel_clear_activate (GSimpleAction *action,
-                                    GVariant      *param,
-                                    gpointer       user_data)
+gbp_buildui_log_pane_clear_activate (GSimpleAction *action,
+                                     GVariant      *param,
+                                     gpointer       user_data)
 {
-  IdeBuildLogPanel *self = user_data;
+  GbpBuilduiLogPane *self = user_data;
 
   g_assert (G_IS_SIMPLE_ACTION (action));
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
 
-  ide_build_log_panel_reset_view (self);
+  gbp_buildui_log_pane_reset_view (self);
 }
 
 static void
-ide_build_log_panel_save_in_file (GSimpleAction *action,
-                                  GVariant      *param,
-                                  gpointer       user_data)
+gbp_buildui_log_pane_save_in_file (GSimpleAction *action,
+                                   GVariant      *param,
+                                   gpointer       user_data)
 {
-  IdeBuildLogPanel *self = user_data;
+  GbpBuilduiLogPane *self = user_data;
   g_autoptr(GtkFileChooserNative) native = NULL;
   GtkWidget *window;
   gint res;
@@ -268,7 +267,7 @@ ide_build_log_panel_save_in_file (GSimpleAction *action,
   IDE_ENTRY;
 
   g_assert (G_IS_SIMPLE_ACTION (action));
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
 
   window = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_WINDOW);
   native = gtk_file_chooser_native_new (_("Save File"),
@@ -316,15 +315,15 @@ ide_build_log_panel_save_in_file (GSimpleAction *action,
 }
 
 static void
-terminal_size_allocate (IdeBuildLogPanel *self,
-                        GtkAllocation    *allocation,
-                        IdeTerminal      *terminal)
+terminal_size_allocate (GbpBuilduiLogPane *self,
+                        GtkAllocation     *allocation,
+                        IdeTerminal       *terminal)
 {
   VtePty *pty;
   gint rows = 0;
   gint columns = 0;
 
-  g_assert (IDE_IS_BUILD_LOG_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
   g_assert (allocation != NULL);
   g_assert (IDE_IS_TERMINAL (terminal));
 
@@ -338,16 +337,18 @@ terminal_size_allocate (IdeBuildLogPanel *self,
 }
 
 static void
-ide_build_log_panel_init (IdeBuildLogPanel *self)
+gbp_buildui_log_pane_init (GbpBuilduiLogPane *self)
 {
   g_autoptr(GSimpleActionGroup) actions = NULL;
   static const GActionEntry entries[] = {
-    { "clear", ide_build_log_panel_clear_activate },
-    { "save", ide_build_log_panel_save_in_file },
+    { "clear", gbp_buildui_log_pane_clear_activate },
+    { "save", gbp_buildui_log_pane_save_in_file },
   };
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
+  dzl_dock_widget_set_icon_name (DZL_DOCK_WIDGET (self), "builder-build-symbolic");
+
   g_signal_connect_object (self->terminal,
                            "size-allocate",
                            G_CALLBACK (terminal_size_allocate),
@@ -356,7 +357,7 @@ ide_build_log_panel_init (IdeBuildLogPanel *self)
 
   g_signal_connect_object (self->terminal,
                            "window-title-changed",
-                           G_CALLBACK (ide_build_log_panel_window_title_changed),
+                           G_CALLBACK (gbp_buildui_log_pane_window_title_changed),
                            self,
                            G_CONNECT_SWAPPED);
 
@@ -369,7 +370,7 @@ ide_build_log_panel_init (IdeBuildLogPanel *self)
 
   dzl_dock_widget_set_title (DZL_DOCK_WIDGET (self), _("Build Output"));
 
-  ide_build_log_panel_reset_view (self);
+  gbp_buildui_log_pane_reset_view (self);
 
   actions = g_simple_action_group_new ();
   g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), self);
diff --git a/src/libide/buildui/ide-build-panel.h b/src/plugins/buildui/gbp-buildui-log-pane.h
similarity index 67%
rename from src/libide/buildui/ide-build-panel.h
rename to src/plugins/buildui/gbp-buildui-log-pane.h
index 9f459b926..31f1ff628 100644
--- a/src/libide/buildui/ide-build-panel.h
+++ b/src/plugins/buildui/gbp-buildui-log-pane.h
@@ -1,4 +1,4 @@
-/* ide-build-panel.h
+/* gbp-buildui-log-pane.h
  *
  * Copyright 2015-2019 Christian Hergert <chergert redhat com>
  *
@@ -20,16 +20,17 @@
 
 #pragma once
 
-#include <gtk/gtk.h>
-#include <ide.h>
+#include <dazzle.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_BUILD_PANEL (ide_build_panel_get_type())
+#define GBP_TYPE_BUILDUI_LOG_PANE (gbp_buildui_log_pane_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeBuildPanel, ide_build_panel, IDE, BUILD_PANEL, DzlDockWidget)
+G_DECLARE_FINAL_TYPE (GbpBuilduiLogPane, gbp_buildui_log_pane, GBP, BUILDUI_LOG_PANE, IdePane)
 
-void ide_build_panel_set_pipeline (IdeBuildPanel    *self,
-                                   IdeBuildPipeline *pipeline);
+void gbp_buildui_log_pane_set_pipeline (GbpBuilduiLogPane *self,
+                                        IdeBuildPipeline  *pipeline);
 
 G_END_DECLS
diff --git a/src/libide/buildui/ide-build-log-panel.ui b/src/plugins/buildui/gbp-buildui-log-pane.ui
similarity index 97%
rename from src/libide/buildui/ide-build-log-panel.ui
rename to src/plugins/buildui/gbp-buildui-log-pane.ui
index 871509680..820d9ac72 100644
--- a/src/libide/buildui/ide-build-log-panel.ui
+++ b/src/plugins/buildui/gbp-buildui-log-pane.ui
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <template class="IdeBuildLogPanel" parent="DzlDockWidget">
+  <template class="GbpBuilduiLogPane" parent="IdePane">
     <child>
       <object class="GtkBox">
         <property name="orientation">horizontal</property>
diff --git a/src/plugins/buildui/gbp-buildui-omni-bar-section.c 
b/src/plugins/buildui/gbp-buildui-omni-bar-section.c
new file mode 100644
index 000000000..103816dd8
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-omni-bar-section.c
@@ -0,0 +1,367 @@
+/* gbp-buildui-omni-bar-section.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-omni-bar-section"
+
+#include "config.h"
+
+#include <dazzle.h>
+#include <glib/gi18n.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+#include <libide-vcs.h>
+
+#include "gbp-buildui-omni-bar-section.h"
+
+struct _GbpBuilduiOmniBarSection
+{
+  GtkBin          parent_instance;
+
+  DzlSignalGroup *build_manager_signals;
+
+  GtkButton      *configure_button;
+  GtkLabel       *config_ready_label;
+  GtkLabel       *popover_branch_label;
+  GtkLabel       *popover_build_message;
+  GtkLabel       *popover_build_result_label;
+  GtkLabel       *popover_config_label;
+  GtkLabel       *popover_errors_label;
+  GtkLabel       *popover_last_build_time_label;
+  GtkLabel       *popover_project_label;
+  GtkLabel       *popover_runtime_label;
+  GtkLabel       *popover_warnings_label;
+
+  GtkRevealer    *popover_details_revealer;
+};
+
+G_DEFINE_TYPE (GbpBuilduiOmniBarSection, gbp_buildui_omni_bar_section, GTK_TYPE_BIN)
+
+static void
+gbp_buildui_omni_bar_section_notify_can_build (GbpBuilduiOmniBarSection *self,
+                                               GParamSpec               *pspec,
+                                               IdeBuildManager          *build_manager)
+{
+  gboolean can_build;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  can_build = ide_build_manager_get_can_build (build_manager);
+
+  gtk_widget_set_visible (GTK_WIDGET (self->config_ready_label), !can_build);
+}
+
+static void
+gbp_buildui_omni_bar_section_notify_pipeline (GbpBuilduiOmniBarSection *self,
+                                              GParamSpec               *pspec,
+                                              IdeBuildManager          *build_manager)
+{
+  IdeBuildPipeline *pipeline;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  if ((pipeline = ide_build_manager_get_pipeline (build_manager)))
+    {
+      IdeConfiguration *config = ide_build_pipeline_get_configuration (pipeline);
+      const gchar *config_id = ide_configuration_get_id (config);
+      const gchar *display_name = ide_configuration_get_display_name (config);
+      IdeRuntime *runtime = ide_configuration_get_runtime (config);
+      const gchar *name = NULL;
+
+      gtk_label_set_label (self->popover_config_label, display_name);
+
+      if (runtime != NULL)
+        name = ide_runtime_get_display_name (runtime);
+
+      if (name == NULL)
+        name = ide_runtime_get_id (runtime);
+
+      gtk_label_set_label (self->popover_runtime_label, name);
+
+      gtk_actionable_set_action_target (GTK_ACTIONABLE (self->configure_button), "s", config_id);
+    }
+}
+
+static void
+gbp_buildui_omni_bar_section_notify_error_count (GbpBuilduiOmniBarSection *self,
+                                                 GParamSpec               *pspec,
+                                                 IdeBuildManager          *build_manager)
+{
+  gchar str[12];
+  guint count;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  count = ide_build_manager_get_error_count (build_manager);
+  g_snprintf (str, sizeof str, "%u", count);
+  gtk_label_set_label (self->popover_errors_label, str);
+}
+
+static void
+gbp_buildui_omni_bar_section_notify_warning_count (GbpBuilduiOmniBarSection *self,
+                                                   GParamSpec               *pspec,
+                                                   IdeBuildManager          *build_manager)
+{
+  gchar str[12];
+  guint count;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  count = ide_build_manager_get_warning_count (build_manager);
+  g_snprintf (str, sizeof str, "%u", count);
+  gtk_label_set_label (self->popover_warnings_label, str);
+}
+
+static void
+gbp_buildui_omni_bar_section_notify_last_build_time (GbpBuilduiOmniBarSection *self,
+                                                     GParamSpec               *pspec,
+                                                     IdeBuildManager          *build_manager)
+{
+  g_autofree gchar *formatted = NULL;
+  GDateTime *last_build_time;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  if ((last_build_time = ide_build_manager_get_last_build_time (build_manager)))
+    formatted = g_date_time_format (last_build_time, "%X");
+
+  gtk_label_set_label (self->popover_last_build_time_label, formatted);
+}
+
+static void
+gbp_buildui_omni_bar_section_notify_message (GbpBuilduiOmniBarSection *self,
+                                             GParamSpec               *pspec,
+                                             IdeBuildManager          *build_manager)
+{
+  g_autofree gchar *message = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  message = ide_build_manager_get_message (build_manager);
+
+  gtk_label_set_label (self->popover_build_message, message);
+}
+
+static void
+gbp_buildui_omni_bar_section_build_started (GbpBuilduiOmniBarSection *self,
+                                            IdeBuildPipeline         *pipeline,
+                                            IdeBuildManager          *build_manager)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  gtk_revealer_set_reveal_child (self->popover_details_revealer, TRUE);
+
+  gtk_label_set_label (self->popover_build_result_label, _("Building…"));
+  dzl_gtk_widget_remove_style_class (GTK_WIDGET (self->popover_build_result_label), "error");
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_omni_bar_section_build_failed (GbpBuilduiOmniBarSection *self,
+                                           IdeBuildPipeline         *pipeline,
+                                           IdeBuildManager          *build_manager)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  gtk_label_set_label (self->popover_build_result_label, _("Failed"));
+  dzl_gtk_widget_add_style_class (GTK_WIDGET (self->popover_build_result_label), "error");
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_omni_bar_section_build_finished (GbpBuilduiOmniBarSection *self,
+                                             IdeBuildPipeline         *pipeline,
+                                             IdeBuildManager          *build_manager)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  gtk_label_set_label (self->popover_build_result_label, _("Success"));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_omni_bar_section_bind_build_manager (GbpBuilduiOmniBarSection *self,
+                                                 IdeBuildManager          *build_manager,
+                                                 DzlSignalGroup           *signals)
+{
+  IdeContext *context;
+  IdeVcs *vcs;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+  g_assert (DZL_IS_SIGNAL_GROUP (signals));
+
+  gbp_buildui_omni_bar_section_notify_can_build (self, NULL, build_manager);
+  gbp_buildui_omni_bar_section_notify_pipeline (self, NULL, build_manager);
+  gbp_buildui_omni_bar_section_notify_message (self, NULL, build_manager);
+  gbp_buildui_omni_bar_section_notify_error_count (self, NULL, build_manager);
+  gbp_buildui_omni_bar_section_notify_warning_count (self, NULL, build_manager);
+  gbp_buildui_omni_bar_section_notify_last_build_time (self, NULL, build_manager);
+
+  context = ide_widget_get_context (GTK_WIDGET (self));
+  vcs = ide_vcs_from_context (context);
+
+  g_object_bind_property (context, "title",
+                          self->popover_project_label, "label",
+                          G_BINDING_SYNC_CREATE);
+
+  g_object_bind_property (vcs, "branch-name",
+                          self->popover_branch_label, "label",
+                          G_BINDING_SYNC_CREATE);
+}
+
+static void
+gbp_buildui_omni_bar_section_destroy (GtkWidget *widget)
+{
+  GbpBuilduiOmniBarSection *self = (GbpBuilduiOmniBarSection *)widget;
+
+  g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+
+  if (self->build_manager_signals)
+    {
+      dzl_signal_group_set_target (self->build_manager_signals, NULL);
+      g_clear_object (&self->build_manager_signals);
+    }
+
+  GTK_WIDGET_CLASS (gbp_buildui_omni_bar_section_parent_class)->destroy (widget);
+}
+
+static void
+gbp_buildui_omni_bar_section_class_init (GbpBuilduiOmniBarSectionClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  widget_class->destroy = gbp_buildui_omni_bar_section_destroy;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/buildui/gbp-buildui-omni-bar-section.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, config_ready_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, configure_button);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_branch_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_build_message);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_build_result_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_config_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_details_revealer);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_errors_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, 
popover_last_build_time_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_project_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_runtime_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_warnings_label);
+}
+
+static void
+gbp_buildui_omni_bar_section_init (GbpBuilduiOmniBarSection *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  self->build_manager_signals = dzl_signal_group_new (IDE_TYPE_BUILD_MANAGER);
+  g_signal_connect_object (self->build_manager_signals,
+                           "bind",
+                           G_CALLBACK (gbp_buildui_omni_bar_section_bind_build_manager),
+                           self,
+                           G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::can-build",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_notify_can_build),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::message",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_notify_message),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::pipeline",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_notify_pipeline),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::error-count",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_notify_error_count),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::warning-count",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_notify_warning_count),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::last-build-time",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_notify_last_build_time),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "build-started",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_build_started),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "build-failed",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_build_failed),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "build-finished",
+                                   G_CALLBACK (gbp_buildui_omni_bar_section_build_finished),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+}
+
+void
+gbp_buildui_omni_bar_section_set_context (GbpBuilduiOmniBarSection *self,
+                                          IdeContext               *context)
+{
+  IdeBuildManager *build_manager;
+
+  g_return_if_fail (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
+  g_return_if_fail (IDE_IS_CONTEXT (context));
+
+  build_manager = ide_build_manager_from_context (context);
+  dzl_signal_group_set_target (self->build_manager_signals, build_manager);
+}
diff --git a/src/plugins/buildui/gbp-buildui-omni-bar-section.h 
b/src/plugins/buildui/gbp-buildui-omni-bar-section.h
new file mode 100644
index 000000000..a064b44f3
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-omni-bar-section.h
@@ -0,0 +1,35 @@
+/* gbp-buildui-omni-bar-section.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_OMNI_BAR_SECTION (gbp_buildui_omni_bar_section_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpBuilduiOmniBarSection, gbp_buildui_omni_bar_section, GBP, BUILDUI_OMNI_BAR_SECTION, 
GtkBin)
+
+void gbp_buildui_omni_bar_section_set_context (GbpBuilduiOmniBarSection *self,
+                                               IdeContext               *context);
+
+G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-omni-bar-section.ui 
b/src/plugins/buildui/gbp-buildui-omni-bar-section.ui
new file mode 100644
index 000000000..c45c23241
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-omni-bar-section.ui
@@ -0,0 +1,530 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.0 -->
+<interface>
+  <requires lib="gtk+" version="3.12"/>
+  <template class="GbpBuilduiOmniBarSection" parent="GtkBin">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_start">24</property>
+            <property name="margin_end">24</property>
+            <property name="margin_top">24</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="spacing">12</property>
+                <child>
+                  <object class="GtkLabel" id="popover_project_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="valign">baseline</property>
+                    <property name="hexpand">True</property>
+                    <property name="xalign">0</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Update project dependencies</property>
+                    <property name="valign">baseline</property>
+                    <property name="action_name">win.update-dependencies</property>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="icon_name">software-update-available-symbolic</property>
+                      </object>
+                    </child>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="configure_button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="focus_on_click">False</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Configure build preferences</property>
+                    <property name="valign">baseline</property>
+                    <property name="action_name">win.edit-config</property>
+                    <property name="action_target">''</property>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="icon_name">builder-build-configure-symbolic</property>
+                      </object>
+                    </child>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkGrid">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="row_spacing">6</property>
+                <property name="column_spacing">18</property>
+                <child>
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Branch</property>
+                    <property name="xalign">1</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="popover_branch_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="build_profile_title">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Build Profile</property>
+                    <property name="xalign">1</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="popover_config_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="runtime_title">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Runtime</property>
+                    <property name="xalign">1</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="popover_runtime_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="use_markup">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="config_ready_label">
+            <property name="can_focus">False</property>
+            <property name="margin_top">12</property>
+            <property name="label" translatable="yes">There is a problem with the current build 
configuration.</property>
+            <property name="xalign">0.5</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+            <style>
+              <class name="warning"/>
+            </style>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkRevealer" id="popover_details_revealer">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">24</property>
+                <property name="margin_end">24</property>
+                <property name="margin_top">24</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="valign">baseline</property>
+                        <property name="label" translatable="yes">Build status</property>
+                        <property name="xalign">0</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="popover_build_message">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="valign">baseline</property>
+                        <property name="hexpand">True</property>
+                        <property name="ellipsize">end</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="focus_on_click">False</property>
+                        <property name="receives_default">False</property>
+                        <property name="tooltip_text" translatable="yes">View build console 
contents</property>
+                        <property name="halign">end</property>
+                        <property name="valign">baseline</property>
+                        <property name="action_name">win.view-output</property>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">utilities-terminal-symbolic</property>
+                          </object>
+                        </child>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkGrid" id="build_status_grid">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">6</property>
+                    <property name="column_spacing">18</property>
+                    <child>
+                      <object class="GtkLabel" id="last_build_title">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">False</property>
+                        <property name="label" translatable="yes">Last build</property>
+                        <property name="xalign">1</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="popover_last_build_time_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="width_chars">10</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="build_result_title">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">False</property>
+                        <property name="label" translatable="yes">Build result</property>
+                        <property name="xalign">1</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="popover_build_result_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="width_chars">10</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="error_title">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">False</property>
+                        <property name="label" translatable="yes">Errors</property>
+                        <property name="xalign">1</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="popover_errors_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="label">0</property>
+                        <property name="width_chars">10</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="warning_title">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">False</property>
+                        <property name="label" translatable="yes">Warnings</property>
+                        <property name="xalign">1</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="popover_warnings_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="label">0</property>
+                        <property name="width_chars">10</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_start">24</property>
+            <property name="margin_end">24</property>
+            <property name="margin_top">24</property>
+            <property name="spacing">6</property>
+            <!-- translators: valid values are 'true' or 'false', untranslated. If the buttons in the build 
popover are too large because of translations, set to false to disable homogeneous sizing -->
+            <property name="homogeneous">true</property>
+            <child>
+              <object class="GtkButton">
+                <property name="label" translatable="yes">Build</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="action_name">build-manager.build</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton">
+                <property name="label" translatable="yes">Rebuild</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="action_name">build-manager.rebuild</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton">
+                <property name="label" translatable="yes">Clean</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="action_name">build-manager.clean</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton">
+                <property name="label" translatable="yes">Export Bundle</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="action_name">build-manager.export</property>
+                <style>
+                  <class name="suggested-action"/>
+                </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <style>
+          <class name="popover-content-area"/>
+        </style>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/libide/buildui/ide-build-panel.c b/src/plugins/buildui/gbp-buildui-pane.c
similarity index 65%
rename from src/libide/buildui/ide-build-panel.c
rename to src/plugins/buildui/gbp-buildui-pane.c
index d24806759..f2d43a880 100644
--- a/src/libide/buildui/ide-build-panel.c
+++ b/src/plugins/buildui/gbp-buildui-pane.c
@@ -1,4 +1,4 @@
-/* ide-build-panel.c
+/* gbp-buildui-pane.c
  *
  * Copyright 2015-2019 Christian Hergert <chergert redhat com>
  *
@@ -18,22 +18,22 @@
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
-#define G_LOG_DOMAIN "ide-build-panel"
+#define G_LOG_DOMAIN "gbp-buildui-pane"
 
 #include "config.h"
 
 #include <glib/gi18n.h>
-#include <ide.h>
+#include <libide-editor.h>
+#include <libide-foundry.h>
 
-#include "buildsystem/ide-build-stage-private.h"
-#include "buildui/ide-build-panel.h"
-#include "buildui/ide-build-stage-row.h"
-#include "util/ide-fancy-tree-view.h"
-#include "util/ide-cell-renderer-fancy.h"
+#include "ide-build-stage-private.h"
 
-struct _IdeBuildPanel
+#include "gbp-buildui-pane.h"
+#include "gbp-buildui-stage-row.h"
+
+struct _GbpBuilduiPane
 {
-  DzlDockWidget        parent_instance;
+  IdePane              parent_instance;
 
   /* Owned references */
   GHashTable          *diags_hash;
@@ -55,7 +55,7 @@ struct _IdeBuildPanel
   guint                warning_count;
 };
 
-G_DEFINE_TYPE (IdeBuildPanel, ide_build_panel, DZL_TYPE_DOCK_WIDGET)
+G_DEFINE_TYPE (GbpBuilduiPane, gbp_buildui_pane, IDE_TYPE_PANE)
 
 enum {
   COLUMN_DIAGNOSTIC,
@@ -71,7 +71,7 @@ enum {
 static GParamSpec *properties [N_PROPS];
 
 static void
-set_warnings_label (IdeBuildPanel *self,
+set_warnings_label (GbpBuilduiPane *self,
                     const gchar   *label)
 {
   gtk_container_child_set (GTK_CONTAINER (self->notebook), GTK_WIDGET (self->warnings_page),
@@ -80,7 +80,7 @@ set_warnings_label (IdeBuildPanel *self,
 }
 
 static void
-set_errors_label (IdeBuildPanel *self,
+set_errors_label (GbpBuilduiPane *self,
                   const gchar   *label)
 {
   gtk_container_child_set (GTK_CONTAINER (self->notebook), GTK_WIDGET (self->errors_page),
@@ -89,16 +89,16 @@ set_errors_label (IdeBuildPanel *self,
 }
 
 static void
-ide_build_panel_diagnostic (IdeBuildPanel    *self,
-                            IdeDiagnostic    *diagnostic,
-                            IdeBuildPipeline *pipeline)
+gbp_buildui_pane_diagnostic (GbpBuilduiPane   *self,
+                             IdeDiagnostic    *diagnostic,
+                             IdeBuildPipeline *pipeline)
 {
   IdeDiagnosticSeverity severity;
   guint hash;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (diagnostic != NULL);
   g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
@@ -148,11 +148,11 @@ ide_build_panel_diagnostic (IdeBuildPanel    *self,
 }
 
 static void
-ide_build_panel_update_running_time (IdeBuildPanel *self)
+gbp_buildui_pane_update_running_time (GbpBuilduiPane *self)
 {
   g_autofree gchar *text = NULL;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
 
   if (self->pipeline != NULL)
     {
@@ -161,7 +161,7 @@ ide_build_panel_update_running_time (IdeBuildPanel *self)
       GTimeSpan span;
 
       context = ide_widget_get_context (GTK_WIDGET (self));
-      build_manager = ide_context_get_build_manager (context);
+      build_manager = ide_build_manager_from_context (context);
 
       span = ide_build_manager_get_running_time (build_manager);
       text = dzl_g_time_span_to_label (span);
@@ -172,13 +172,13 @@ ide_build_panel_update_running_time (IdeBuildPanel *self)
 }
 
 static void
-ide_build_panel_started (IdeBuildPanel    *self,
-                         IdeBuildPhase     phase,
-                         IdeBuildPipeline *pipeline)
+gbp_buildui_pane_started (GbpBuilduiPane   *self,
+                          IdeBuildPhase     phase,
+                          IdeBuildPipeline *pipeline)
 {
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
   if (phase >= IDE_BUILD_PHASE_BUILD)
@@ -197,23 +197,23 @@ ide_build_panel_started (IdeBuildPanel    *self,
 }
 
 static GtkWidget *
-ide_build_panel_create_stage_row_cb (gpointer data,
+gbp_buildui_pane_create_stage_row_cb (gpointer data,
                                      gpointer user_data)
 {
   IdeBuildStage *stage = data;
 
   g_assert (IDE_IS_BUILD_STAGE (stage));
-  g_assert (IDE_IS_BUILD_PANEL (user_data));
+  g_assert (GBP_IS_BUILDUI_PANE (user_data));
 
-  return ide_build_stage_row_new (stage);
+  return gbp_buildui_stage_row_new (stage);
 }
 
 static void
-ide_build_panel_bind_pipeline (IdeBuildPanel    *self,
-                               IdeBuildPipeline *pipeline,
-                               DzlSignalGroup   *signals)
+gbp_buildui_pane_bind_pipeline (GbpBuilduiPane   *self,
+                                IdeBuildPipeline *pipeline,
+                                DzlSignalGroup   *signals)
 {
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
   g_assert (G_IS_LIST_MODEL (pipeline));
   g_assert (self->pipeline == NULL);
@@ -231,17 +231,17 @@ ide_build_panel_bind_pipeline (IdeBuildPanel    *self,
 
   gtk_list_box_bind_model (self->stages_list_box,
                            G_LIST_MODEL (pipeline),
-                           ide_build_panel_create_stage_row_cb,
+                           gbp_buildui_pane_create_stage_row_cb,
                            self, NULL);
 
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PIPELINE]);
 }
 
 static void
-ide_build_panel_unbind_pipeline (IdeBuildPanel  *self,
-                                 DzlSignalGroup *signals)
+gbp_buildui_pane_unbind_pipeline (GbpBuilduiPane *self,
+                                  DzlSignalGroup *signals)
 {
-  g_return_if_fail (IDE_IS_BUILD_PANEL (self));
+  g_return_if_fail (GBP_IS_BUILDUI_PANE (self));
   g_return_if_fail (!self->pipeline || IDE_IS_BUILD_PIPELINE (self->pipeline));
 
   g_clear_object (&self->pipeline);
@@ -258,10 +258,10 @@ ide_build_panel_unbind_pipeline (IdeBuildPanel  *self,
 }
 
 void
-ide_build_panel_set_pipeline (IdeBuildPanel    *self,
-                              IdeBuildPipeline *pipeline)
+gbp_buildui_pane_set_pipeline (GbpBuilduiPane   *self,
+                               IdeBuildPipeline *pipeline)
 {
-  g_return_if_fail (IDE_IS_BUILD_PANEL (self));
+  g_return_if_fail (GBP_IS_BUILDUI_PANE (self));
   g_return_if_fail (!pipeline || IDE_IS_BUILD_PIPELINE (pipeline));
 
   if (self->pipeline_signals != NULL)
@@ -269,21 +269,21 @@ ide_build_panel_set_pipeline (IdeBuildPanel    *self,
 }
 
 static void
-ide_build_panel_diagnostic_activated (IdeBuildPanel     *self,
-                                      GtkTreePath       *path,
-                                      GtkTreeViewColumn *colun,
-                                      GtkTreeView       *tree_view)
+gbp_buildui_pane_diagnostic_activated (GbpBuilduiPane    *self,
+                                       GtkTreePath       *path,
+                                       GtkTreeViewColumn *colun,
+                                       GtkTreeView       *tree_view)
 {
   g_autoptr(IdeDiagnostic) diagnostic = NULL;
-  g_autoptr(IdeUri) uri = NULL;
-  IdeSourceLocation *loc;
-  IdeWorkbench *workbench;
+  IdeWorkspace *workspace;
+  IdeLocation *loc;
   GtkTreeModel *model;
+  IdeSurface *surface;
   GtkTreeIter iter;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (path != NULL);
   g_assert (GTK_IS_TREE_VIEW_COLUMN (colun));
   g_assert (GTK_IS_TREE_VIEW (tree_view));
@@ -296,28 +296,22 @@ ide_build_panel_diagnostic_activated (IdeBuildPanel     *self,
                       COLUMN_DIAGNOSTIC, &diagnostic,
                       -1);
 
-  if (diagnostic == NULL ||
-      NULL == (loc = ide_diagnostic_get_location (diagnostic)) ||
-      NULL == (uri = ide_source_location_get_uri (loc)))
+  if (diagnostic == NULL || !(loc = ide_diagnostic_get_location (diagnostic)))
     IDE_EXIT;
 
-  workbench = ide_widget_get_workbench (GTK_WIDGET (self));
-
-  ide_workbench_open_uri_async (workbench,
-                                uri,
-                                "editor",
-                                IDE_WORKBENCH_OPEN_FLAGS_NONE,
-                                NULL, NULL, NULL);
+  workspace = ide_widget_get_workspace (GTK_WIDGET (self));
+  surface = ide_workspace_get_surface_by_name (workspace, "editor");
+  ide_editor_surface_focus_location (IDE_EDITOR_SURFACE (surface), loc);
 
   IDE_EXIT;
 }
 
 static void
-ide_build_panel_text_func (GtkCellLayout   *layout,
-                           GtkCellRenderer *renderer,
-                           GtkTreeModel    *model,
-                           GtkTreeIter     *iter,
-                           gpointer         user_data)
+gbp_buildui_pane_text_func (GtkCellLayout   *layout,
+                            GtkCellRenderer *renderer,
+                            GtkTreeModel    *model,
+                            GtkTreeIter     *iter,
+                            gpointer         user_data)
 {
   IdeCellRendererFancy *fancy = (IdeCellRendererFancy *)renderer;
   g_autoptr(IdeDiagnostic) diagnostic = NULL;
@@ -330,9 +324,9 @@ ide_build_panel_text_func (GtkCellLayout   *layout,
     {
       g_autofree gchar *title = NULL;
       g_autofree gchar *name = NULL;
-      IdeSourceLocation *location;
+      IdeLocation *location;
       const gchar *text;
-      GFile *gfile = NULL;
+      GFile *file = NULL;
       guint line = 0;
       guint column = 0;
 
@@ -340,18 +334,12 @@ ide_build_panel_text_func (GtkCellLayout   *layout,
 
       if (location != NULL)
         {
-          IdeFile *file;
-
-          if (NULL != (file = ide_source_location_get_file (location)))
+          if ((file = ide_location_get_file (location)))
             {
-              if (NULL != (gfile = ide_file_get_file (file)))
-                {
-                  name = g_file_get_basename (gfile);
-                  line = ide_source_location_get_line (location);
-                  column = ide_source_location_get_line_offset (location);
-                }
+              name = g_file_get_basename (file);
+              line = ide_location_get_line (location);
+              column = ide_location_get_line_offset (location);
             }
-
         }
 
       title = g_strdup_printf ("%s:%u:%u", name ?: "", line + 1, column + 1);
@@ -368,15 +356,15 @@ ide_build_panel_text_func (GtkCellLayout   *layout,
 }
 
 static void
-ide_build_panel_notify_message (IdeBuildPanel   *self,
-                                GParamSpec      *pspec,
-                                IdeBuildManager *build_manager)
+gbp_buildui_pane_notify_message (GbpBuilduiPane  *self,
+                                 GParamSpec      *pspec,
+                                 IdeBuildManager *build_manager)
 {
   g_autofree gchar *message = NULL;
   IdeBuildPipeline *pipeline;
   GtkStyleContext *style;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
 
   message = ide_build_manager_get_message (build_manager);
@@ -393,49 +381,49 @@ ide_build_panel_notify_message (IdeBuildPanel   *self,
 }
 
 static void
-ide_build_panel_context_handler (GtkWidget  *widget,
-                                 IdeContext *context)
+gbp_buildui_pane_context_handler (GtkWidget  *widget,
+                                  IdeContext *context)
 {
-  IdeBuildPanel *self = (IdeBuildPanel *)widget;
+  GbpBuilduiPane *self = (GbpBuilduiPane *)widget;
   IdeBuildManager *build_manager;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (!context || IDE_IS_CONTEXT (context));
 
   if (context == NULL)
     IDE_EXIT;
 
-  build_manager = ide_context_get_build_manager (context);
+  build_manager = ide_build_manager_from_context (context);
 
   g_signal_connect_object (build_manager,
                            "notify::message",
-                           G_CALLBACK (ide_build_panel_notify_message),
+                           G_CALLBACK (gbp_buildui_pane_notify_message),
                            self,
                            G_CONNECT_SWAPPED);
 
   g_signal_connect_object (build_manager,
                            "notify::running-time",
-                           G_CALLBACK (ide_build_panel_update_running_time),
+                           G_CALLBACK (gbp_buildui_pane_update_running_time),
                            self,
                            G_CONNECT_SWAPPED);
 
   g_signal_connect_object (build_manager,
                            "build-started",
-                           G_CALLBACK (ide_build_panel_update_running_time),
+                           G_CALLBACK (gbp_buildui_pane_update_running_time),
                            self,
                            G_CONNECT_SWAPPED);
 
   g_signal_connect_object (build_manager,
                            "build-finished",
-                           G_CALLBACK (ide_build_panel_update_running_time),
+                           G_CALLBACK (gbp_buildui_pane_update_running_time),
                            self,
                            G_CONNECT_SWAPPED);
 
   g_signal_connect_object (build_manager,
                            "build-failed",
-                           G_CALLBACK (ide_build_panel_update_running_time),
+                           G_CALLBACK (gbp_buildui_pane_update_running_time),
                            self,
                            G_CONNECT_SWAPPED);
 
@@ -443,17 +431,17 @@ ide_build_panel_context_handler (GtkWidget  *widget,
 }
 
 static gboolean
-ide_build_panel_diagnostic_tooltip (IdeBuildPanel *self,
-                                    gint           x,
-                                    gint           y,
-                                    gboolean       keyboard_mode,
-                                    GtkTooltip    *tooltip,
-                                    GtkTreeView   *tree_view)
+gbp_buildui_pane_diagnostic_tooltip (GbpBuilduiPane *self,
+                                     gint            x,
+                                     gint            y,
+                                     gboolean        keyboard_mode,
+                                     GtkTooltip     *tooltip,
+                                     GtkTreeView    *tree_view)
 {
   GtkTreeModel *model = NULL;
   GtkTreeIter iter;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (GTK_IS_TOOLTIP (tooltip));
   g_assert (GTK_IS_TREE_VIEW (tree_view));
 
@@ -515,21 +503,21 @@ diagnostic_is_error (GtkTreeModel *model,
 }
 
 static void
-ide_build_panel_stage_row_activated (IdeBuildPanel    *self,
-                                     IdeBuildStageRow *row,
-                                     GtkListBox       *list_box)
+gbp_buildui_pane_stage_row_activated (GbpBuilduiPane     *self,
+                                      GbpBuilduiStageRow *row,
+                                      GtkListBox         *list_box)
 {
   IdeBuildStage *stage;
   IdeBuildPhase phase;
 
-  g_assert (IDE_IS_BUILD_PANEL (self));
-  g_assert (IDE_IS_BUILD_STAGE_ROW (row));
+  g_assert (GBP_IS_BUILDUI_PANE (self));
+  g_assert (GBP_IS_BUILDUI_STAGE_ROW (row));
   g_assert (GTK_IS_LIST_BOX (list_box));
 
   if (self->pipeline == NULL)
     return;
 
-  stage = ide_build_stage_row_get_stage (row);
+  stage = gbp_buildui_stage_row_get_stage (row);
   g_assert (IDE_IS_BUILD_STAGE (stage));
 
   phase = _ide_build_stage_get_phase (stage);
@@ -540,9 +528,9 @@ ide_build_panel_stage_row_activated (IdeBuildPanel    *self,
 }
 
 static void
-ide_build_panel_destroy (GtkWidget *widget)
+gbp_buildui_pane_destroy (GtkWidget *widget)
 {
-  IdeBuildPanel *self = (IdeBuildPanel *)widget;
+  GbpBuilduiPane *self = (GbpBuilduiPane *)widget;
 
   if (self->pipeline_signals != NULL)
     dzl_signal_group_set_target (self->pipeline_signals, NULL);
@@ -552,16 +540,16 @@ ide_build_panel_destroy (GtkWidget *widget)
   g_clear_object (&self->pipeline_signals);
   g_clear_object (&self->pipeline);
 
-  GTK_WIDGET_CLASS (ide_build_panel_parent_class)->destroy (widget);
+  GTK_WIDGET_CLASS (gbp_buildui_pane_parent_class)->destroy (widget);
 }
 
 static void
-ide_build_panel_get_property (GObject    *object,
-                              guint       prop_id,
-                              GValue     *value,
-                              GParamSpec *pspec)
+gbp_buildui_pane_get_property (GObject    *object,
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
 {
-  IdeBuildPanel *self = IDE_BUILD_PANEL (object);
+  GbpBuilduiPane *self = GBP_BUILDUI_PANE (object);
 
   switch (prop_id)
     {
@@ -575,17 +563,17 @@ ide_build_panel_get_property (GObject    *object,
 }
 
 static void
-ide_build_panel_set_property (GObject      *object,
-                              guint         prop_id,
-                              const GValue *value,
-                              GParamSpec   *pspec)
+gbp_buildui_pane_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
 {
-  IdeBuildPanel *self = IDE_BUILD_PANEL (object);
+  GbpBuilduiPane *self = GBP_BUILDUI_PANE (object);
 
   switch (prop_id)
     {
     case PROP_PIPELINE:
-      ide_build_panel_set_pipeline (self, g_value_get_object (value));
+      gbp_buildui_pane_set_pipeline (self, g_value_get_object (value));
       break;
 
     default:
@@ -594,15 +582,15 @@ ide_build_panel_set_property (GObject      *object,
 }
 
 static void
-ide_build_panel_class_init (IdeBuildPanelClass *klass)
+gbp_buildui_pane_class_init (GbpBuilduiPaneClass *klass)
 {
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  widget_class->destroy = ide_build_panel_destroy;
+  widget_class->destroy = gbp_buildui_pane_destroy;
 
-  object_class->get_property = ide_build_panel_get_property;
-  object_class->set_property = ide_build_panel_set_property;
+  object_class->get_property = gbp_buildui_pane_get_property;
+  object_class->set_property = gbp_buildui_pane_set_property;
 
   properties [PROP_PIPELINE] =
     g_param_spec_object ("pipeline",
@@ -613,18 +601,17 @@ ide_build_panel_class_init (IdeBuildPanelClass *klass)
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
-  gtk_widget_class_set_template_from_resource (widget_class,
-                                               "/org/gnome/builder/plugins/buildui/ide-build-panel.ui");
+  gtk_widget_class_set_template_from_resource (widget_class, "/plugins/buildui/gbp-buildui-pane.ui");
   gtk_widget_class_set_css_name (widget_class, "buildpanel");
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, build_status_label);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, time_completed_label);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, notebook);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, errors_page);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, errors_tree_view);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, warnings_page);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, warnings_tree_view);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, diagnostics_store);
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildPanel, stages_list_box);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, build_status_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, time_completed_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, notebook);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, errors_page);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, errors_tree_view);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, warnings_page);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, warnings_tree_view);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, diagnostics_store);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, stages_list_box);
 
   g_type_ensure (IDE_TYPE_CELL_RENDERER_FANCY);
   g_type_ensure (IDE_TYPE_DIAGNOSTIC);
@@ -632,7 +619,7 @@ ide_build_panel_class_init (IdeBuildPanelClass *klass)
 }
 
 static void
-ide_build_panel_init (IdeBuildPanel *self)
+gbp_buildui_pane_init (GbpBuilduiPane *self)
 {
   GtkTreeModel *filter;
 
@@ -642,25 +629,25 @@ ide_build_panel_init (IdeBuildPanel *self)
 
   g_signal_connect_object (self->pipeline_signals,
                            "bind",
-                           G_CALLBACK (ide_build_panel_bind_pipeline),
+                           G_CALLBACK (gbp_buildui_pane_bind_pipeline),
                            self,
                            G_CONNECT_SWAPPED);
 
   g_signal_connect_object (self->pipeline_signals,
                            "unbind",
-                           G_CALLBACK (ide_build_panel_unbind_pipeline),
+                           G_CALLBACK (gbp_buildui_pane_unbind_pipeline),
                            self,
                            G_CONNECT_SWAPPED);
 
   dzl_signal_group_connect_object (self->pipeline_signals,
                                    "diagnostic",
-                                   G_CALLBACK (ide_build_panel_diagnostic),
+                                   G_CALLBACK (gbp_buildui_pane_diagnostic),
                                    self,
                                    G_CONNECT_SWAPPED);
 
   dzl_signal_group_connect_object (self->pipeline_signals,
                                    "started",
-                                   G_CALLBACK (ide_build_panel_started),
+                                   G_CALLBACK (gbp_buildui_pane_started),
                                    self,
                                    G_CONNECT_SWAPPED);
 
@@ -668,26 +655,26 @@ ide_build_panel_init (IdeBuildPanel *self)
 
   g_object_set (self, "title", _("Build Issues"), NULL);
 
-  ide_widget_set_context_handler (self, ide_build_panel_context_handler);
+  ide_widget_set_context_handler (self, gbp_buildui_pane_context_handler);
 
   g_signal_connect_swapped (self->warnings_tree_view,
                            "row-activated",
-                           G_CALLBACK (ide_build_panel_diagnostic_activated),
+                           G_CALLBACK (gbp_buildui_pane_diagnostic_activated),
                            self);
 
   g_signal_connect_swapped (self->warnings_tree_view,
                            "query-tooltip",
-                           G_CALLBACK (ide_build_panel_diagnostic_tooltip),
+                           G_CALLBACK (gbp_buildui_pane_diagnostic_tooltip),
                            self);
 
   g_signal_connect_swapped (self->errors_tree_view,
                            "row-activated",
-                           G_CALLBACK (ide_build_panel_diagnostic_activated),
+                           G_CALLBACK (gbp_buildui_pane_diagnostic_activated),
                            self);
 
   g_signal_connect_swapped (self->errors_tree_view,
                            "query-tooltip",
-                           G_CALLBACK (ide_build_panel_diagnostic_tooltip),
+                           G_CALLBACK (gbp_buildui_pane_diagnostic_tooltip),
                            self);
 
   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (self->diagnostics_store), NULL);
@@ -703,13 +690,13 @@ ide_build_panel_init (IdeBuildPanel *self)
   g_object_unref (filter);
 
   ide_fancy_tree_view_set_data_func (IDE_FANCY_TREE_VIEW (self->warnings_tree_view),
-                                     ide_build_panel_text_func, self, NULL);
+                                     gbp_buildui_pane_text_func, self, NULL);
 
   ide_fancy_tree_view_set_data_func (IDE_FANCY_TREE_VIEW (self->errors_tree_view),
-                                     ide_build_panel_text_func, self, NULL);
+                                     gbp_buildui_pane_text_func, self, NULL);
 
   g_signal_connect_swapped (self->stages_list_box,
                             "row-activated",
-                            G_CALLBACK (ide_build_panel_stage_row_activated),
+                            G_CALLBACK (gbp_buildui_pane_stage_row_activated),
                             self);
 }
diff --git a/src/libide/buildui/ide-build-log-panel.h b/src/plugins/buildui/gbp-buildui-pane.h
similarity index 70%
rename from src/libide/buildui/ide-build-log-panel.h
rename to src/plugins/buildui/gbp-buildui-pane.h
index 49f63c685..f7c1efcc8 100644
--- a/src/libide/buildui/ide-build-log-panel.h
+++ b/src/plugins/buildui/gbp-buildui-pane.h
@@ -1,4 +1,4 @@
-/* ide-build-log-panel.h
+/* gbp-buildui-pane.h
  *
  * Copyright 2015-2019 Christian Hergert <chergert redhat com>
  *
@@ -20,15 +20,16 @@
 
 #pragma once
 
-#include <ide.h>
+#include <libide-gui.h>
+#include <libide-foundry.h>
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_BUILD_LOG_PANEL (ide_build_log_panel_get_type())
+#define GBP_TYPE_BUILDUI_PANE (gbp_buildui_pane_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeBuildLogPanel, ide_build_log_panel, IDE, BUILD_LOG_PANEL, DzlDockWidget)
+G_DECLARE_FINAL_TYPE (GbpBuilduiPane, gbp_buildui_pane, GBP, BUILDUI_PANE, IdePane)
 
-void ide_build_log_panel_set_pipeline (IdeBuildLogPanel *self,
-                                       IdeBuildPipeline *pipeline);
+void gbp_buildui_pane_set_pipeline (GbpBuilduiPane   *self,
+                                    IdeBuildPipeline *pipeline);
 
 G_END_DECLS
diff --git a/src/libide/buildui/ide-build-panel.ui b/src/plugins/buildui/gbp-buildui-pane.ui
similarity index 98%
rename from src/libide/buildui/ide-build-panel.ui
rename to src/plugins/buildui/gbp-buildui-pane.ui
index f643ebd92..8511ca473 100644
--- a/src/libide/buildui/ide-build-panel.ui
+++ b/src/plugins/buildui/gbp-buildui-pane.ui
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <template class="IdeBuildPanel" parent="DzlDockWidget">
+  <template class="GbpBuilduiPane" parent="IdePane">
     <child>
       <object class="DzlMultiPaned">
         <property name="orientation">vertical</property>
diff --git a/src/plugins/buildui/gbp-buildui-runtime-categories.c 
b/src/plugins/buildui/gbp-buildui-runtime-categories.c
new file mode 100644
index 000000000..e4a693559
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-runtime-categories.c
@@ -0,0 +1,251 @@
+/* gbp-buildui-runtime-categories.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-runtime-categories"
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gbp-buildui-runtime-categories.h"
+
+struct _GbpBuilduiRuntimeCategories
+{
+  GObject            parent_instance;
+  GPtrArray         *items;
+  gchar             *prefix;
+  gchar             *name;
+  IdeRuntimeManager *runtime_manager;
+};
+
+static gboolean
+filter_by_category (GObject *object,
+                    gpointer user_data)
+{
+  const gchar *category = user_data;
+  IdeRuntime *runtime = IDE_RUNTIME (object);
+
+  return ide_str_equal0 (category, ide_runtime_get_category (runtime));
+}
+
+static GType
+gbp_buildui_runtime_categories_get_item_type (GListModel *model)
+{
+  return G_TYPE_OBJECT;
+}
+
+static guint
+gbp_buildui_runtime_categories_get_n_items (GListModel *model)
+{
+  GbpBuilduiRuntimeCategories *self = (GbpBuilduiRuntimeCategories *)model;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (self));
+
+  return GBP_BUILDUI_RUNTIME_CATEGORIES (model)->items->len;
+}
+
+static gpointer
+gbp_buildui_runtime_categories_get_item (GListModel *model,
+                                         guint       position)
+{
+  GbpBuilduiRuntimeCategories *self = GBP_BUILDUI_RUNTIME_CATEGORIES (model);
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (self));
+
+  if (self->items->len > position)
+    {
+      const gchar *category = g_ptr_array_index (self->items, position);
+      return gbp_buildui_runtime_categories_create_child_model (self, category);
+    }
+
+  return NULL;
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+  iface->get_item_type = gbp_buildui_runtime_categories_get_item_type;
+  iface->get_n_items = gbp_buildui_runtime_categories_get_n_items;
+  iface->get_item = gbp_buildui_runtime_categories_get_item;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpBuilduiRuntimeCategories, gbp_buildui_runtime_categories, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
+
+static void
+gbp_buildui_runtime_categories_finalize (GObject *object)
+{
+  GbpBuilduiRuntimeCategories *self = (GbpBuilduiRuntimeCategories *)object;
+
+  g_clear_object (&self->runtime_manager);
+  g_clear_pointer (&self->items, g_ptr_array_unref);
+  g_clear_pointer (&self->name, g_free);
+  g_clear_pointer (&self->prefix, g_free);
+
+  G_OBJECT_CLASS (gbp_buildui_runtime_categories_parent_class)->finalize (object);
+}
+
+static void
+gbp_buildui_runtime_categories_class_init (GbpBuilduiRuntimeCategoriesClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_buildui_runtime_categories_finalize;
+}
+
+static void
+gbp_buildui_runtime_categories_init (GbpBuilduiRuntimeCategories *self)
+{
+  self->items = g_ptr_array_new_with_free_func (g_free);
+}
+
+static gint
+sort_by_name (const gchar **name_a,
+              const gchar **name_b)
+{
+  return g_strcmp0 (*name_a, *name_b);
+}
+
+static void
+on_items_changed_cb (GbpBuilduiRuntimeCategories *self,
+                     guint                        position,
+                     guint                        added,
+                     guint                        removed,
+                     IdeRuntimeManager           *runtime_manager)
+{
+  g_autoptr(GHashTable) found = NULL;
+  guint old_len;
+  guint n_items;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (self));
+  g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
+
+  old_len = self->items->len;
+
+  if (old_len > 0)
+    g_ptr_array_remove_range (self->items, 0, old_len);
+
+  found = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  n_items = g_list_model_get_n_items (G_LIST_MODEL (runtime_manager));
+
+  for (guint i = 0; i < n_items; i++)
+    {
+      g_autoptr(IdeRuntime) runtime = g_list_model_get_item (G_LIST_MODEL (runtime_manager), i);
+      g_autofree gchar *word = NULL;
+      const gchar *category = ide_runtime_get_category (runtime);
+      const gchar *next = category;
+      const gchar *slash;
+
+      if (self->prefix != NULL && !g_str_has_prefix (category, self->prefix))
+        continue;
+
+      if (self->prefix)
+        next += strlen (self->prefix);
+
+      if ((slash = strchr (next, '/')))
+        next = word = g_strndup (next, slash + 1 - next);
+
+      if (!g_hash_table_contains (found, next))
+        {
+          g_hash_table_insert (found, g_strdup (next), NULL);
+          g_ptr_array_add (self->items, g_strdup (next));
+        }
+    }
+
+  g_ptr_array_sort (self->items, (GCompareFunc)sort_by_name);
+
+  g_list_model_items_changed (G_LIST_MODEL (self), 0, old_len, self->items->len);
+}
+
+GbpBuilduiRuntimeCategories *
+gbp_buildui_runtime_categories_new (IdeRuntimeManager *runtime_manager,
+                                    const gchar       *prefix)
+{
+  GbpBuilduiRuntimeCategories *ret;
+
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (IDE_IS_RUNTIME_MANAGER (runtime_manager), NULL);
+
+  ret = g_object_new (GBP_TYPE_BUILDUI_RUNTIME_CATEGORIES, NULL);
+  ret->runtime_manager = g_object_ref (runtime_manager);
+  ret->prefix = g_strdup (prefix);
+  ret->name = prefix ? g_path_get_basename (prefix) : NULL;
+
+  g_signal_connect_object (runtime_manager,
+                           "items-changed",
+                           G_CALLBACK (on_items_changed_cb),
+                           ret,
+                           G_CONNECT_SWAPPED);
+
+  on_items_changed_cb (ret, 0, 0, 0, runtime_manager);
+
+  return g_steal_pointer (&ret);
+}
+
+const gchar *
+gbp_buildui_runtime_categories_get_name (GbpBuilduiRuntimeCategories *self)
+{
+  g_return_val_if_fail (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (self), NULL);
+
+  return self->name;
+}
+
+const gchar *
+gbp_buildui_runtime_categories_get_prefix (GbpBuilduiRuntimeCategories *self)
+{
+  g_return_val_if_fail (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (self), NULL);
+
+  return self->prefix;
+}
+
+GListModel *
+gbp_buildui_runtime_categories_create_child_model (GbpBuilduiRuntimeCategories *self,
+                                                   const gchar                 *category)
+{
+  g_autofree gchar *prefix = NULL;
+  g_autofree gchar *name = NULL;
+  DzlListModelFilter *filter;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (self));
+  g_assert (category != NULL);
+
+  if (self->prefix == NULL)
+    prefix = g_strdup (category);
+  else
+    prefix = g_strdup_printf ("%s%s", self->prefix, category);
+
+  name = g_path_get_basename (prefix);
+
+  if (g_str_has_suffix (category, "/"))
+    return G_LIST_MODEL (gbp_buildui_runtime_categories_new (self->runtime_manager, prefix));
+
+  filter = dzl_list_model_filter_new (G_LIST_MODEL (self->runtime_manager));
+  g_object_set_data_full (G_OBJECT (filter), "CATEGORY", g_steal_pointer (&name), g_free);
+  dzl_list_model_filter_set_filter_func (filter,
+                                         filter_by_category,
+                                         g_strdup (prefix),
+                                         g_free);
+
+  return G_LIST_MODEL (g_steal_pointer (&filter));
+}
diff --git a/src/plugins/buildui/gbp-buildui-runtime-categories.h 
b/src/plugins/buildui/gbp-buildui-runtime-categories.h
new file mode 100644
index 000000000..ae70b360e
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-runtime-categories.h
@@ -0,0 +1,38 @@
+/* gbp-buildui-runtime-categories.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-foundry.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_RUNTIME_CATEGORIES (gbp_buildui_runtime_categories_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpBuilduiRuntimeCategories, gbp_buildui_runtime_categories, GBP, 
BUILDUI_RUNTIME_CATEGORIES, GObject)
+
+GbpBuilduiRuntimeCategories *gbp_buildui_runtime_categories_new                (IdeRuntimeManager           
*runtime_manager,
+                                                                                const gchar                 
*prefix);
+GListModel                  *gbp_buildui_runtime_categories_create_child_model (GbpBuilduiRuntimeCategories 
*self,
+                                                                                const gchar                 
*category);
+const gchar                 *gbp_buildui_runtime_categories_get_prefix         (GbpBuilduiRuntimeCategories 
*self);
+const gchar                 *gbp_buildui_runtime_categories_get_name           (GbpBuilduiRuntimeCategories 
*self);
+
+G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-runtime-row.c b/src/plugins/buildui/gbp-buildui-runtime-row.c
new file mode 100644
index 000000000..ec7bedb4f
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-runtime-row.c
@@ -0,0 +1,137 @@
+/* gbp-buildui-runtime-row.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-runtime-row"
+
+#include "config.h"
+
+#include "gbp-buildui-runtime-row.h"
+
+struct _GbpBuilduiRuntimeRow
+{
+  GtkListBoxRow  parent_instance;
+
+  gchar         *runtime_id;
+
+  GtkLabel      *label;
+  GtkImage      *image;
+};
+
+G_DEFINE_TYPE (GbpBuilduiRuntimeRow, gbp_buildui_runtime_row, GTK_TYPE_LIST_BOX_ROW)
+
+static void
+gbp_buildui_runtime_row_finalize (GObject *object)
+{
+  GbpBuilduiRuntimeRow *self = (GbpBuilduiRuntimeRow *)object;
+
+  g_clear_pointer (&self->runtime_id, g_free);
+
+  G_OBJECT_CLASS (gbp_buildui_runtime_row_parent_class)->finalize (object);
+}
+
+static void
+gbp_buildui_runtime_row_class_init (GbpBuilduiRuntimeRowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_buildui_runtime_row_finalize;
+}
+
+static void
+gbp_buildui_runtime_row_init (GbpBuilduiRuntimeRow *self)
+{
+  GtkWidget *box;
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "margin", 10,
+                      "orientation", GTK_ORIENTATION_HORIZONTAL,
+                      "spacing", 6,
+                      "visible", TRUE,
+                      NULL);
+  gtk_container_add (GTK_CONTAINER (self), box);
+
+  self->label = g_object_new (GTK_TYPE_LABEL,
+                              "visible", TRUE,
+                              "use-markup", TRUE,
+                              "xalign", 0.0f,
+                              NULL);
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (self->label));
+
+  self->image = g_object_new (GTK_TYPE_IMAGE,
+                              "visible", TRUE,
+                              "halign", GTK_ALIGN_START,
+                              "hexpand", TRUE,
+                              "icon-name", "object-select-symbolic",
+                              NULL);
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (self->image));
+}
+
+static void
+notify_config_runtime_id (GbpBuilduiRuntimeRow *self,
+                          GParamSpec           *pspec,
+                          IdeConfiguration     *config)
+{
+  g_assert (GBP_IS_BUILDUI_RUNTIME_ROW (self));
+  g_assert (IDE_IS_CONFIGURATION (config));
+
+  gtk_widget_set_visible (GTK_WIDGET (self->image),
+                          ide_str_equal0 (self->runtime_id,
+                                          ide_configuration_get_runtime_id (config)));
+}
+
+GtkWidget *
+gbp_buildui_runtime_row_new (IdeRuntime       *runtime,
+                             IdeConfiguration *config)
+{
+  GbpBuilduiRuntimeRow *self;
+  gboolean sensitive;
+
+  g_return_val_if_fail (IDE_IS_RUNTIME (runtime), NULL);
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (config), NULL);
+
+  sensitive = ide_configuration_supports_runtime (config, runtime);
+
+  self = g_object_new (GBP_TYPE_BUILDUI_RUNTIME_ROW,
+                       "sensitive", sensitive,
+                       "visible", TRUE,
+                       NULL);
+  self->runtime_id = g_strdup (ide_runtime_get_id (runtime));
+  gtk_label_set_label (self->label,
+                       ide_runtime_get_display_name (runtime));
+
+  g_signal_connect_object (config,
+                           "notify::runtime-id",
+                           G_CALLBACK (notify_config_runtime_id),
+                           self,
+                           G_CONNECT_SWAPPED);
+  gtk_widget_set_visible (GTK_WIDGET (self->image),
+                          ide_str_equal0 (self->runtime_id,
+                                          ide_configuration_get_runtime_id (config)));
+
+  return GTK_WIDGET (self);
+}
+
+const gchar *
+gbp_buildui_runtime_row_get_id (GbpBuilduiRuntimeRow *self)
+{
+  g_return_val_if_fail (GBP_IS_BUILDUI_RUNTIME_ROW (self), NULL);
+
+  return self->runtime_id;
+}
diff --git a/src/libide/buildui/ide-build-configuration-row.h b/src/plugins/buildui/gbp-buildui-runtime-row.h
similarity index 59%
rename from src/libide/buildui/ide-build-configuration-row.h
rename to src/plugins/buildui/gbp-buildui-runtime-row.h
index a0f7816fe..64fe8b5a0 100644
--- a/src/libide/buildui/ide-build-configuration-row.h
+++ b/src/plugins/buildui/gbp-buildui-runtime-row.h
@@ -1,6 +1,6 @@
-/* ide-build-configuration-row.h
+/* gbp-buildui-runtime-row.h
  *
- * Copyright 2016-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2018-2019 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
@@ -21,15 +21,16 @@
 #pragma once
 
 #include <gtk/gtk.h>
-#include <ide.h>
+#include <libide-foundry.h>
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_BUILD_CONFIGURATION_ROW (ide_build_configuration_row_get_type())
+#define GBP_TYPE_BUILDUI_RUNTIME_ROW (gbp_buildui_runtime_row_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeBuildConfigurationRow, ide_build_configuration_row, IDE, BUILD_CONFIGURATION_ROW, 
GtkListBoxRow)
+G_DECLARE_FINAL_TYPE (GbpBuilduiRuntimeRow, gbp_buildui_runtime_row, GBP, BUILDUI_RUNTIME_ROW, GtkListBoxRow)
 
-GtkWidget        *ide_build_configuration_row_new               (IdeConfiguration         *configuration);
-IdeConfiguration *ide_build_configuration_row_get_configuration (IdeBuildConfigurationRow *self);
+GtkWidget   *gbp_buildui_runtime_row_new    (IdeRuntime           *runtime,
+                                             IdeConfiguration     *config);
+const gchar *gbp_buildui_runtime_row_get_id (GbpBuilduiRuntimeRow *self);
 
 G_END_DECLS
diff --git a/src/libide/buildui/ide-build-stage-row.c b/src/plugins/buildui/gbp-buildui-stage-row.c
similarity index 65%
rename from src/libide/buildui/ide-build-stage-row.c
rename to src/plugins/buildui/gbp-buildui-stage-row.c
index bf2ea560f..6cfdc9f3d 100644
--- a/src/libide/buildui/ide-build-stage-row.c
+++ b/src/plugins/buildui/gbp-buildui-stage-row.c
@@ -1,4 +1,4 @@
-/* ide-build-stage-row.c
+/* gbp-buildui-stage-row.c
  *
  * Copyright 2017-2019 Christian Hergert <chergert redhat com>
  *
@@ -18,15 +18,15 @@
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
-#define G_LOG_DOMAIN "ide-build-stage-row"
+#define G_LOG_DOMAIN "gbp-buildui-stage-row"
 
 #include "config.h"
 
 #include <dazzle.h>
 
-#include "buildui/ide-build-stage-row.h"
+#include "gbp-buildui-stage-row.h"
 
-struct _IdeBuildStageRow
+struct _GbpBuilduiStageRow
 {
   GtkListBoxRow    parent_instance;
 
@@ -41,16 +41,16 @@ enum {
   N_PROPS
 };
 
-G_DEFINE_TYPE (IdeBuildStageRow, ide_build_stage_row, GTK_TYPE_LIST_BOX_ROW)
+G_DEFINE_TYPE (GbpBuilduiStageRow, gbp_buildui_stage_row, GTK_TYPE_LIST_BOX_ROW)
 
 static GParamSpec *properties [N_PROPS];
 
 static void
-ide_build_stage_row_notify_completed (IdeBuildStageRow *row,
+gbp_buildui_stage_row_notify_completed (GbpBuilduiStageRow *row,
                                       GParamSpec       *pspec,
                                       IdeBuildStage    *stage)
 {
-  g_assert (IDE_IS_BUILD_STAGE_ROW (row));
+  g_assert (GBP_IS_BUILDUI_STAGE_ROW (row));
   g_assert (IDE_IS_BUILD_STAGE (stage));
 
   if (ide_build_stage_get_completed (stage))
@@ -60,12 +60,12 @@ ide_build_stage_row_notify_completed (IdeBuildStageRow *row,
 }
 
 static void
-ide_build_stage_row_set_stage (IdeBuildStageRow *self,
+gbp_buildui_stage_row_set_stage (GbpBuilduiStageRow *self,
                                IdeBuildStage    *stage)
 {
   const gchar *name;
 
-  g_return_if_fail (IDE_IS_BUILD_STAGE_ROW (self));
+  g_return_if_fail (GBP_IS_BUILDUI_STAGE_ROW (self));
   g_return_if_fail (IDE_IS_BUILD_STAGE (stage));
 
   g_set_object (&self->stage, stage);
@@ -79,38 +79,38 @@ ide_build_stage_row_set_stage (IdeBuildStageRow *self,
 
   g_signal_connect_object (stage,
                            "notify::completed",
-                           G_CALLBACK (ide_build_stage_row_notify_completed),
+                           G_CALLBACK (gbp_buildui_stage_row_notify_completed),
                            self,
                            G_CONNECT_SWAPPED);
 
   g_object_bind_property (stage, "disabled", self, "sensitive", G_BINDING_DEFAULT);
   g_object_bind_property (stage, "active", self->label, "bold", G_BINDING_DEFAULT);
 
-  ide_build_stage_row_notify_completed (self, NULL, stage);
+  gbp_buildui_stage_row_notify_completed (self, NULL, stage);
 }
 
 static void
-ide_build_stage_row_destroy (GtkWidget *widget)
+gbp_buildui_stage_row_destroy (GtkWidget *widget)
 {
-  IdeBuildStageRow *self = (IdeBuildStageRow *)widget;
+  GbpBuilduiStageRow *self = (GbpBuilduiStageRow *)widget;
 
   g_clear_object (&self->stage);
 
-  GTK_WIDGET_CLASS (ide_build_stage_row_parent_class)->destroy (widget);
+  GTK_WIDGET_CLASS (gbp_buildui_stage_row_parent_class)->destroy (widget);
 }
 
 static void
-ide_build_stage_row_get_property (GObject    *object,
+gbp_buildui_stage_row_get_property (GObject    *object,
                                   guint       prop_id,
                                   GValue     *value,
                                   GParamSpec *pspec)
 {
-  IdeBuildStageRow *self = IDE_BUILD_STAGE_ROW (object);
+  GbpBuilduiStageRow *self = GBP_BUILDUI_STAGE_ROW (object);
 
   switch (prop_id)
     {
     case PROP_STAGE:
-      g_value_set_object (value, ide_build_stage_row_get_stage (self));
+      g_value_set_object (value, gbp_buildui_stage_row_get_stage (self));
       break;
 
     default:
@@ -119,17 +119,17 @@ ide_build_stage_row_get_property (GObject    *object,
 }
 
 static void
-ide_build_stage_row_set_property (GObject      *object,
+gbp_buildui_stage_row_set_property (GObject      *object,
                                   guint         prop_id,
                                   const GValue *value,
                                   GParamSpec   *pspec)
 {
-  IdeBuildStageRow *self = IDE_BUILD_STAGE_ROW (object);
+  GbpBuilduiStageRow *self = GBP_BUILDUI_STAGE_ROW (object);
 
   switch (prop_id)
     {
     case PROP_STAGE:
-      ide_build_stage_row_set_stage (self, g_value_get_object (value));
+      gbp_buildui_stage_row_set_stage (self, g_value_get_object (value));
       break;
 
     default:
@@ -138,15 +138,15 @@ ide_build_stage_row_set_property (GObject      *object,
 }
 
 static void
-ide_build_stage_row_class_init (IdeBuildStageRowClass *klass)
+gbp_buildui_stage_row_class_init (GbpBuilduiStageRowClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  object_class->get_property = ide_build_stage_row_get_property;
-  object_class->set_property = ide_build_stage_row_set_property;
+  object_class->get_property = gbp_buildui_stage_row_get_property;
+  object_class->set_property = gbp_buildui_stage_row_set_property;
 
-  widget_class->destroy = ide_build_stage_row_destroy;
+  widget_class->destroy = gbp_buildui_stage_row_destroy;
 
   properties [PROP_STAGE] =
     g_param_spec_object ("stage",
@@ -154,34 +154,34 @@ ide_build_stage_row_class_init (IdeBuildStageRowClass *klass)
                          "The stage for the row",
                          IDE_TYPE_BUILD_STAGE,
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 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/plugins/buildui/ide-build-stage-row.ui");
-  gtk_widget_class_bind_template_child (widget_class, IdeBuildStageRow, label);
+                                               "/plugins/buildui/gbp-buildui-stage-row.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStageRow, label);
 }
 
 static void
-ide_build_stage_row_init (IdeBuildStageRow *self)
+gbp_buildui_stage_row_init (GbpBuilduiStageRow *self)
 {
   gtk_widget_init_template (GTK_WIDGET (self));
 }
 
 GtkWidget *
-ide_build_stage_row_new (IdeBuildStage *stage)
+gbp_buildui_stage_row_new (IdeBuildStage *stage)
 {
   g_return_val_if_fail (IDE_IS_BUILD_STAGE (stage), NULL);
 
-  return g_object_new (IDE_TYPE_BUILD_STAGE_ROW,
+  return g_object_new (GBP_TYPE_BUILDUI_STAGE_ROW,
                        "stage", stage,
                        "visible", TRUE,
                        NULL);
 }
 
 /**
- * ide_build_stage_row_get_stage:
- * @self: a #IdeBuildStageRow
+ * gbp_buildui_stage_row_get_stage:
+ * @self: a #GbpBuilduiStageRow
  *
  * Gets the stage for the row.
  *
@@ -190,9 +190,9 @@ ide_build_stage_row_new (IdeBuildStage *stage)
  * Since: 3.32
  */
 IdeBuildStage *
-ide_build_stage_row_get_stage (IdeBuildStageRow *self)
+gbp_buildui_stage_row_get_stage (GbpBuilduiStageRow *self)
 {
-  g_return_val_if_fail (IDE_IS_BUILD_STAGE_ROW (self), NULL);
+  g_return_val_if_fail (GBP_IS_BUILDUI_STAGE_ROW (self), NULL);
 
   return self->stage;
 }
diff --git a/src/libide/buildui/ide-build-stage-row.h b/src/plugins/buildui/gbp-buildui-stage-row.h
similarity index 67%
rename from src/libide/buildui/ide-build-stage-row.h
rename to src/plugins/buildui/gbp-buildui-stage-row.h
index 9f7405f9b..d5bca66ad 100644
--- a/src/libide/buildui/ide-build-stage-row.h
+++ b/src/plugins/buildui/gbp-buildui-stage-row.h
@@ -1,4 +1,4 @@
-/* ide-build-stage-row.h
+/* gbp-buildui-stage-row.h
  *
  * Copyright 2017-2019 Christian Hergert <chergert redhat com>
  *
@@ -20,15 +20,16 @@
 
 #pragma once
 
-#include "buildsystem/ide-build-stage.h"
+#include <gtk/gtk.h>
+#include <libide-foundry.h>
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_BUILD_STAGE_ROW (ide_build_stage_row_get_type())
+#define GBP_TYPE_BUILDUI_STAGE_ROW (gbp_buildui_stage_row_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeBuildStageRow, ide_build_stage_row, IDE, BUILD_STAGE_ROW, GtkListBoxRow)
+G_DECLARE_FINAL_TYPE (GbpBuilduiStageRow, gbp_buildui_stage_row, GBP, BUILDUI_STAGE_ROW, GtkListBoxRow)
 
-GtkWidget     *ide_build_stage_row_new       (IdeBuildStage    *stage);
-IdeBuildStage *ide_build_stage_row_get_stage (IdeBuildStageRow *self);
+GtkWidget     *gbp_buildui_stage_row_new       (IdeBuildStage    *stage);
+IdeBuildStage *gbp_buildui_stage_row_get_stage (GbpBuilduiStageRow *self);
 
 G_END_DECLS
diff --git a/src/libide/buildui/ide-build-stage-row.ui b/src/plugins/buildui/gbp-buildui-stage-row.ui
similarity index 88%
rename from src/libide/buildui/ide-build-stage-row.ui
rename to src/plugins/buildui/gbp-buildui-stage-row.ui
index b3a428ff9..9eb96f579 100644
--- a/src/libide/buildui/ide-build-stage-row.ui
+++ b/src/plugins/buildui/gbp-buildui-stage-row.ui
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <template class="IdeBuildStageRow" parent="GtkListBoxRow">
+  <template class="GbpBuilduiStageRow" parent="GtkListBoxRow">
     <child>
       <object class="GtkBox">
         <property name="visible">true</property>
diff --git a/src/plugins/buildui/gbp-buildui-tree-addin.c b/src/plugins/buildui/gbp-buildui-tree-addin.c
new file mode 100644
index 000000000..6c8c337df
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-tree-addin.c
@@ -0,0 +1,381 @@
+/* gbp-buildui-tree-addin.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-tree-addin"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libpeas/peas.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+#include <libide-plugins.h>
+#include <libide-threading.h>
+#include <libide-tree.h>
+
+#include "gbp-buildui-tree-addin.h"
+
+struct _GbpBuilduiTreeAddin
+{
+  GObject       parent_instance;
+  IdeTree      *tree;
+  IdeTreeModel *model;
+};
+
+typedef struct
+{
+  IdeTreeNode *node;
+  guint        n_active;
+} BuildTargets;
+
+static void
+build_targets_free (BuildTargets *state)
+{
+  g_clear_object (&state->node);
+  g_slice_free (BuildTargets, state);
+}
+
+static void
+get_targets_cb (GObject      *object,
+                GAsyncResult *result,
+                gpointer      user_data)
+{
+  IdeBuildTargetProvider *provider = (IdeBuildTargetProvider *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GPtrArray) targets = NULL;
+  BuildTargets *state;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_BUILD_TARGET_PROVIDER (provider));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  state = ide_task_get_task_data (task);
+
+  if ((targets = ide_build_target_provider_get_targets_finish (provider, result, &error)))
+    {
+      for (guint i = 0; i < targets->len; i++)
+        {
+          IdeBuildTarget *target = g_ptr_array_index (targets, i);
+          g_autoptr(IdeTreeNode) node = NULL;
+          g_autofree gchar *name = NULL;
+
+          name = ide_build_target_get_name (target);
+          node = g_object_new (IDE_TYPE_TREE_NODE,
+                               "destroy-item", TRUE,
+                               "display-name", name,
+                               "icon-name", "builder-build-symbolic",
+                               "item", target,
+                               NULL);
+          ide_tree_node_append (state->node, node);
+        }
+    }
+
+  state->n_active--;
+
+  if (state->n_active == 0)
+    ide_task_return_boolean (task, TRUE);
+}
+
+static void
+build_targets_cb (IdeExtensionSetAdapter *set,
+                  PeasPluginInfo         *plugin_info,
+                  PeasExtension          *exten,
+                  gpointer                user_data)
+{
+  IdeBuildTargetProvider *provider = (IdeBuildTargetProvider *)exten;
+  IdeTask *task = user_data;
+  BuildTargets *state;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
+  g_assert (IDE_IS_BUILD_TARGET_PROVIDER (provider));
+  g_assert (IDE_IS_TASK (task));
+
+  state = ide_task_get_task_data (task);
+  state->n_active++;
+
+  ide_build_target_provider_get_targets_async (provider,
+                                               ide_task_get_cancellable (task),
+                                               get_targets_cb,
+                                               g_object_ref (task));
+}
+
+static void
+gbp_buildui_tree_addin_build_children_async (IdeTreeAddin        *addin,
+                                             IdeTreeNode         *node,
+                                             GCancellable        *cancellable,
+                                             GAsyncReadyCallback  callback,
+                                             gpointer             user_data)
+{
+  GbpBuilduiTreeAddin *self = (GbpBuilduiTreeAddin *)addin;
+  g_autoptr(IdeTask) task = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TREE_ADDIN (self));
+  g_assert (IDE_IS_TREE_NODE (node));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_buildui_tree_addin_build_children_async);
+
+  if (ide_tree_node_holds (node, IDE_TYPE_CONTEXT))
+    {
+      g_autoptr(IdeTreeNode) targets = NULL;
+
+      targets = g_object_new (IDE_TYPE_TREE_NODE,
+                              "icon-name", "builder-build-symbolic",
+                              "item", NULL,
+                              "display-name", _("Build Targets"),
+                              "children-possible", TRUE,
+                              "tag", "BUILD_TARGETS",
+                              NULL);
+      ide_tree_node_prepend (node, targets);
+    }
+  else if (ide_tree_node_is_tag (node, "BUILD_TARGETS"))
+    {
+      g_autoptr(IdeExtensionSetAdapter) set = NULL;
+      BuildTargets *state;
+
+      state = g_slice_new0 (BuildTargets);
+      state->node = g_object_ref (node);
+      state->n_active = 0;
+      ide_task_set_task_data (task, state, build_targets_free);
+
+      set = ide_extension_set_adapter_new (IDE_OBJECT (self->model),
+                                           peas_engine_get_default (),
+                                           IDE_TYPE_BUILD_TARGET_PROVIDER,
+                                           NULL, NULL);
+      ide_extension_set_adapter_foreach (set, build_targets_cb, task);
+
+      if (state->n_active > 0)
+        return;
+    }
+
+  ide_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+gbp_buildui_tree_addin_build_children_finish (IdeTreeAddin  *addin,
+                                              GAsyncResult  *result,
+                                              GError       **error)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TASK (result));
+
+  return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
+
+static void
+gbp_buildui_tree_addin_action_build (GSimpleAction *action,
+                                     GVariant      *param,
+                                     gpointer       user_data)
+{
+  GbpBuilduiTreeAddin *self = user_data;
+  g_autoptr(GPtrArray) targets = NULL;
+  IdeBuildManager *build_manager;
+  IdeBuildTarget *target;
+  IdeTreeNode *node;
+  IdeContext *context;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
+
+  if (!(context = ide_widget_get_context (GTK_WIDGET (self->tree))) ||
+      !(build_manager = ide_build_manager_from_context (context)) ||
+      !(node = ide_tree_get_selected_node (self->tree)) ||
+      !ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET) ||
+      !(target = ide_tree_node_get_item (node)))
+    return;
+
+  targets = g_ptr_array_new_full (1, g_object_unref);
+  g_ptr_array_add (targets, g_object_ref (target));
+
+  ide_build_manager_execute_async (build_manager, IDE_BUILD_PHASE_BUILD, targets, NULL, NULL, NULL);
+}
+
+static void
+gbp_buildui_tree_addin_action_rebuild (GSimpleAction *action,
+                                       GVariant      *param,
+                                       gpointer       user_data)
+{
+  GbpBuilduiTreeAddin *self = user_data;
+  g_autoptr(GPtrArray) targets = NULL;
+  IdeBuildManager *build_manager;
+  IdeBuildTarget *target;
+  IdeTreeNode *node;
+  IdeContext *context;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
+
+  if (!(context = ide_widget_get_context (GTK_WIDGET (self->tree))) ||
+      !(build_manager = ide_build_manager_from_context (context)) ||
+      !(node = ide_tree_get_selected_node (self->tree)) ||
+      !ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET) ||
+      !(target = ide_tree_node_get_item (node)))
+    return;
+
+  targets = g_ptr_array_new_full (1, g_object_unref);
+  g_ptr_array_add (targets, g_object_ref (target));
+
+  ide_build_manager_rebuild_async (build_manager, IDE_BUILD_PHASE_BUILD, targets, NULL, NULL, NULL);
+}
+
+static void
+gbp_buildui_tree_addin_action_run (GSimpleAction *action,
+                                   GVariant      *param,
+                                   gpointer       user_data)
+{
+  GbpBuilduiTreeAddin *self = user_data;
+  g_autoptr(GPtrArray) targets = NULL;
+  IdeBuildManager *build_manager;
+  IdeBuildTarget *target;
+  IdeRunManager *run_manager;
+  IdeTreeNode *node;
+  IdeContext *context;
+  const gchar *handler;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (param != NULL);
+  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+  g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
+
+  if (!(context = ide_widget_get_context (GTK_WIDGET (self->tree))) ||
+      !(build_manager = ide_build_manager_from_context (context)) ||
+      !(node = ide_tree_get_selected_node (self->tree)) ||
+      !ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET) ||
+      !(target = ide_tree_node_get_item (node)))
+    return;
+
+  run_manager = ide_run_manager_from_context (context);
+  handler = g_variant_get_string (param, NULL);
+
+  if (ide_str_empty0 (handler))
+    ide_run_manager_set_handler (run_manager, NULL);
+  else
+    ide_run_manager_set_handler (run_manager, handler);
+
+  ide_run_manager_run_async (run_manager,
+                             target,
+                             NULL,
+                             NULL,
+                             NULL);
+}
+
+static void
+gbp_buildui_tree_addin_load (IdeTreeAddin *addin,
+                             IdeTree      *tree,
+                             IdeTreeModel *model)
+{
+  GbpBuilduiTreeAddin *self = (GbpBuilduiTreeAddin *)addin;
+  g_autoptr(GSimpleActionGroup) group = NULL;
+  static const GActionEntry actions[] = {
+    { "build", gbp_buildui_tree_addin_action_build },
+    { "rebuild", gbp_buildui_tree_addin_action_rebuild },
+    { "run-with-handler", gbp_buildui_tree_addin_action_run, "s" },
+  };
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
+  g_assert (IDE_IS_TREE (tree));
+  g_assert (IDE_IS_TREE_MODEL (model));
+
+  self->model = model;
+  self->tree = tree;
+
+  group = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (group),
+                                   actions,
+                                   G_N_ELEMENTS (actions),
+                                   self);
+  gtk_widget_insert_action_group (GTK_WIDGET (tree), "buildui", G_ACTION_GROUP (group));
+}
+
+static void
+gbp_buildui_tree_addin_unload (IdeTreeAddin *addin,
+                               IdeTree      *tree,
+                               IdeTreeModel *model)
+{
+  GbpBuilduiTreeAddin *self = (GbpBuilduiTreeAddin *)addin;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
+  g_assert (IDE_IS_TREE (tree));
+  g_assert (IDE_IS_TREE_MODEL (model));
+
+  gtk_widget_insert_action_group (GTK_WIDGET (tree), "buildui", NULL);
+
+  self->model = NULL;
+  self->tree = NULL;
+}
+
+static void
+gbp_buildui_tree_addin_selection_changed (IdeTreeAddin *addin,
+                                          IdeTreeNode  *node)
+{
+  GbpBuilduiTreeAddin *self = (GbpBuilduiTreeAddin *)addin;
+  IdeBuildTarget *target;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
+  g_assert (!node || IDE_IS_TREE_NODE (node));
+
+  dzl_gtk_widget_action_set (GTK_WIDGET (self->tree), "buildui", "build",
+                             "enabled", node && ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET),
+                             NULL);
+  dzl_gtk_widget_action_set (GTK_WIDGET (self->tree), "buildui", "rebuild",
+                             "enabled", node && ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET),
+                             NULL);
+  dzl_gtk_widget_action_set (GTK_WIDGET (self->tree), "buildui", "run-with-handler",
+                             "enabled", node &&
+                                        ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET) &&
+                                        (target = ide_tree_node_get_item (node)) &&
+                                        ide_build_target_get_install (target) &&
+                                        ide_build_target_get_kind (target) == IDE_ARTIFACT_KIND_EXECUTABLE,
+                             NULL);
+}
+
+static void
+tree_addin_iface_init (IdeTreeAddinInterface *iface)
+{
+  iface->build_children_async = gbp_buildui_tree_addin_build_children_async;
+  iface->build_children_finish = gbp_buildui_tree_addin_build_children_finish;
+  iface->selection_changed = gbp_buildui_tree_addin_selection_changed;
+  iface->load = gbp_buildui_tree_addin_load;
+  iface->unload = gbp_buildui_tree_addin_unload;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpBuilduiTreeAddin, gbp_buildui_tree_addin, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_TREE_ADDIN, tree_addin_iface_init))
+
+static void
+gbp_buildui_tree_addin_class_init (GbpBuilduiTreeAddinClass *klass)
+{
+}
+
+static void
+gbp_buildui_tree_addin_init (GbpBuilduiTreeAddin *self)
+{
+}
diff --git a/src/libide/buildui/ide-build-tool.h b/src/plugins/buildui/gbp-buildui-tree-addin.h
similarity index 72%
rename from src/libide/buildui/ide-build-tool.h
rename to src/plugins/buildui/gbp-buildui-tree-addin.h
index 6c6b2eba8..ef7005605 100644
--- a/src/libide/buildui/ide-build-tool.h
+++ b/src/plugins/buildui/gbp-buildui-tree-addin.h
@@ -1,6 +1,6 @@
-/* ide-build-tool.h
+/* gbp-buildui-tree-addin.h
  *
- * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ * Copyright 2018-2019 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
@@ -20,12 +20,12 @@
 
 #pragma once
 
-#include <ide.h>
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_BUILD_TOOL (ide_build_tool_get_type())
+#define GBP_TYPE_BUILDUI_TREE_ADDIN (gbp_buildui_tree_addin_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeBuildTool, ide_build_tool, IDE, BUILD_TOOL, GObject)
+G_DECLARE_FINAL_TYPE (GbpBuilduiTreeAddin, gbp_buildui_tree_addin, GBP, BUILDUI_TREE_ADDIN, GObject)
 
 G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-workspace-addin.c 
b/src/plugins/buildui/gbp-buildui-workspace-addin.c
new file mode 100644
index 000000000..e36cd1bd1
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-workspace-addin.c
@@ -0,0 +1,428 @@
+/* gbp-buildui-workspace-addin.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-workspace-addin"
+
+#include "config.h"
+
+#include <dazzle.h>
+#include <glib/gi18n.h>
+#include <libide-editor.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+
+#include "gbp-buildui-config-surface.h"
+#include "gbp-buildui-log-pane.h"
+#include "gbp-buildui-omni-bar-section.h"
+#include "gbp-buildui-pane.h"
+#include "gbp-buildui-workspace-addin.h"
+
+struct _GbpBuilduiWorkspaceAddin
+{
+  GObject                   parent_instance;
+
+  /* Borrowed references */
+  IdeWorkspace             *workspace;
+  GbpBuilduiConfigSurface  *surface;
+  GbpBuilduiOmniBarSection *omni_bar_section;
+  GbpBuilduiLogPane        *log_pane;
+  GbpBuilduiPane           *pane;
+  GtkBox                   *diag_box;
+  GtkImage                 *error_image;
+  GtkLabel                 *error_label;
+  GtkImage                 *warning_image;
+  GtkLabel                 *warning_label;
+  GtkButton                *build_button;
+  GtkButton                *cancel_button;
+
+  /* Owned references */
+  DzlSignalGroup           *build_manager_signals;
+};
+
+static void
+gbp_buildui_workspace_addin_notify_error_count (GbpBuilduiWorkspaceAddin *self,
+                                                GParamSpec               *pspec,
+                                                IdeBuildManager          *build_manager)
+{
+  gchar str[12];
+  guint count;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  if (!(count = ide_build_manager_get_error_count (build_manager)))
+    {
+      gtk_widget_set_visible (GTK_WIDGET (self->error_label), FALSE);
+      gtk_widget_set_visible (GTK_WIDGET (self->error_image), FALSE);
+      gtk_label_set_label (self->error_label, NULL);
+      return;
+    }
+
+  g_snprintf (str, sizeof str, "%u", count);
+  gtk_label_set_label (self->error_label, str);
+  gtk_widget_set_visible (GTK_WIDGET (self->error_label), TRUE);
+  gtk_widget_set_visible (GTK_WIDGET (self->error_image), TRUE);
+}
+
+static void
+gbp_buildui_workspace_addin_notify_warning_count (GbpBuilduiWorkspaceAddin *self,
+                                                  GParamSpec               *pspec,
+                                                  IdeBuildManager          *build_manager)
+{
+  gchar str[12];
+  guint count;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  if (!(count = ide_build_manager_get_warning_count (build_manager)))
+    {
+      gtk_widget_set_visible (GTK_WIDGET (self->warning_label), FALSE);
+      gtk_widget_set_visible (GTK_WIDGET (self->warning_image), FALSE);
+      gtk_label_set_label (self->warning_label, NULL);
+      return;
+    }
+
+  g_snprintf (str, sizeof str, "%u", count);
+  gtk_label_set_label (self->warning_label, str);
+  gtk_widget_set_visible (GTK_WIDGET (self->warning_label), TRUE);
+  gtk_widget_set_visible (GTK_WIDGET (self->warning_image), TRUE);
+}
+
+static void
+gbp_buildui_workspace_addin_notify_pipeline (GbpBuilduiWorkspaceAddin *self,
+                                             GParamSpec               *pspec,
+                                             IdeBuildManager          *build_manager)
+{
+  IdeBuildPipeline *pipeline;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+  gbp_buildui_log_pane_set_pipeline (self->log_pane, pipeline);
+  gbp_buildui_pane_set_pipeline (self->pane, pipeline);
+}
+
+static void
+gbp_buildui_workspace_addin_notify_busy (GbpBuilduiWorkspaceAddin *self,
+                                         GParamSpec               *pspec,
+                                         IdeBuildManager          *build_manager)
+{
+  gboolean busy;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  busy = ide_build_manager_get_busy (build_manager);
+
+  gtk_widget_set_visible (GTK_WIDGET (self->build_button), !busy);
+  gtk_widget_set_visible (GTK_WIDGET (self->cancel_button), busy);
+}
+
+static void
+gbp_buildui_workspace_addin_bind_build_manager (GbpBuilduiWorkspaceAddin *self,
+                                                IdeBuildManager          *build_manager,
+                                                DzlSignalGroup           *signals)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+  g_assert (DZL_IS_SIGNAL_GROUP (signals));
+
+  gbp_buildui_workspace_addin_notify_busy (self, NULL, build_manager);
+  gbp_buildui_workspace_addin_notify_pipeline (self, NULL, build_manager);
+  gbp_buildui_workspace_addin_notify_error_count (self, NULL, build_manager);
+  gbp_buildui_workspace_addin_notify_warning_count (self, NULL, build_manager);
+}
+
+static void
+on_view_output_cb (GSimpleAction *action,
+                   GVariant      *param,
+                   gpointer       user_data)
+{
+  GbpBuilduiWorkspaceAddin *self = user_data;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+
+  ide_widget_reveal_and_grab (GTK_WIDGET (self->log_pane));
+}
+
+static void
+on_edit_config_cb (GSimpleAction *action,
+                   GVariant      *param,
+                   gpointer       user_data)
+{
+  GbpBuilduiWorkspaceAddin *self = user_data;
+  IdeConfigurationManager *config_manager;
+  IdeConfiguration *config;
+  IdeContext *context;
+  const gchar *id;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+
+  ide_workspace_set_visible_surface_name (self->workspace, "buildui");
+
+  context = ide_widget_get_context (GTK_WIDGET (self->workspace));
+  config_manager = ide_configuration_manager_from_context (context);
+  id = g_variant_get_string (param, NULL);
+  config = ide_configuration_manager_get_configuration (config_manager, id);
+
+  if (config != NULL)
+    gbp_buildui_config_surface_set_config (self->surface, config);
+}
+
+static const GActionEntry actions[] = {
+  { "edit-config", on_edit_config_cb, "s" },
+  { "view-output", on_view_output_cb },
+};
+
+static void
+gbp_buildui_workspace_addin_load (IdeWorkspaceAddin *addin,
+                                  IdeWorkspace      *workspace)
+{
+  GbpBuilduiWorkspaceAddin *self = (GbpBuilduiWorkspaceAddin *)addin;
+  IdeConfigurationManager *config_manager;
+  PangoAttrList *small_attrs = NULL;
+  IdeEditorSidebar *sidebar;
+  IdeBuildManager *build_manager;
+  IdeWorkbench *workbench;
+  IdeHeaderBar *headerbar;
+  IdeSurface *surface;
+  IdeOmniBar *omnibar;
+  IdeContext *context;
+  GtkWidget *utilities;
+
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_PRIMARY_WORKSPACE (workspace));
+
+  self->workspace = workspace;
+
+  g_action_map_add_action_entries (G_ACTION_MAP (workspace),
+                                   actions,
+                                   G_N_ELEMENTS (actions),
+                                   self);
+
+  headerbar = ide_workspace_get_header_bar (workspace);
+  omnibar = IDE_OMNI_BAR (gtk_header_bar_get_custom_title (GTK_HEADER_BAR (headerbar)));
+  workbench = ide_widget_get_workbench (GTK_WIDGET (workspace));
+  context = ide_workbench_get_context (workbench);
+  build_manager = ide_build_manager_from_context (context);
+  config_manager = ide_configuration_manager_from_context (context);
+
+  small_attrs = pango_attr_list_new ();
+  pango_attr_list_insert (small_attrs, pango_attr_scale_new (0.833333));
+
+  self->diag_box = g_object_new (GTK_TYPE_BOX,
+                                 "orientation", GTK_ORIENTATION_HORIZONTAL,
+                                 "visible", TRUE,
+                                 NULL);
+  g_signal_connect (self->diag_box,
+                    "destroy",
+                    G_CALLBACK (gtk_widget_destroyed),
+                    &self->diag_box);
+  ide_omni_bar_add_status_icon (omnibar, GTK_WIDGET (self->diag_box), 0);
+
+  self->error_image = g_object_new (GTK_TYPE_IMAGE,
+                                    "icon-name", "dialog-error-symbolic",
+                                    "margin-end", 2,
+                                    "margin-start", 4,
+                                    "pixel-size", 12,
+                                    "valign", GTK_ALIGN_BASELINE,
+                                    NULL);
+  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->error_image));
+
+  self->error_label = g_object_new (GTK_TYPE_LABEL,
+                                    "attributes", small_attrs,
+                                    "margin-end", 2,
+                                    "margin-start", 2,
+                                    "valign", GTK_ALIGN_BASELINE,
+                                    NULL);
+  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->error_label));
+
+  self->warning_image = g_object_new (GTK_TYPE_IMAGE,
+                                      "icon-name", "dialog-warning-symbolic",
+                                      "margin-end", 2,
+                                      "margin-start", 4,
+                                      "pixel-size", 12,
+                                      "valign", GTK_ALIGN_BASELINE,
+                                      NULL);
+  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->warning_image));
+
+  self->warning_label = g_object_new (GTK_TYPE_LABEL,
+                                      "attributes", small_attrs,
+                                      "margin-end", 2,
+                                      "margin-start", 2,
+                                      "valign", GTK_ALIGN_BASELINE,
+                                      NULL);
+  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->warning_label));
+
+  g_clear_pointer (&small_attrs, pango_attr_list_unref);
+
+  self->omni_bar_section = g_object_new (GBP_TYPE_BUILDUI_OMNI_BAR_SECTION,
+                                         "visible", TRUE,
+                                         NULL);
+  g_signal_connect (self->omni_bar_section,
+                    "destroy",
+                    G_CALLBACK (gtk_widget_destroyed),
+                    &self->omni_bar_section);
+  ide_omni_bar_add_popover_section (omnibar, GTK_WIDGET (self->omni_bar_section), 0);
+  gbp_buildui_omni_bar_section_set_context (self->omni_bar_section, context);
+
+  self->build_button = g_object_new (GTK_TYPE_BUTTON,
+                                     "action-name", "build-manager.build",
+                                     "child", g_object_new (GTK_TYPE_IMAGE,
+                                                            "icon-name", "builder-build-symbolic",
+                                                            "visible", TRUE,
+                                                            NULL),
+                                     "focus-on-click", FALSE,
+                                     "has-tooltip", TRUE,
+                                     "visible", TRUE,
+                                     NULL);
+  ide_omni_bar_add_button (omnibar, GTK_WIDGET (self->build_button), GTK_PACK_END, 0);
+
+  self->cancel_button = g_object_new (GTK_TYPE_BUTTON,
+                                      "action-name", "build-manager.cancel",
+                                      "child", g_object_new (GTK_TYPE_IMAGE,
+                                                             "icon-name", "process-stop-symbolic",
+                                                             "visible", TRUE,
+                                                             NULL),
+                                      "focus-on-click", FALSE,
+                                      "has-tooltip", TRUE,
+                                      "visible", TRUE,
+                                      NULL);
+  ide_omni_bar_add_button (omnibar, GTK_WIDGET (self->cancel_button), GTK_PACK_END, 0);
+
+  surface = ide_workspace_get_surface_by_name (workspace, "editor");
+  utilities = ide_editor_surface_get_utilities (IDE_EDITOR_SURFACE (surface));
+  sidebar = ide_editor_surface_get_sidebar (IDE_EDITOR_SURFACE (surface));
+
+  self->log_pane = g_object_new (GBP_TYPE_BUILDUI_LOG_PANE,
+                                 "visible", TRUE,
+                                 NULL);
+  gtk_container_add (GTK_CONTAINER (utilities), GTK_WIDGET (self->log_pane));
+
+  self->pane = g_object_new (GBP_TYPE_BUILDUI_PANE,
+                             "visible", TRUE,
+                             NULL);
+  ide_editor_sidebar_add_section (sidebar,
+                                  "build-issues",
+                                  _("Build Issues"),
+                                  "builder-build-symbolic",
+                                  NULL, NULL,
+                                  GTK_WIDGET (self->pane),
+                                  100);
+
+  self->surface = g_object_new (GBP_TYPE_BUILDUI_CONFIG_SURFACE,
+                                "config-manager", config_manager,
+                                "icon-name", "builder-build-configure-symbolic",
+                                "title", _("Build Preferences"),
+                                "name", "buildui",
+                                "visible", TRUE,
+                                NULL);
+  g_signal_connect (self->surface,
+                    "destroy",
+                    G_CALLBACK (gtk_widget_destroyed),
+                    &self->surface);
+  ide_workspace_add_surface (workspace, IDE_SURFACE (self->surface));
+
+  self->build_manager_signals = dzl_signal_group_new (IDE_TYPE_BUILD_MANAGER);
+  g_signal_connect_object (self->build_manager_signals,
+                           "bind",
+                           G_CALLBACK (gbp_buildui_workspace_addin_bind_build_manager),
+                           self,
+                           G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::error-count",
+                                   G_CALLBACK (gbp_buildui_workspace_addin_notify_error_count),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::warning-count",
+                                   G_CALLBACK (gbp_buildui_workspace_addin_notify_warning_count),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::pipeline",
+                                   G_CALLBACK (gbp_buildui_workspace_addin_notify_pipeline),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_connect_object (self->build_manager_signals,
+                                   "notify::busy",
+                                   G_CALLBACK (gbp_buildui_workspace_addin_notify_busy),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+  dzl_signal_group_set_target (self->build_manager_signals, build_manager);
+}
+
+static void
+gbp_buildui_workspace_addin_unload (IdeWorkspaceAddin *addin,
+                                    IdeWorkspace      *workspace)
+{
+  GbpBuilduiWorkspaceAddin *self = (GbpBuilduiWorkspaceAddin *)addin;
+
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_PRIMARY_WORKSPACE (workspace));
+
+  for (guint i = 0; i < G_N_ELEMENTS (actions); i++)
+    g_action_map_remove_action (G_ACTION_MAP (workspace), actions[i].name);
+
+  if (self->omni_bar_section)
+    gtk_widget_destroy (GTK_WIDGET (self->omni_bar_section));
+
+  if (self->diag_box)
+    gtk_widget_destroy (GTK_WIDGET (self->diag_box));
+
+  if (self->surface)
+    gtk_widget_destroy (GTK_WIDGET (self->surface));
+
+  dzl_signal_group_set_target (self->build_manager_signals, NULL);
+  g_clear_object (&self->build_manager_signals);
+
+  self->workspace = NULL;
+}
+
+static void
+workspace_addin_iface_init (IdeWorkspaceAddinInterface *iface)
+{
+  iface->load = gbp_buildui_workspace_addin_load;
+  iface->unload = gbp_buildui_workspace_addin_unload;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpBuilduiWorkspaceAddin, gbp_buildui_workspace_addin, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKSPACE_ADDIN, workspace_addin_iface_init))
+
+static void
+gbp_buildui_workspace_addin_class_init (GbpBuilduiWorkspaceAddinClass *klass)
+{
+}
+
+static void
+gbp_buildui_workspace_addin_init (GbpBuilduiWorkspaceAddin *self)
+{
+}
diff --git a/src/libide/buildui/ide-build-workbench-addin.h 
b/src/plugins/buildui/gbp-buildui-workspace-addin.h
similarity index 70%
rename from src/libide/buildui/ide-build-workbench-addin.h
rename to src/plugins/buildui/gbp-buildui-workspace-addin.h
index a98fe935d..4279292c9 100644
--- a/src/libide/buildui/ide-build-workbench-addin.h
+++ b/src/plugins/buildui/gbp-buildui-workspace-addin.h
@@ -1,6 +1,6 @@
-/* ide-build-workbench-addin.h
+/* gbp-buildui-workspace-addin.h
  *
- * Copyright 2015-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2018-2019 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
@@ -20,12 +20,12 @@
 
 #pragma once
 
-#include <ide.h>
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_BUILD_WORKBENCH_ADDIN (ide_build_workbench_addin_get_type())
+#define GBP_TYPE_BUILDUI_WORKSPACE_ADDIN (gbp_buildui_workspace_addin_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeBuildWorkbenchAddin, ide_build_workbench_addin, IDE, BUILD_WORKBENCH_ADDIN, GObject)
+G_DECLARE_FINAL_TYPE (GbpBuilduiWorkspaceAddin, gbp_buildui_workspace_addin, GBP, BUILDUI_WORKSPACE_ADDIN, 
GObject)
 
 G_END_DECLS
diff --git a/src/plugins/buildui/gtk/menus.ui b/src/plugins/buildui/gtk/menus.ui
new file mode 100644
index 000000000..7741b8491
--- /dev/null
+++ b/src/plugins/buildui/gtk/menus.ui
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <menu id="ide-primary-workspace-surfaces-menu">
+    <section id="ide-primary-workspace-surfaces-menu-section">
+      <item>
+        <attribute name="accel">&lt;alt&gt;2</attribute>
+        <attribute name="id">surface-menu-config</attribute>
+        <attribute name="label" translatable="yes">Build Preferences</attribute>
+        <attribute name="role">normal</attribute>
+        <attribute name="action">win.surface</attribute>
+        <attribute name="target">buildui</attribute>
+        <attribute name="verb-icon-name">builder-build-configure-symbolic</attribute>
+      </item>
+    </section>
+  </menu>
+  <menu id="project-tree-menu">
+    <section id="project-tree-menu-placeholder3">
+      <item>
+        <attribute name="id">project-tree-menu-build</attribute>
+        <attribute name="label" translatable="yes">Build</attribute>
+        <attribute name="action">buildui.build</attribute>
+      </item>
+      <item>
+        <attribute name="id">project-tree-menu-rebuild</attribute>
+        <attribute name="label" translatable="yes">Rebuild</attribute>
+        <attribute name="action">buildui.rebuild</attribute>
+      </item>
+      <item>
+        <attribute name="id">project-tree-menu-run</attribute>
+        <attribute name="label" translatable="yes">Run</attribute>
+        <attribute name="action">buildui.run-with-handler</attribute>
+        <attribute name="target" type="s">''</attribute>
+      </item>
+      <submenu id="project-tree-run-with-submenu">
+        <attribute name="label" translatable="yes">Run With…</attribute>
+        <section id="project-tree-menu-run-with-section">
+        </section>
+      </submenu>
+    </section>
+  </menu>
+</interface>
diff --git a/src/plugins/buildui/meson.build b/src/plugins/buildui/meson.build
new file mode 100644
index 000000000..fe69f85e4
--- /dev/null
+++ b/src/plugins/buildui/meson.build
@@ -0,0 +1,21 @@
+plugins_sources += files([
+  'buildui-plugin.c',
+  'gbp-buildui-config-surface.c',
+  'gbp-buildui-config-view-addin.c',
+  'gbp-buildui-log-pane.c',
+  'gbp-buildui-omni-bar-section.c',
+  'gbp-buildui-pane.c',
+  'gbp-buildui-runtime-categories.c',
+  'gbp-buildui-runtime-row.c',
+  'gbp-buildui-stage-row.c',
+  'gbp-buildui-tree-addin.c',
+  'gbp-buildui-workspace-addin.c',
+])
+
+plugin_buildui_resources = gnome.compile_resources(
+  'buildui-resources',
+  'buildui.gresource.xml',
+  c_name: 'gbp_buildui',
+)
+
+plugins_sources += plugin_buildui_resources[0]
diff --git a/src/plugins/buildui/themes/shared.css b/src/plugins/buildui/themes/shared.css
new file mode 100644
index 000000000..a4f1baea0
--- /dev/null
+++ b/src/plugins/buildui/themes/shared.css
@@ -0,0 +1,9 @@
+.buildui .sidebar label.header {
+  padding: 8px;
+  border-bottom: 1px solid alpha(@borders, 0.5);
+}
+
+.omnibar label.error {
+  color: @error_color;
+  font-weight: bold;
+}



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