[gnome-builder] plugins/sysprof: port to GTK 4



commit ddc625558260d6ede371f2ee2f81b1313011bfc6
Author: Christian Hergert <chergert redhat com>
Date:   Mon Jul 11 23:21:35 2022 -0700

    plugins/sysprof: port to GTK 4
    
    This port is incomplete. It does not yet handle IdeRunTool to the point of
    using a subprocess to spawn the worker. That will be needed for this to
    be complete.
    
    We might be able to expand sysprof-cli to do that in a more programmable
    fashion without having to create a new executable.

 src/plugins/sysprof/gbp-sysprof-page.c             | 251 +++++++++++++
 src/plugins/sysprof/gbp-sysprof-page.h             |  37 ++
 src/plugins/sysprof/gbp-sysprof-tool.c             | 104 +++++
 src/plugins/sysprof/gbp-sysprof-tool.h             |  31 ++
 src/plugins/sysprof/gbp-sysprof-workbench-addin.c  | 195 ++++++++++
 src/plugins/sysprof/gbp-sysprof-workbench-addin.h  |  31 ++
 src/plugins/sysprof/gbp-sysprof-workspace-addin.c  | 418 ++++++---------------
 src/plugins/sysprof/gtk/keybindings.json           |   3 +
 src/plugins/sysprof/gtk/menus.ui                   | 124 +++++-
 src/plugins/sysprof/meson.build                    |  12 +-
 .../sysprof/org.gnome.builder.sysprof.gschema.xml  |  16 +
 src/plugins/sysprof/sysprof-plugin.c               |  13 +-
 src/plugins/sysprof/sysprof.gresource.xml          |   3 +-
 src/plugins/sysprof/sysprof.plugin                 |   6 +-
 src/plugins/sysprof/themes/shared.css              |  13 -
 15 files changed, 917 insertions(+), 340 deletions(-)
---
diff --git a/src/plugins/sysprof/gbp-sysprof-page.c b/src/plugins/sysprof/gbp-sysprof-page.c
new file mode 100644
index 000000000..1824b614b
--- /dev/null
+++ b/src/plugins/sysprof/gbp-sysprof-page.c
@@ -0,0 +1,251 @@
+/* gbp-sysprof-page.c
+ *
+ * Copyright 2022 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-sysprof-page"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <sysprof-ui.h>
+
+#include "gbp-sysprof-page.h"
+
+struct _GbpSysprofPage
+{
+  IdePage             parent_instance;
+
+  GFile              *file;
+  GSimpleActionGroup *actions;
+
+  SysprofDisplay     *display;
+};
+
+enum {
+  PROP_0,
+  PROP_FILE,
+  N_PROPS
+};
+
+G_DEFINE_TYPE (GbpSysprofPage, gbp_sysprof_page, IDE_TYPE_PAGE)
+
+static GParamSpec *properties [N_PROPS];
+
+GFile *
+gbp_sysprof_page_get_file (GbpSysprofPage *self)
+{
+  g_return_val_if_fail (GBP_IS_SYSPROF_PAGE (self), NULL);
+
+  return self->file;
+}
+
+static IdePage *
+gbp_sysprof_page_create_split (IdePage *page)
+{
+  GbpSysprofPage *self = (GbpSysprofPage *)page;
+
+  g_assert (GBP_IS_SYSPROF_PAGE (page));
+  g_assert (G_IS_FILE (self->file));
+
+  return IDE_PAGE (gbp_sysprof_page_new_for_file (self->file));
+}
+
+static void
+on_notify_can_replay_cb (GbpSysprofPage *self,
+                         GParamSpec     *pspec,
+                         SysprofDisplay *display)
+{
+  GAction *action;
+
+  g_assert (GBP_IS_SYSPROF_PAGE (self));
+  g_assert (SYSPROF_IS_DISPLAY (display));
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (self->actions), "record-again");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+                               sysprof_display_get_can_replay (display));
+}
+
+static void
+gbp_sysprof_page_set_display (GbpSysprofPage *self,
+                              SysprofDisplay *display)
+{
+  g_assert (GBP_IS_SYSPROF_PAGE (self));
+  g_assert (SYSPROF_IS_DISPLAY (display));
+
+  self->display = display;
+
+  g_signal_connect_object (display,
+                           "notify::can-replay",
+                           G_CALLBACK (on_notify_can_replay_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  on_notify_can_replay_cb (self, NULL, display);
+
+  g_object_bind_property (display, "title", self, "title", G_BINDING_SYNC_CREATE);
+  gtk_widget_set_hexpand (GTK_WIDGET (display), TRUE);
+  gtk_widget_set_vexpand (GTK_WIDGET (display), TRUE);
+  ide_page_add_content_widget (IDE_PAGE (self), GTK_WIDGET (display));
+}
+
+static void
+record_again_action (GSimpleAction *action,
+                     GVariant      *param,
+                     gpointer       user_data)
+{
+  GbpSysprofPage *self = user_data;
+  g_autoptr(IdePanelPosition) position = NULL;
+  GbpSysprofPage *new_page;
+  SysprofDisplay *display;
+  IdeWorkspace *workspace;
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+
+  if (!sysprof_display_get_can_replay (self->display))
+    return;
+
+  if (!(display = sysprof_display_replay (self->display)))
+    return;
+
+  new_page = g_object_new (GBP_TYPE_SYSPROF_PAGE, NULL);
+  g_set_object (&new_page->file, self->file);
+  gbp_sysprof_page_set_display (new_page, display);
+
+  workspace = ide_widget_get_workspace (GTK_WIDGET (self));
+  position = ide_page_get_position (IDE_PAGE (self));
+  ide_panel_position_set_depth (position, 0);
+  ide_workspace_add_page (workspace, IDE_PAGE (new_page), position);
+}
+
+static void
+save_as_action (GSimpleAction *action,
+                GVariant      *param,
+                gpointer       user_data)
+{
+  GbpSysprofPage *self = user_data;
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+
+  if (sysprof_display_get_can_save (self->display))
+    sysprof_display_save (self->display);
+}
+
+static const GActionEntry actions[] = {
+  { "record-again", record_again_action },
+  { "save-as", save_as_action },
+};
+
+static void
+gbp_sysprof_page_dispose (GObject *object)
+{
+  GbpSysprofPage *self = (GbpSysprofPage *)object;
+
+  g_clear_object (&self->file);
+  g_clear_object (&self->actions);
+
+  G_OBJECT_CLASS (gbp_sysprof_page_parent_class)->dispose (object);
+}
+
+static void
+gbp_sysprof_page_get_property (GObject    *object,
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  GbpSysprofPage *self = GBP_SYSPROF_PAGE (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      g_value_set_object (value, gbp_sysprof_page_get_file (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_sysprof_page_class_init (GbpSysprofPageClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdePageClass *page_class = IDE_PAGE_CLASS (klass);
+
+  object_class->dispose = gbp_sysprof_page_dispose;
+  object_class->get_property = gbp_sysprof_page_get_property;
+
+  page_class->create_split = gbp_sysprof_page_create_split;
+
+  properties [PROP_FILE] =
+    g_param_spec_object ("file", NULL, NULL,
+                         G_TYPE_FILE,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_sysprof_page_init (GbpSysprofPage *self)
+{
+  ide_page_set_menu_id (IDE_PAGE (self), "gbp-sysprof-page-menu");
+  panel_widget_set_icon_name (PANEL_WIDGET (self), "builder-profiler-symbolic");
+
+  self->actions = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+                                   actions,
+                                   G_N_ELEMENTS (actions),
+                                   self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self), "sysprof", G_ACTION_GROUP (self->actions));
+}
+
+GbpSysprofPage *
+gbp_sysprof_page_new_for_file (GFile *file)
+{
+  GbpSysprofPage *self;
+  SysprofDisplay *display;
+
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+  g_return_val_if_fail (g_file_is_native (file), NULL);
+
+  self = g_object_new (GBP_TYPE_SYSPROF_PAGE, NULL);
+  g_set_object (&self->file, file);
+  ide_page_set_can_split (IDE_PAGE (self), TRUE);
+
+  display = SYSPROF_DISPLAY (sysprof_display_new ());
+  sysprof_display_open (display, file);
+
+  gbp_sysprof_page_set_display (self, display);
+
+  return self;
+}
+
+GbpSysprofPage *
+gbp_sysprof_page_new_for_profiler (SysprofProfiler *profiler)
+{
+  GbpSysprofPage *self;
+  SysprofDisplay *display;
+
+  g_return_val_if_fail (SYSPROF_IS_PROFILER (profiler), NULL);
+
+  self = g_object_new (GBP_TYPE_SYSPROF_PAGE, NULL);
+  display = SYSPROF_DISPLAY (sysprof_display_new_for_profiler (profiler));
+  gbp_sysprof_page_set_display (self, display);
+
+  return self;
+}
diff --git a/src/plugins/sysprof/gbp-sysprof-page.h b/src/plugins/sysprof/gbp-sysprof-page.h
new file mode 100644
index 000000000..f1f941d7b
--- /dev/null
+++ b/src/plugins/sysprof/gbp-sysprof-page.h
@@ -0,0 +1,37 @@
+/* gbp-sysprof-page.h
+ *
+ * Copyright 2022 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 <sysprof.h>
+
+#include <libide-gui.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SYSPROF_PAGE (gbp_sysprof_page_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpSysprofPage, gbp_sysprof_page, GBP, SYSPROF_PAGE, IdePage)
+
+GbpSysprofPage *gbp_sysprof_page_new_for_file     (GFile           *file);
+GbpSysprofPage *gbp_sysprof_page_new_for_profiler (SysprofProfiler *profiler);
+GFile          *gbp_sysprof_page_get_file         (GbpSysprofPage  *self);
+
+G_END_DECLS
diff --git a/src/plugins/sysprof/gbp-sysprof-tool.c b/src/plugins/sysprof/gbp-sysprof-tool.c
new file mode 100644
index 000000000..8f469aaf3
--- /dev/null
+++ b/src/plugins/sysprof/gbp-sysprof-tool.c
@@ -0,0 +1,104 @@
+/* gbp-sysprof-tool.c
+ *
+ * Copyright 2022 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-sysprof-tool"
+
+#include "config.h"
+
+#include "gbp-sysprof-tool.h"
+
+struct _GbpSysprofTool
+{
+  IdeRunTool parent_instance;
+};
+
+G_DEFINE_FINAL_TYPE (GbpSysprofTool, gbp_sysprof_tool, IDE_TYPE_RUN_TOOL)
+
+static void
+gbp_sysprof_tool_prepare_to_run (IdeRunTool    *run_tool,
+                                 IdePipeline   *pipeline,
+                                 IdeRunCommand *run_command,
+                                 IdeRunContext *run_context)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_TOOL (run_tool));
+  g_assert (IDE_IS_PIPELINE (pipeline));
+  g_assert (IDE_IS_RUN_COMMAND (run_command));
+  g_assert (IDE_IS_RUN_CONTEXT (run_context));
+
+  g_printerr ("TODO: Port sysprof tool\n");
+
+  IDE_EXIT;
+}
+
+static void
+gbp_sysprof_tool_send_signal (IdeRunTool *run_tool,
+                              int         signum)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_TOOL (run_tool));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_sysprof_tool_started (IdeRunTool    *run_tool,
+                          IdeSubprocess *subprocess)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_TOOL (run_tool));
+  g_assert (IDE_IS_SUBPROCESS (subprocess));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_sysprof_tool_stopped (IdeRunTool *run_tool)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_TOOL (run_tool));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_sysprof_tool_class_init (GbpSysprofToolClass *klass)
+{
+  IdeRunToolClass *run_tool_class = IDE_RUN_TOOL_CLASS (klass);
+
+  run_tool_class->prepare_to_run = gbp_sysprof_tool_prepare_to_run;
+  run_tool_class->send_signal = gbp_sysprof_tool_send_signal;
+  run_tool_class->started = gbp_sysprof_tool_started;
+  run_tool_class->stopped = gbp_sysprof_tool_stopped;
+}
+
+static void
+gbp_sysprof_tool_init (GbpSysprofTool *self)
+{
+  ide_run_tool_set_icon_name (IDE_RUN_TOOL (self), "builder-profiler-symbolic");
+}
diff --git a/src/plugins/sysprof/gbp-sysprof-tool.h b/src/plugins/sysprof/gbp-sysprof-tool.h
new file mode 100644
index 000000000..1ca0b4afb
--- /dev/null
+++ b/src/plugins/sysprof/gbp-sysprof-tool.h
@@ -0,0 +1,31 @@
+/* gbp-sysprof-tool.h
+ *
+ * Copyright 2022 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_SYSPROF_TOOL (gbp_sysprof_tool_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpSysprofTool, gbp_sysprof_tool, GBP, SYSPROF_TOOL, IdeRunTool)
+
+G_END_DECLS
diff --git a/src/plugins/sysprof/gbp-sysprof-workbench-addin.c 
b/src/plugins/sysprof/gbp-sysprof-workbench-addin.c
new file mode 100644
index 000000000..4a1b635b6
--- /dev/null
+++ b/src/plugins/sysprof/gbp-sysprof-workbench-addin.c
@@ -0,0 +1,195 @@
+/* gbp-sysprof-workbench-addin.c
+ *
+ * Copyright 2022 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-sysprof-workbench-addin"
+
+#include "config.h"
+
+#include <libide-gui.h>
+#include <libide-threading.h>
+
+#include "gbp-sysprof-page.h"
+#include "gbp-sysprof-workbench-addin.h"
+
+struct _GbpSysprofWorkbenchAddin
+{
+  GObject       parent_instance;
+  IdeWorkbench *workbench;
+};
+
+typedef struct
+{
+  GFile          *file;
+  GbpSysprofPage *page;
+} FindPageWithFile;
+
+static void
+find_page_with_file (IdePage *page,
+                     gpointer user_data)
+{
+  FindPageWithFile *find = user_data;
+  GFile *file;
+
+  g_assert (find != NULL);
+  g_assert (!find->page || GBP_IS_SYSPROF_PAGE (find->page));
+  g_assert (G_IS_FILE (find->file));
+
+  if (find->page != NULL || !GBP_IS_SYSPROF_PAGE (page))
+    return;
+
+  if (!(file = gbp_sysprof_page_get_file (GBP_SYSPROF_PAGE (page))))
+    return;
+
+  if (g_file_equal (file, find->file))
+    find->page = GBP_SYSPROF_PAGE (page);
+}
+
+static void
+gbp_sysprof_workbench_addin_open_async (IdeWorkbenchAddin   *addin,
+                                        GFile               *file,
+                                        const char          *content_type,
+                                        int                  at_line,
+                                        int                  at_line_offset,
+                                        IdeBufferOpenFlags   flags,
+                                        IdePanelPosition    *position,
+                                        GCancellable        *cancellable,
+                                        GAsyncReadyCallback  callback,
+                                        gpointer             user_data)
+{
+  GbpSysprofWorkbenchAddin *self = (GbpSysprofWorkbenchAddin *)addin;
+  g_autoptr(IdeTask) task = NULL;
+  IdeWorkspace *workspace;
+  FindPageWithFile find = {file, NULL};
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_FILE (file));
+  g_assert (IDE_IS_WORKBENCH (self->workbench));
+
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_sysprof_workbench_addin_open_async);
+
+  ide_workbench_foreach_page (self->workbench, find_page_with_file, &find);
+
+  if (find.page == NULL)
+    {
+      workspace = ide_workbench_get_current_workspace (self->workbench);
+      find.page = gbp_sysprof_page_new_for_file (file);
+      ide_workspace_add_page (workspace, IDE_PAGE (find.page), position);
+    }
+
+  workspace = ide_widget_get_workspace (GTK_WIDGET (find.page));
+  panel_widget_raise (PANEL_WIDGET (find.page));
+  gtk_window_present (GTK_WINDOW (workspace));
+
+  ide_task_return_boolean (task, TRUE);
+
+  IDE_EXIT;
+}
+
+static gboolean
+gbp_sysprof_workbench_addin_open_finish (IdeWorkbenchAddin  *addin,
+                                         GAsyncResult       *result,
+                                         GError            **error)
+{
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (addin));
+  g_assert (IDE_IS_TASK (result));
+
+  ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+static gboolean
+gbp_sysprof_workbench_addin_can_open (IdeWorkbenchAddin *addin,
+                                      GFile             *file,
+                                      const char        *content_type,
+                                      gint              *priority)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (addin));
+  g_assert (G_IS_FILE (file));
+  g_assert (priority != NULL);
+
+  if (ide_str_equal0 (content_type, "application/x-sysprof-capture"))
+    {
+      *priority = 0;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gbp_sysprof_workbench_addin_load (IdeWorkbenchAddin *addin,
+                                  IdeWorkbench      *workbench)
+{
+  GbpSysprofWorkbenchAddin *self = (GbpSysprofWorkbenchAddin *)addin;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  self->workbench = workbench;
+}
+
+static void
+gbp_sysprof_workbench_addin_unload (IdeWorkbenchAddin *addin,
+                                    IdeWorkbench      *workbench)
+{
+  GbpSysprofWorkbenchAddin *self = (GbpSysprofWorkbenchAddin *)addin;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  self->workbench = NULL;
+}
+
+static void
+workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
+{
+  iface->load = gbp_sysprof_workbench_addin_load;
+  iface->unload = gbp_sysprof_workbench_addin_unload;
+  iface->can_open = gbp_sysprof_workbench_addin_can_open;
+  iface->open_async = gbp_sysprof_workbench_addin_open_async;
+  iface->open_finish = gbp_sysprof_workbench_addin_open_finish;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpSysprofWorkbenchAddin, gbp_sysprof_workbench_addin, G_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKBENCH_ADDIN, workbench_addin_iface_init))
+
+static void
+gbp_sysprof_workbench_addin_class_init (GbpSysprofWorkbenchAddinClass *klass)
+{
+}
+
+static void
+gbp_sysprof_workbench_addin_init (GbpSysprofWorkbenchAddin *self)
+{
+}
diff --git a/src/plugins/sysprof/gbp-sysprof-workbench-addin.h 
b/src/plugins/sysprof/gbp-sysprof-workbench-addin.h
new file mode 100644
index 000000000..9db7b340e
--- /dev/null
+++ b/src/plugins/sysprof/gbp-sysprof-workbench-addin.h
@@ -0,0 +1,31 @@
+/* gbp-sysprof-workbench-addin.h
+ *
+ * Copyright 2022 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_SYSPROF_WORKBENCH_ADDIN (gbp_sysprof_workbench_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpSysprofWorkbenchAddin, gbp_sysprof_workbench_addin, GBP, SYSPROF_WORKBENCH_ADDIN, 
GObject)
+
+G_END_DECLS
diff --git a/src/plugins/sysprof/gbp-sysprof-workspace-addin.c 
b/src/plugins/sysprof/gbp-sysprof-workspace-addin.c
index eb12f5e0f..5e88639ed 100644
--- a/src/plugins/sysprof/gbp-sysprof-workspace-addin.c
+++ b/src/plugins/sysprof/gbp-sysprof-workspace-addin.c
@@ -22,219 +22,75 @@
 
 #include "config.h"
 
-#include <dazzle.h>
 #include <glib/gi18n.h>
+
 #include <sysprof-ui.h>
 
-#include "gbp-sysprof-surface.h"
+#include "gbp-sysprof-page.h"
 #include "gbp-sysprof-workspace-addin.h"
 
 struct _GbpSysprofWorkspaceAddin
 {
-  GObject                parent_instance;
+  GObject             parent_instance;
 
-  GSimpleActionGroup    *actions;
+  IdeWorkspace       *workspace;
 
-  GbpSysprofSurface     *surface;
-  IdeWorkspace          *workspace;
+  GSimpleActionGroup *actions;
+  IdeRunManager      *run_manager;
 };
 
-static void workspace_addin_iface_init (IdeWorkspaceAddinInterface *iface);
-
-G_DEFINE_FINAL_TYPE_WITH_CODE (GbpSysprofWorkspaceAddin, gbp_sysprof_workspace_addin, G_TYPE_OBJECT,
-                         G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKSPACE_ADDIN, workspace_addin_iface_init))
-
 static void
-profiler_child_spawned (IdeRunner       *runner,
-                        const gchar     *identifier,
-                        SysprofProfiler *profiler)
+gbp_sysprof_workspace_addin_open (GbpSysprofWorkspaceAddin *self,
+                                  GFile                    *file)
 {
-#ifdef G_OS_UNIX
-  GPid pid = 0;
+  g_autoptr(IdePanelPosition) position = NULL;
+  GbpSysprofPage *page;
 
-  g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (SYSPROF_IS_PROFILER (profiler));
-  g_assert (identifier != NULL);
-  g_assert (IDE_IS_RUNNER (runner));
+  IDE_ENTRY;
 
-  pid = g_ascii_strtoll (identifier, NULL, 10);
+  g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
+  g_assert (G_IS_FILE (file));
 
-  if (pid == 0)
+  if (self->workspace == NULL)
+    IDE_EXIT;
+
+  if (!g_file_is_native (file))
     {
-      g_warning ("Failed to parse integer value from %s", identifier);
+      g_warning ("Can only open local sysprof capture files.");
       return;
     }
 
-  IDE_TRACE_MSG ("Adding pid %s to profiler", identifier);
-
-  sysprof_profiler_add_pid (profiler, pid);
-  sysprof_profiler_start (profiler);
-#endif
-}
-
-static void
-runner_exited_cb (IdeRunner       *runner,
-                  SysprofProfiler *profiler)
-{
-  g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (IDE_IS_RUNNER (runner));
-  g_assert (SYSPROF_IS_PROFILER (profiler));
-
-  if (sysprof_profiler_get_is_running (profiler))
-    sysprof_profiler_stop (profiler);
-}
+  position = ide_panel_position_new ();
+  page = gbp_sysprof_page_new_for_file (file);
 
-static void
-foreach_fd (gint     dest_fd,
-            gint     fd,
-            gpointer user_data)
-{
-  IdeRunner *runner = user_data;
+  ide_workspace_add_page (self->workspace, IDE_PAGE (page), position);
 
-  g_assert (IDE_IS_RUNNER (runner));
-  g_assert (dest_fd >= 0);
-  g_assert (fd >= 0);
-
-  ide_runner_take_fd (runner, dup (fd), dest_fd);
+  IDE_EXIT;
 }
 
 static void
-profiler_run_handler (IdeRunManager *run_manager,
-                      IdeRunner     *runner,
-                      gpointer       user_data)
+on_native_dialog_respnose_cb (GbpSysprofWorkspaceAddin *self,
+                              int                       response_id,
+                              GtkFileChooserNative     *native)
 {
-  GbpSysprofWorkspaceAddin *self = user_data;
-  g_autoptr(SysprofProfiler) profiler = NULL;
-  g_autoptr(SysprofSource) app_source = NULL;
-  g_autoptr(SysprofSpawnable) spawnable = NULL;
-  g_autoptr(GPtrArray) sources = NULL;
-  g_auto(GStrv) argv = NULL;
-  const gchar * const *env;
-  IdeEnvironment *ienv;
-
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
-  g_assert (IDE_IS_RUNNER (runner));
-  g_assert (IDE_IS_RUN_MANAGER (run_manager));
-
-  sources = g_ptr_array_new_with_free_func (g_object_unref);
-
-  profiler = sysprof_local_profiler_new ();
-
-  /*
-   * Currently we require whole-system because otherwise we can get a situation
-   * where we only watch the spawning process (say jhbuild, flatpak, etc).
-   * Longer term we either need a way to follow-children and/or limit to a
-   * cgroup/process-group.
-   */
-  sysprof_profiler_set_whole_system (profiler, TRUE);
-
-#ifdef __linux__
-  {
-    g_ptr_array_add (sources, sysprof_proc_source_new ());
-    g_ptr_array_add (sources, sysprof_perf_source_new ());
-    g_ptr_array_add (sources, sysprof_hostinfo_source_new ());
-    g_ptr_array_add (sources, sysprof_memory_source_new ());
-    g_ptr_array_add (sources, sysprof_proxy_source_new (G_BUS_TYPE_SYSTEM,
-                                                        "org.gnome.Sysprof3",
-                                                        "/org/gnome/Sysprof3/RAPL"));
-    g_ptr_array_add (sources, sysprof_netdev_source_new ());
-  }
-#endif
-
-  g_ptr_array_add (sources, sysprof_gjs_source_new ());
-  g_ptr_array_add (sources, sysprof_symbols_source_new ());
-
-  /* Allow the app to submit us data if it supports "SYSPROF_TRACE_FD" */
-  app_source = sysprof_tracefd_source_new ();
-  sysprof_tracefd_source_set_envvar (SYSPROF_TRACEFD_SOURCE (app_source), "SYSPROF_TRACE_FD");
-  g_ptr_array_add (sources, g_object_ref (app_source));
-
-  /*
-   * TODO:
-   *
-   * We need to synchronize the inferior with the parent here. Ideally, we would
-   * prepend the application launch (to some degree) with the application we want
-   * to execute. In this case, we might want to add a "gnome-builder-sysprof"
-   * helper that will synchronize with the parent, and then block until we start
-   * the process (with the appropriate pid) before exec() otherwise we could
-   * miss the exit of the app and race to add the pid to the profiler.
-   */
-
-  g_signal_connect_object (runner,
-                           "spawned",
-                           G_CALLBACK (profiler_child_spawned),
-                           profiler,
-                           0);
-
-  g_signal_connect_object (runner,
-                           "exited",
-                           G_CALLBACK (runner_exited_cb),
-                           profiler,
-                           0);
-
-  /*
-   * We need to allow the sources to modify the execution environment, so copy
-   * the environment into the spawnable, modify it, and the propagate back.
-   */
-  argv = ide_runner_get_argv (runner);
-  ienv = ide_runner_get_environment (runner);
-
-  spawnable = sysprof_spawnable_new ();
-  sysprof_spawnable_append_args (spawnable, (const gchar * const *)argv);
-  sysprof_spawnable_set_starting_fd (spawnable, ide_runner_get_max_fd (runner) + 1);
-
-  for (guint i = 0; i < sources->len; i++)
-    {
-      SysprofSource *source = g_ptr_array_index (sources, i);
-
-      if (source != NULL)
-        {
-          sysprof_profiler_add_source (profiler, source);
-          sysprof_source_modify_spawn (source, spawnable);
-        }
-    }
-
-  /* TODO: Propagate argv back to runner.
-   *
-   * Currently this is a non-issue because none of our sources modify argv.
-   * So doing it now is just brittle for no benefit.
-   */
+  g_assert (GTK_IS_FILE_CHOOSER_NATIVE (native));
 
-  if ((env = sysprof_spawnable_get_environ (spawnable)))
+  if (response_id == GTK_RESPONSE_ACCEPT)
     {
-      for (guint i = 0; env[i] != NULL; i++)
-        {
-          g_autofree gchar *key = NULL;
-          g_autofree gchar *value = NULL;
-
-          if (ide_environ_parse (env[i], &key, &value))
-            ide_environment_setenv (ienv, key, value);
-        }
-    }
-
-  sysprof_spawnable_foreach_fd (spawnable, foreach_fd, runner);
-
-  gbp_sysprof_surface_add_profiler (self->surface, profiler);
-
-  ide_workspace_set_visible_surface (self->workspace, IDE_SURFACE (self->surface));
-}
+      g_autoptr(GFile) file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
 
-static void
-gbp_sysprof_workspace_addin_open (GbpSysprofWorkspaceAddin *self,
-                                  GFile                    *file)
-{
-  g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
-  g_assert (G_IS_FILE (file));
+      if (G_IS_FILE (file))
+        gbp_sysprof_workspace_addin_open (self, file);
+    }
 
-  if (!g_file_is_native (file))
-    g_warning ("Can only open local sysprof capture files.");
-  else
-    gbp_sysprof_surface_open (self->surface, file);
+  gtk_native_dialog_hide (GTK_NATIVE_DIALOG (native));
+  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
 }
 
 static void
-open_profile_action (GSimpleAction *action,
+open_capture_action (GSimpleAction *action,
                      GVariant      *variant,
                      gpointer       user_data)
 {
@@ -243,14 +99,10 @@ open_profile_action (GSimpleAction *action,
   GtkFileChooserNative *native;
   GtkFileFilter *filter;
   IdeContext *context;
-  gint ret;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
   g_assert (IDE_IS_WORKSPACE (self->workspace));
-  g_assert (GBP_IS_SYSPROF_SURFACE (self->surface));
-
-  ide_workspace_set_visible_surface (self->workspace, IDE_SURFACE (self->surface));
 
   context = ide_workspace_get_context (self->workspace);
   workdir = ide_context_ref_workdir (context);
@@ -260,7 +112,7 @@ open_profile_action (GSimpleAction *action,
                                         GTK_FILE_CHOOSER_ACTION_OPEN,
                                         _("Open"),
                                         _("Cancel"));
-  gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (native), workdir, NULL);
+  gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (native), workdir, NULL);
 
   /* Add our filter for sysprof capture files.  */
   filter = gtk_file_filter_new ();
@@ -274,22 +126,13 @@ open_profile_action (GSimpleAction *action,
   gtk_file_filter_add_pattern (filter, "*");
   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
 
-  /* Unlike gtk_dialog_run(), this will handle processing
-   * various I/O events and so should be safe to use.
-   */
-  ret = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
+  g_signal_connect_object (native,
+                           "response",
+                           G_CALLBACK (on_native_dialog_respnose_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
 
-  if (ret == GTK_RESPONSE_ACCEPT)
-    {
-      g_autoptr(GFile) file = NULL;
-
-      file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
-      if (G_IS_FILE (file))
-        gbp_sysprof_workspace_addin_open (self, file);
-    }
-
-  gtk_native_dialog_hide (GTK_NATIVE_DIALOG (native));
-  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
+  gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
 }
 
 static void
@@ -298,66 +141,15 @@ run_cb (GSimpleAction *action,
         gpointer       user_data)
 {
   GbpSysprofWorkspaceAddin *self = user_data;
+  PeasPluginInfo *plugin_info;
 
   g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_WORKSPACE (self->workspace));
+  g_assert (IDE_IS_RUN_MANAGER (self->run_manager));
 
-  if (self->workspace != NULL)
-    dzl_gtk_widget_action (GTK_WIDGET (self->workspace),
-                           "run-manager",
-                           "run-with-handler",
-                           g_variant_new_string ("profiler"));
-}
-
-static void
-show_cb (GSimpleAction *action,
-         GVariant      *param,
-         gpointer       user_data)
-{
-  GbpSysprofWorkspaceAddin *self = user_data;
-
-  g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
-
-  if (self->workspace != NULL)
-    ide_workspace_set_visible_surface (self->workspace, IDE_SURFACE (self->surface));
-}
-
-static void
-gbp_sysprof_workspace_addin_finalize (GObject *object)
-{
-  GbpSysprofWorkspaceAddin *self = (GbpSysprofWorkspaceAddin *)object;
-
-  g_assert (IDE_IS_MAIN_THREAD ());
-
-  g_clear_object (&self->actions);
-
-  G_OBJECT_CLASS (gbp_sysprof_workspace_addin_parent_class)->finalize (object);
-}
-
-static void
-gbp_sysprof_workspace_addin_class_init (GbpSysprofWorkspaceAddinClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->finalize = gbp_sysprof_workspace_addin_finalize;
-}
-
-static void
-gbp_sysprof_workspace_addin_init (GbpSysprofWorkspaceAddin *self)
-{
-  static const GActionEntry entries[] = {
-    { "open-profile", open_profile_action },
-    { "run", run_cb },
-    { "show", show_cb },
-  };
-
-  g_assert (IDE_IS_MAIN_THREAD ());
-
-  self->actions = g_simple_action_group_new ();
-
-  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
-                                   entries,
-                                   G_N_ELEMENTS (entries),
-                                   self);
+  plugin_info = peas_engine_get_plugin_info (peas_engine_get_default (), "sysprof");
+  ide_run_manager_set_run_tool_from_plugin_info (self->run_manager, plugin_info);
+  ide_run_manager_run_async (self->run_manager, NULL, NULL, NULL);
 }
 
 static void
@@ -367,55 +159,50 @@ gbp_sysprof_workspace_addin_check_supported_cb (GObject      *object,
 {
   g_autoptr(GbpSysprofWorkspaceAddin) self = user_data;
   g_autoptr(GError) error = NULL;
-  IdeRunManager *run_manager;
-  IdeContext *context;
 
-  g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
-  g_assert (G_IS_ASYNC_RESULT (result));
+  IDE_ENTRY;
 
-  /* Check if we're unloaded */
-  if (self->workspace == NULL)
-    return;
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
 
   if (!sysprof_check_supported_finish (result, &error))
     {
       g_warning ("Sysprof-3 is not supported, will not enable profiler: %s",
                  error->message);
-      return;
+      IDE_EXIT;
     }
 
+  if (self->workspace == NULL)
+    IDE_EXIT;
+
+  g_assert (IDE_IS_WORKSPACE (self->workspace));
+  g_assert (IDE_IS_RUN_MANAGER (self->run_manager));
+
   gtk_widget_insert_action_group (GTK_WIDGET (self->workspace),
-                                  "profiler",
+                                  "sysprof",
                                   G_ACTION_GROUP (self->actions));
 
-  /* Register our custom run handler to activate the profiler. */
-  context = ide_workspace_get_context (self->workspace);
-  run_manager = ide_run_manager_from_context (context);
-  ide_run_manager_add_handler (run_manager,
-                               "profiler",
-                               _("Run with Profiler"),
-                               "builder-profiler-symbolic",
-                               "<primary>F8",
-                               profiler_run_handler,
-                               self,
-                               NULL);
-
-  /* Add the surface to the workspace. */
-  self->surface = g_object_new (GBP_TYPE_SYSPROF_SURFACE,
-                                "visible", TRUE,
-                                NULL);
-  g_signal_connect (self->surface,
-                    "destroy",
-                    G_CALLBACK (gtk_widget_destroyed),
-                    &self->surface);
-  ide_workspace_add_surface (self->workspace, IDE_SURFACE (self->surface));
+  IDE_EXIT;
 }
 
+static const GActionEntry entries[] = {
+  { "open-capture", open_capture_action },
+  { "run", run_cb },
+};
+
 static void
 gbp_sysprof_workspace_addin_load (IdeWorkspaceAddin *addin,
                                   IdeWorkspace      *workspace)
 {
   GbpSysprofWorkspaceAddin *self = (GbpSysprofWorkspaceAddin *)addin;
+  g_autoptr(GSettingsSchema) schema = NULL;
+  g_autoptr(GSettings) settings = NULL;
+  g_auto(GStrv) keys = NULL;
+  IdeRunManager *run_manager;
+  IdeContext *context;
+
+  IDE_ENTRY;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
@@ -423,9 +210,38 @@ gbp_sysprof_workspace_addin_load (IdeWorkspaceAddin *addin,
 
   self->workspace = workspace;
 
+  context = ide_workspace_get_context (workspace);
+  run_manager = ide_run_manager_from_context (context);
+
+  self->run_manager = g_object_ref (run_manager);
+  self->actions = g_simple_action_group_new ();
+
+  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+                                   entries,
+                                   G_N_ELEMENTS (entries),
+                                   self);
+
+  settings = g_settings_new ("org.gnome.builder.sysprof");
+  g_object_get (settings, "settings-schema", &schema, NULL);
+  keys = g_settings_schema_list_keys (schema);
+
+  for (guint i = 0; keys[i]; i++)
+    {
+      g_autoptr(GAction) action = g_settings_create_action (settings, keys[i]);
+      g_action_map_add_action (G_ACTION_MAP (self->actions), action);
+    }
+
+  g_object_bind_property (self->run_manager,
+                          "busy",
+                          g_action_map_lookup_action (G_ACTION_MAP (self->actions), "run"),
+                          "enabled",
+                          G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
   sysprof_check_supported_async (NULL,
                                  gbp_sysprof_workspace_addin_check_supported_cb,
                                  g_object_ref (self));
+
+  IDE_EXIT;
 }
 
 static void
@@ -433,24 +249,20 @@ gbp_sysprof_workspace_addin_unload (IdeWorkspaceAddin *addin,
                                     IdeWorkspace      *workspace)
 {
   GbpSysprofWorkspaceAddin *self = (GbpSysprofWorkspaceAddin *)addin;
-  IdeRunManager *run_manager;
-  IdeContext *context;
+
+  IDE_ENTRY;
 
   g_assert (GBP_IS_SYSPROF_WORKSPACE_ADDIN (self));
   g_assert (IDE_IS_WORKSPACE (workspace));
 
-  context = ide_workspace_get_context (workspace);
+  gtk_widget_insert_action_group (GTK_WIDGET (workspace), "sysprof", NULL);
 
-  gtk_widget_insert_action_group (GTK_WIDGET (workspace), "profiler", NULL);
-
-  run_manager = ide_run_manager_from_context (context);
-  ide_run_manager_remove_handler (run_manager, "profiler");
-
-  if (self->surface != NULL)
-    gtk_widget_destroy (GTK_WIDGET (self->surface));
+  g_clear_object (&self->actions);
+  g_clear_object (&self->run_manager);
 
-  self->surface = NULL;
   self->workspace = NULL;
+
+  IDE_EXIT;
 }
 
 static void
@@ -459,3 +271,17 @@ workspace_addin_iface_init (IdeWorkspaceAddinInterface *iface)
   iface->load = gbp_sysprof_workspace_addin_load;
   iface->unload = gbp_sysprof_workspace_addin_unload;
 }
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpSysprofWorkspaceAddin, gbp_sysprof_workspace_addin, G_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKSPACE_ADDIN, workspace_addin_iface_init))
+
+static void
+gbp_sysprof_workspace_addin_class_init (GbpSysprofWorkspaceAddinClass *klass)
+{
+}
+
+static void
+gbp_sysprof_workspace_addin_init (GbpSysprofWorkspaceAddin *self)
+{
+}
+
diff --git a/src/plugins/sysprof/gtk/keybindings.json b/src/plugins/sysprof/gtk/keybindings.json
new file mode 100644
index 000000000..413a17b0d
--- /dev/null
+++ b/src/plugins/sysprof/gtk/keybindings.json
@@ -0,0 +1,3 @@
+{ "trigger" : "<Control>s", "action" : "sysprof.save-as", "when" : "inPageWithTypeName(\"GbpSysprofPage\")", 
"phase" : "capture" },
+{ "trigger" : "<Control><Shift><Alt>p", "action" : "sysprof.run", "when" : "hasProject()", "phase" : 
"capture" },
+{ "trigger" : "<Control>w", "action" : "frame.close-page-or-frame", "when" : 
"inPageWithTypeName(\"GbpSysprofPage\")", "phase" : "capture" },
diff --git a/src/plugins/sysprof/gtk/menus.ui b/src/plugins/sysprof/gtk/menus.ui
index 0050f4b9e..ced6ceb4c 100644
--- a/src/plugins/sysprof/gtk/menus.ui
+++ b/src/plugins/sysprof/gtk/menus.ui
@@ -6,42 +6,128 @@
         <attribute name="id">open-sysprof-capture</attribute>
         <attribute name="after">open-file</attribute>
         <attribute name="label" translatable="yes" context="menu label">Open _Sysprof Capture…</attribute>
-        <attribute name="action">profiler.open-profile</attribute>
-      </item>
-    </section>
-  </menu>
-  <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="before">surface-menu-config</attribute>
-        <attribute name="id">surface-menu-profiler</attribute>
-        <attribute name="label" translatable="yes">Profiler</attribute>
-        <attribute name="role">normal</attribute>
-        <attribute name="action">profiler.show</attribute>
-        <attribute name="verb-icon-name">builder-profiler-symbolic</attribute>
+        <attribute name="action">sysprof.open-capture</attribute>
       </item>
     </section>
   </menu>
   <menu id="run-menu">
-    <section id="run-menu-section">
+    <section id="run-menu-observation-section">
       <item>
-        <attribute name="id">profiler-run-handler</attribute>
+        <attribute name="id">sysprof-run-handler</attribute>
         <attribute name="after">default-run-handler</attribute>
-        <attribute name="action">profiler.run</attribute>
+        <attribute name="action">sysprof.run</attribute>
         <attribute name="label" translatable="yes">Run with Profiler</attribute>
         <attribute name="verb-icon-name">builder-profiler-symbolic</attribute>
-        <attribute name="accel">&lt;Control&gt;F8</attribute>
+        <attribute name="accel">&lt;Control&gt;&lt;Shift&gt;&lt;Alt&gt;p</attribute>
       </item>
     </section>
   </menu>
+  <menu id="run-menu">
+    <section id="run-menu-tools-section">
+      <submenu id="run-menu-sysprof-submenu">
+        <attribute name="before">run-menu-verbose-logging</attribute>
+        <attribute name="label" translatable="yes">Profiler</attribute>
+        <section id="run-menu-sysprof-threads-section">
+          <attribute name="label" translatable="yes">Thread Sampling</attribute>
+          <item>
+            <attribute name="label" translatable="yes">CPU Performance</attribute>
+            <attribute name="action">sysprof.perf-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+          <item>
+            <attribute name="label" translatable="yes">Memory Allocations</attribute>
+            <attribute name="action">sysprof.memprof-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+        </section>
+        <section id="run-menu-sysprof-graphics-section">
+          <attribute name="label" translatable="yes">Graphics</attribute>
+          <item>
+            <attribute name="label" translatable="yes">Display Timings</attribute>
+            <attribute name="action">sysprof.compositor-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+        </section>
+        <section id="run-menu-sysprof-counters-section">
+          <attribute name="label" translatable="yes">Counters</attribute>
+          <item>
+            <attribute name="label" translatable="yes">CPU Usage</attribute>
+            <attribute name="action">sysprof.cpu-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+          <item>
+            <attribute name="label" translatable="yes">Memory Usage</attribute>
+            <attribute name="action">sysprof.memory-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+          <item>
+            <attribute name="label" translatable="yes">Storage I/O</attribute>
+            <attribute name="action">sysprof.diskstat-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+          <item>
+            <attribute name="label" translatable="yes">Network I/O</attribute>
+            <attribute name="action">sysprof.netstat-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+        </section>
+        <section id="run-menu-sysprof-energy-section">
+          <attribute name="label" translatable="yes">Energy</attribute>
+          <item>
+            <attribute name="label" translatable="yes">Consumption</attribute>
+            <attribute name="action">sysprof.energy-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+          <item>
+            <attribute name="label" translatable="yes">Battery Charge</attribute>
+            <attribute name="action">sysprof.battery-aid</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+        </section>
+        <section id="run-menu-sysprof-misc-section">
+          <item>
+            <attribute name="label" translatable="yes">Allow Application Integration</attribute>
+            <attribute name="action">sysprof.allow-tracefd</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+          <item>
+            <attribute name="label" translatable="yes">Allow CPU Throttling</attribute>
+            <attribute name="action">sysprof.allow-throttle</attribute>
+            <attribute name="role">check</attribute>
+          </item>
+        </section>
+      </submenu>
+    </section>
+  </menu>
   <menu id="project-tree-run-with-submenu">
     <section id="project-tree-menu-run-with-section">
       <item>
         <attribute name="id">project-tree-menu-profiler</attribute>
         <attribute name="label" translatable="yes">Run with _Profiler</attribute>
         <attribute name="action">buildui.run-with-handler</attribute>
-        <attribute name="target" type="s">'profiler'</attribute>
+        <attribute name="target" type="s">'sysprof'</attribute>
+      </item>
+    </section>
+  </menu>
+  <menu id="gbp-sysprof-page-menu">
+    <section id="gbp-sysprof-page-file-section">
+      <item>
+        <attribute name="label" translatable="yes">Save</attribute>
+        <attribute name="action">sysprof.save-as</attribute>
+        <attribute name="accel">&lt;control&gt;s</attribute>
+      </item>
+    </section>
+    <section id="gbp-sysprof-page-record-section">
+      <item>
+        <attribute name="label" translatable="yes">Record Again…</attribute>
+        <attribute name="action">sysprof.record-again</attribute>
+      </item>
+    </section>
+    <section id="gbp-sysprof-page-close-section">
+      <item>
+        <attribute name="label" translatable="yes">Close</attribute>
+        <attribute name="action">frame.close-page-or-frame</attribute>
+        <attribute name="accel">&lt;control&gt;w</attribute>
       </item>
     </section>
   </menu>
diff --git a/src/plugins/sysprof/meson.build b/src/plugins/sysprof/meson.build
index 15570ba7a..b19174f80 100644
--- a/src/plugins/sysprof/meson.build
+++ b/src/plugins/sysprof/meson.build
@@ -1,16 +1,16 @@
 if get_option('plugin_sysprof')
 
 plugins_deps += [
-  dependency('sysprof-4', version: '>= 3.37.1'),
-  dependency('sysprof-ui-4', version: '>= 3.37.1'),
+  dependency('sysprof-4', version: '>= 3.45.0'),
+  dependency('sysprof-ui-5', version: '>= 3.45.0'),
 ]
 
 plugins_sources += files([
   'sysprof-plugin.c',
-  'gbp-sysprof-surface.c',
-  'gbp-sysprof-surface.h',
+  'gbp-sysprof-page.c',
+  'gbp-sysprof-tool.c',
+  'gbp-sysprof-workbench-addin.c',
   'gbp-sysprof-workspace-addin.c',
-  'gbp-sysprof-workspace-addin.h',
 ])
 
 plugin_sysprof_resources = gnome.compile_resources(
@@ -21,4 +21,6 @@ plugin_sysprof_resources = gnome.compile_resources(
 
 plugins_sources += plugin_sysprof_resources
 
+install_data(['org.gnome.builder.sysprof.gschema.xml'], install_dir: schema_dir)
+
 endif
diff --git a/src/plugins/sysprof/org.gnome.builder.sysprof.gschema.xml 
b/src/plugins/sysprof/org.gnome.builder.sysprof.gschema.xml
new file mode 100644
index 000000000..b88e84c6e
--- /dev/null
+++ b/src/plugins/sysprof/org.gnome.builder.sysprof.gschema.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist>
+  <schema id="org.gnome.builder.sysprof" path="/org/gnome/builder/sysprof/" gettext-domain="gnome-builder">
+    <key type="b" name="cpu-aid"><default>true</default></key>
+    <key type="b" name="perf-aid"><default>true</default></key>
+    <key type="b" name="memory-aid"><default>true</default></key>
+    <key type="b" name="memprof-aid"><default>false</default></key>
+    <key type="b" name="diskstat-aid"><default>true</default></key>
+    <key type="b" name="netstat-aid"><default>true</default></key>
+    <key type="b" name="energy-aid"><default>false</default></key>
+    <key type="b" name="battery-aid"><default>false</default></key>
+    <key type="b" name="compositor-aid"><default>false</default></key>
+    <key type="b" name="allow-throttle"><default>true</default></key>
+    <key type="b" name="allow-tracefd"><default>true</default></key>
+  </schema>
+</schemalist>
diff --git a/src/plugins/sysprof/sysprof-plugin.c b/src/plugins/sysprof/sysprof-plugin.c
index f403d1cde..6d6c97db3 100644
--- a/src/plugins/sysprof/sysprof-plugin.c
+++ b/src/plugins/sysprof/sysprof-plugin.c
@@ -1,6 +1,6 @@
 /* sysprof-plugin.c
  *
- * Copyright 2016-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2016-2022 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
@@ -23,9 +23,12 @@
 #include "config.h"
 
 #include <libpeas/peas.h>
-#include <libide-gui.h>
 #include <sysprof.h>
 
+#include <libide-gui.h>
+
+#include "gbp-sysprof-tool.h"
+#include "gbp-sysprof-workbench-addin.h"
 #include "gbp-sysprof-workspace-addin.h"
 
 _IDE_EXTERN void
@@ -33,6 +36,12 @@ _gbp_sysprof_register_types (PeasObjectModule *module)
 {
   sysprof_clock_init ();
 
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_RUN_TOOL,
+                                              GBP_TYPE_SYSPROF_TOOL);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_WORKBENCH_ADDIN,
+                                              GBP_TYPE_SYSPROF_WORKBENCH_ADDIN);
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_WORKSPACE_ADDIN,
                                               GBP_TYPE_SYSPROF_WORKSPACE_ADDIN);
diff --git a/src/plugins/sysprof/sysprof.gresource.xml b/src/plugins/sysprof/sysprof.gresource.xml
index 1d23d1167..ab5e8c9b5 100644
--- a/src/plugins/sysprof/sysprof.gresource.xml
+++ b/src/plugins/sysprof/sysprof.gresource.xml
@@ -3,7 +3,6 @@
   <gresource prefix="/plugins/sysprof">
     <file>sysprof.plugin</file>
     <file>gtk/menus.ui</file>
-    <file>themes/shared.css</file>
-    <file>gbp-sysprof-surface.ui</file>
+    <file>gtk/keybindings.json</file>
   </gresource>
 </gresources>
diff --git a/src/plugins/sysprof/sysprof.plugin b/src/plugins/sysprof/sysprof.plugin
index 4b4c07c40..276d5b51b 100644
--- a/src/plugins/sysprof/sysprof.plugin
+++ b/src/plugins/sysprof/sysprof.plugin
@@ -2,10 +2,10 @@
 Authors=Christian Hergert <christian hergert me>
 Builtin=true
 Copyright=Copyright © 2016-2018 Christian Hergert
-Depends=buildui;
-Description=Integration with the Sysprof system profiler
+Depends=buildui;project-tree;
+Description=Integrates a whole-system profiler using Sysprof
 Embedded=_gbp_sysprof_register_types
-Hidden=true
 Module=sysprof
 Name=Sysprof
+X-Category=debuggers
 X-Workspace-Kind=primary;


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