[gnome-builder/wip/chergert/sysprof: 16/18] sysprof: add sysprof profiling plugin



commit 75298f798136bdf6dc4d021968c3470f312216fd
Author: Christian Hergert <chergert redhat com>
Date:   Mon Aug 22 18:43:12 2016 -0700

    sysprof: add sysprof profiling plugin
    
    This is a basic plugin for Builder that provides profiling with the sysprof
    library. Sysprof has both a backend library (libsysprof-2) and a library
    for UI components (libsysprof-ui-2).
    
    This builds on those components and tries to merge the gap between
    launching your project and hooking up the profiler components. It is not
    yet as featureful as the standalone Sysprof UI, but simplifies the process
    of launching your target project.

 configure.ac                                  |    2 +
 plugins/Makefile.am                           |    1 +
 plugins/sysprof/Makefile.am                   |   37 +++
 plugins/sysprof/configure.ac                  |   21 ++
 plugins/sysprof/gbp-sysprof-perspective.c     |  184 +++++++++++
 plugins/sysprof/gbp-sysprof-perspective.h     |   36 +++
 plugins/sysprof/gbp-sysprof-perspective.ui    |   15 +
 plugins/sysprof/gbp-sysprof-plugin.c          |   30 ++
 plugins/sysprof/gbp-sysprof-workbench-addin.c |  409 +++++++++++++++++++++++++
 plugins/sysprof/gbp-sysprof-workbench-addin.h |   33 ++
 plugins/sysprof/gtk/menus.ui                  |   11 +
 plugins/sysprof/sysprof.gresource.xml         |    7 +
 plugins/sysprof/sysprof.plugin                |    7 +
 13 files changed, 793 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index c896021..8f09661 100644
--- a/configure.ac
+++ b/configure.ac
@@ -308,6 +308,7 @@ m4_include([plugins/run-tools/configure.ac])
 m4_include([plugins/support/configure.ac])
 m4_include([plugins/symbol-tree/configure.ac])
 m4_include([plugins/sysmon/configure.ac])
+m4_include([plugins/sysprof/configure.ac])
 m4_include([plugins/todo/configure.ac])
 m4_include([plugins/terminal/configure.ac])
 m4_include([plugins/vala-pack/configure.ac])
@@ -595,6 +596,7 @@ echo "  Python Language Pack ................. : ${enable_python_pack_plugin}"
 echo "  Run Tools ............................ : ${enable_run_tools_plugin}"
 echo "  Support .............................. : ${enable_support_plugin}"
 echo "  System Monitor ....................... : ${enable_sysmon_plugin}"
+echo "  Sysprof System Profiler .............. : ${enable_sysprof_plugin}"
 echo "  Symbol Tree .......................... : ${enable_symbol_tree_plugin}"
 echo "  Todo ................................. : ${enable_todo_plugin}"
 echo "  Terminal ............................. : ${enable_terminal_plugin}"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 0827d68..14b3b4b 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -31,6 +31,7 @@ SUBDIRS = \
        support \
        symbol-tree \
        sysmon \
+       sysprof \
        terminal \
        todo \
        vala-pack \
diff --git a/plugins/sysprof/Makefile.am b/plugins/sysprof/Makefile.am
new file mode 100644
index 0000000..27bc552
--- /dev/null
+++ b/plugins/sysprof/Makefile.am
@@ -0,0 +1,37 @@
+if ENABLE_SYSPROF_PLUGIN
+
+DISTCLEANFILES =
+BUILT_SOURCES =
+CLEANFILES =
+EXTRA_DIST = $(plugin_DATA)
+
+plugindir = $(libdir)/gnome-builder/plugins
+plugin_LTLIBRARIES = libsysprof-plugin.la
+dist_plugin_DATA = sysprof.plugin
+
+libsysprof_plugin_la_SOURCES = \
+       gbp-sysprof-plugin.c \
+       gbp-sysprof-perspective.c \
+       gbp-sysprof-perspective.h \
+       gbp-sysprof-workbench-addin.c \
+       gbp-sysprof-workbench-addin.h \
+       $(NULL)
+
+nodist_libsysprof_plugin_la_SOURCES = \
+       gbp-sysprof-resources.c \
+       gbp-sysprof-resources.h
+
+libsysprof_plugin_la_CFLAGS = $(PLUGIN_CFLAGS) $(SYSPROF_CFLAGS)
+libsysprof_plugin_la_LIBADD = $(PLUGIN_LIBS) $(SYSPROF_LIBS)
+
+glib_resources_c = gbp-sysprof-resources.c
+glib_resources_h = gbp-sysprof-resources.h
+glib_resources_xml = sysprof.gresource.xml
+glib_resources_namespace = gbp_sysprof
+include $(top_srcdir)/build/autotools/Makefile.am.gresources
+
+include $(top_srcdir)/plugins/Makefile.plugin
+
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/sysprof/configure.ac b/plugins/sysprof/configure.ac
new file mode 100644
index 0000000..657d385
--- /dev/null
+++ b/plugins/sysprof/configure.ac
@@ -0,0 +1,21 @@
+m4_define(sysprof_required_version, [3.20.1])
+
+PKG_CHECK_MODULES(SYSPROF, [sysprof-2 >= sysprof_required_version
+                           sysprof-ui-2 >= sysprof_required_version])
+
+# --enable-sysprof-plugin=yes/no
+AC_ARG_ENABLE([sysprof-plugin],
+              [AS_HELP_STRING([--enable-sysprof-plugin=@<:@yes/no@:>@],
+                              [Build with support for the Sysprof system profiler.])],
+              [enable_sysprof_plugin=$enableval],
+              [enable_sysprof_plugin=yes])
+
+AS_IF([test x$enable_sysprof_plugin = xyes && test x$have_sysprof_ui = xno],[
+       AC_MSG_ERROR([Failed to locate sysprof-ui dependencies. Try installing Sysprof with GTK support.])
+])
+
+# for if ENABLE_SYSPROF_PLUGIN in Makefile.am
+AM_CONDITIONAL(ENABLE_SYSPROF_PLUGIN, test x$enable_sysprof_plugin != xno)
+
+# Ensure our makefile is generated by autoconf
+AC_CONFIG_FILES([plugins/sysprof/Makefile])
diff --git a/plugins/sysprof/gbp-sysprof-perspective.c b/plugins/sysprof/gbp-sysprof-perspective.c
new file mode 100644
index 0000000..3928954
--- /dev/null
+++ b/plugins/sysprof/gbp-sysprof-perspective.c
@@ -0,0 +1,184 @@
+/* gbp-sysprof-perspective.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-sysprof-perspective"
+
+#include <glib/gi18n.h>
+#include <sysprof.h>
+#include <sysprof-ui.h>
+
+#include "gbp-sysprof-perspective.h"
+
+struct _GbpSysprofPerspective
+{
+  GtkBin           parent_instance;
+
+  SpCallgraphView *callgraph_view;
+};
+
+enum {
+  PROP_0,
+  N_PROPS
+};
+
+static void perspective_iface_init (IdePerspectiveInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GbpSysprofPerspective, gbp_sysprof_perspective, GTK_TYPE_BIN, 0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_PERSPECTIVE, perspective_iface_init))
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_sysprof_perspective_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gbp_sysprof_perspective_parent_class)->finalize (object);
+}
+
+static void
+gbp_sysprof_perspective_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+  GbpSysprofPerspective *self = GBP_SYSPROF_PERSPECTIVE (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_sysprof_perspective_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  GbpSysprofPerspective *self = GBP_SYSPROF_PERSPECTIVE (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_sysprof_perspective_class_init (GbpSysprofPerspectiveClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gbp_sysprof_perspective_finalize;
+  object_class->get_property = gbp_sysprof_perspective_get_property;
+  object_class->set_property = gbp_sysprof_perspective_set_property;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/sysprof-plugin/gbp-sysprof-perspective.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpSysprofPerspective, callgraph_view);
+
+  g_type_ensure (SP_TYPE_CALLGRAPH_VIEW);
+}
+
+static void
+gbp_sysprof_perspective_init (GbpSysprofPerspective *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static gchar *
+gbp_sysprof_perspective_get_icon_name (IdePerspective *perspective)
+{
+  return g_strdup ("utilities-system-monitor-symbolic");
+}
+
+static gchar *
+gbp_sysprof_perspective_get_title (IdePerspective *perspective)
+{
+  return g_strdup (_("Profiler"));
+}
+
+static gchar *
+gbp_sysprof_perspective_get_id (IdePerspective *perspective)
+{
+  return g_strdup ("profiler");
+}
+
+static gint
+gbp_sysprof_perspective_get_priority (IdePerspective *perspective)
+{
+  return 70000;
+}
+
+static gchar *
+gbp_sysprof_perspective_get_accelerator (IdePerspective *perspective)
+{
+  return g_strdup ("<Alt>2");
+}
+
+static void
+perspective_iface_init (IdePerspectiveInterface *iface)
+{
+  iface->get_icon_name = gbp_sysprof_perspective_get_icon_name;
+  iface->get_title = gbp_sysprof_perspective_get_title;
+  iface->get_id = gbp_sysprof_perspective_get_id;
+  iface->get_priority = gbp_sysprof_perspective_get_priority;
+  iface->get_accelerator = gbp_sysprof_perspective_get_accelerator;
+}
+
+static void
+generate_cb (GObject      *object,
+             GAsyncResult *result,
+             gpointer      user_data)
+{
+  SpCallgraphProfile *profile = (SpCallgraphProfile *)object;
+  g_autoptr(GbpSysprofPerspective) self = user_data;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (SP_IS_CALLGRAPH_PROFILE (profile));
+  g_assert (GBP_IS_SYSPROF_PERSPECTIVE (self));
+
+  if (!sp_profile_generate_finish (SP_PROFILE (profile), result, &error))
+    {
+      g_warning ("Failed to generate profile: %s", error->message);
+      return;
+    }
+
+  sp_callgraph_view_set_profile (self->callgraph_view, profile);
+}
+
+void
+gbp_sysprof_perspective_set_reader (GbpSysprofPerspective *self,
+                                    SpCaptureReader       *reader)
+{
+  g_autoptr(SpProfile) profile = NULL;
+
+  g_assert (GBP_IS_SYSPROF_PERSPECTIVE (self));
+
+  if (reader == NULL)
+    {
+      sp_callgraph_view_set_profile (self->callgraph_view, NULL);
+      return;
+    }
+
+  profile = sp_callgraph_profile_new ();
+
+  sp_profile_set_reader (profile, reader);
+
+  sp_profile_generate (profile, NULL, generate_cb, g_object_ref (self));
+}
diff --git a/plugins/sysprof/gbp-sysprof-perspective.h b/plugins/sysprof/gbp-sysprof-perspective.h
new file mode 100644
index 0000000..54355c4
--- /dev/null
+++ b/plugins/sysprof/gbp-sysprof-perspective.h
@@ -0,0 +1,36 @@
+/* gbp-sysprof-perspective.h
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GBP_SYSPROF_PERSPECTIVE_H
+#define GBP_SYSPROF_PERSPECTIVE_H
+
+#include <ide.h>
+#include <sysprof.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SYSPROF_PERSPECTIVE (gbp_sysprof_perspective_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpSysprofPerspective, gbp_sysprof_perspective, GBP, SYSPROF_PERSPECTIVE, GtkBin)
+
+void gbp_sysprof_perspective_set_reader (GbpSysprofPerspective *self,
+                                         SpCaptureReader       *reader);
+
+G_END_DECLS
+
+#endif /* GBP_SYSPROF_PERSPECTIVE_H */
diff --git a/plugins/sysprof/gbp-sysprof-perspective.ui b/plugins/sysprof/gbp-sysprof-perspective.ui
new file mode 100644
index 0000000..253f51b
--- /dev/null
+++ b/plugins/sysprof/gbp-sysprof-perspective.ui
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpSysprofPerspective" parent="GtkBin">
+    <child>
+      <object class="GtkStack">
+        <property name="visible">true</property>
+        <child>
+          <object class="SpCallgraphView" id="callgraph_view">
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/plugins/sysprof/gbp-sysprof-plugin.c b/plugins/sysprof/gbp-sysprof-plugin.c
new file mode 100644
index 0000000..987ff07
--- /dev/null
+++ b/plugins/sysprof/gbp-sysprof-plugin.c
@@ -0,0 +1,30 @@
+/* gbp-sysprof-plugin.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libpeas/peas.h>
+#include <ide.h>
+
+#include "gbp-sysprof-workbench-addin.h"
+
+void
+peas_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_WORKBENCH_ADDIN,
+                                              GBP_TYPE_SYSPROF_WORKBENCH_ADDIN);
+}
diff --git a/plugins/sysprof/gbp-sysprof-workbench-addin.c b/plugins/sysprof/gbp-sysprof-workbench-addin.c
new file mode 100644
index 0000000..85c3365
--- /dev/null
+++ b/plugins/sysprof/gbp-sysprof-workbench-addin.c
@@ -0,0 +1,409 @@
+/* gbp-sysprof-workbench-addin.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+#include <sysprof.h>
+
+#include "gbp-sysprof-perspective.h"
+#include "gbp-sysprof-workbench-addin.h"
+
+struct _GbpSysprofWorkbenchAddin
+{
+  GObject                parent_instance;
+
+  GSimpleActionGroup    *actions;
+  SpProfiler            *profiler;
+
+  GbpSysprofPerspective *perspective;
+  IdeWorkbench          *workbench;
+};
+
+static void workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GbpSysprofWorkbenchAddin, gbp_sysprof_workbench_addin, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKBENCH_ADDIN, workbench_addin_iface_init))
+
+static void
+profiler_stopped (GbpSysprofWorkbenchAddin *self,
+                  SpProfiler               *profiler)
+{
+  g_autoptr(SpCaptureReader) reader = NULL;
+  g_autoptr(GError) error = NULL;
+  SpCaptureWriter *writer;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_return_if_fail (SP_IS_PROFILER (profiler));
+
+  if (self->profiler != profiler)
+    IDE_EXIT;
+
+  if (self->workbench == NULL)
+    IDE_EXIT;
+
+  writer = sp_profiler_get_writer (profiler);
+  reader = sp_capture_writer_create_reader (writer, &error);
+
+  if (reader == NULL)
+    {
+      /* TODO: Propagate error to an infobar or similar */
+      g_warning ("%s", error->message);
+      IDE_EXIT;
+    }
+
+  gbp_sysprof_perspective_set_reader (self->perspective, reader);
+
+  ide_workbench_set_visible_perspective_name (self->workbench, "profiler");
+
+  IDE_EXIT;
+}
+
+static void
+profiler_child_spawned (GbpSysprofWorkbenchAddin *self,
+                        const gchar              *identifier,
+                        IdeRunner                *runner)
+{
+  GPid pid = 0;
+
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (identifier != NULL);
+  g_assert (IDE_IS_RUNNER (runner));
+
+  if (!SP_IS_PROFILER (self->profiler))
+    return;
+
+#ifdef G_OS_UNIX
+  pid = g_ascii_strtoll (identifier, NULL, 10);
+#endif
+
+  if G_UNLIKELY (pid == 0)
+    {
+      g_warning ("Failed to parse integer value from %s", identifier);
+      return;
+    }
+
+  IDE_TRACE_MSG ("Adding pid %s to profiler", identifier);
+
+  sp_profiler_add_pid (self->profiler, pid);
+  sp_profiler_start (self->profiler);
+}
+
+static void
+profiler_run_handler (IdeRunManager *run_manager,
+                      IdeRunner     *runner,
+                      gpointer       user_data)
+{
+  GbpSysprofWorkbenchAddin *self = user_data;
+  g_autoptr(SpSource) proc_source = NULL;
+  g_autoptr(SpSource) perf_source = NULL;
+
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_RUNNER (runner));
+  g_assert (IDE_IS_RUN_MANAGER (run_manager));
+
+  if (SP_IS_PROFILER (self->profiler))
+    {
+      if (sp_profiler_get_is_running (self->profiler))
+        sp_profiler_stop (self->profiler);
+      g_clear_object (&self->profiler);
+    }
+
+  self->profiler = sp_local_profiler_new ();
+
+  sp_profiler_set_whole_system (SP_PROFILER (self->profiler), FALSE);
+
+  proc_source = sp_proc_source_new ();
+  sp_profiler_add_source (self->profiler, proc_source);
+
+  perf_source = sp_perf_source_new ();
+  sp_profiler_add_source (self->profiler, perf_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),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self->profiler,
+                           "stopped",
+                           G_CALLBACK (profiler_stopped),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+gbp_sysprof_workbench_addin_open_cb (GObject      *object,
+                                     GAsyncResult *result,
+                                     gpointer      user_data)
+{
+  GbpSysprofWorkbenchAddin *self = (GbpSysprofWorkbenchAddin *)object;
+  g_autoptr(SpCaptureReader) reader = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_TASK (result));
+
+  reader = g_task_propagate_pointer (G_TASK (result), &error);
+
+  g_assert (reader || error != NULL);
+
+  if (reader == NULL)
+    {
+      g_message ("%s", error->message);
+      return;
+    }
+
+  gbp_sysprof_perspective_set_reader (self->perspective, reader);
+}
+
+static void
+gbp_sysprof_workbench_addin_open_worker (GTask        *task,
+                                         gpointer      source_object,
+                                         gpointer      task_data,
+                                         GCancellable *cancellable)
+{
+  GbpSysprofWorkbenchAddin *self = source_object;
+  g_autofree gchar *path = NULL;
+  SpCaptureReader *reader;
+  GFile *file = task_data;
+  GError *error = NULL;
+
+  g_assert (G_IS_TASK (task));
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_FILE (file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  path = g_file_get_path (file);
+
+  if (NULL == (reader = sp_capture_reader_new (path, &error)))
+    {
+      g_assert (error != NULL);
+      g_task_return_error (task, error);
+      return;
+    }
+
+  g_task_return_pointer (task, reader, (GDestroyNotify)sp_capture_reader_unref);
+}
+
+static void
+gbp_sysprof_workbench_addin_open (GbpSysprofWorkbenchAddin *self,
+                                  GFile                    *file)
+{
+  g_autoptr(GTask) task = NULL;
+
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_FILE (file));
+
+  if (!g_file_is_native (file))
+    {
+      g_warning ("Can only open local sysprof capture files.");
+      return;
+    }
+
+  task = g_task_new (self, NULL, gbp_sysprof_workbench_addin_open_cb, NULL);
+  g_task_set_task_data (task, g_object_ref (file), g_object_unref);
+  g_task_run_in_thread (task, gbp_sysprof_workbench_addin_open_worker);
+}
+
+static void
+open_profile_action (GSimpleAction *action,
+                     GVariant      *variant,
+                     gpointer       user_data)
+{
+  GbpSysprofWorkbenchAddin *self = user_data;
+  GtkFileChooserNative *native;
+  GtkFileFilter *filter;
+  gint ret;
+
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (self->workbench));
+  g_assert (GBP_IS_SYSPROF_PERSPECTIVE (self->perspective));
+
+  ide_workbench_set_visible_perspective (self->workbench, IDE_PERSPECTIVE (self->perspective));
+
+  native = gtk_file_chooser_native_new (_("Open Profile"),
+                                        GTK_WINDOW (self->workbench),
+                                        GTK_FILE_CHOOSER_ACTION_OPEN,
+                                        _("Open"),
+                                        _("Cancel"));
+
+  /* Add our filter for sysprof capture files.  */
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Sysprof Capture (*.syscap)"));
+  gtk_file_filter_add_pattern (filter, "*.syscap");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
+
+  /* And all files now */
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("All Files"));
+  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));
+
+  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_workbench_addin_open (self, file);
+    }
+
+  gtk_native_dialog_hide (GTK_NATIVE_DIALOG (native));
+  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
+}
+
+static void
+gbp_sysprof_workbench_addin_finalize (GObject *object)
+{
+  GbpSysprofWorkbenchAddin *self = (GbpSysprofWorkbenchAddin *)object;
+
+  g_clear_object (&self->actions);
+
+  G_OBJECT_CLASS (gbp_sysprof_workbench_addin_parent_class)->finalize (object);
+}
+
+static void
+gbp_sysprof_workbench_addin_class_init (GbpSysprofWorkbenchAddinClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_sysprof_workbench_addin_finalize;
+}
+
+static void
+gbp_sysprof_workbench_addin_init (GbpSysprofWorkbenchAddin *self)
+{
+  static const GActionEntry entries[] = {
+    { "open-profile", open_profile_action },
+  };
+
+  self->actions = g_simple_action_group_new ();
+
+  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+                                   entries,
+                                   G_N_ELEMENTS (entries),
+                                   self);
+}
+
+static void
+run_manager_stopped (GbpSysprofWorkbenchAddin *self,
+                     IdeRunManager            *run_manager)
+{
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_RUN_MANAGER (run_manager));
+
+  if (self->profiler != NULL && sp_profiler_get_is_running (self->profiler))
+    sp_profiler_stop (self->profiler);
+}
+
+static void
+gbp_sysprof_workbench_addin_load (IdeWorkbenchAddin *addin,
+                                  IdeWorkbench      *workbench)
+{
+  GbpSysprofWorkbenchAddin *self = (GbpSysprofWorkbenchAddin *)addin;
+  IdeRunManager *run_manager;
+  IdeContext *context;
+
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  self->workbench = workbench;
+
+  context = ide_workbench_get_context (workbench);
+
+  /*
+   * Register our custom run handler to activate the profiler.
+   */
+  run_manager = ide_context_get_run_manager (context);
+  ide_run_manager_add_handler (run_manager,
+                               "profiler",
+                               _("Profile"),
+                               "utilities-system-monitor-symbolic",
+                               "<Control>F8",
+                               profiler_run_handler,
+                               self,
+                               NULL);
+  g_signal_connect_object (run_manager,
+                           "stopped",
+                           G_CALLBACK (run_manager_stopped),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  /*
+   * Add the perspcetive to the workbench.
+   */
+  self->perspective = g_object_new (GBP_TYPE_SYSPROF_PERSPECTIVE,
+                                    "visible", TRUE,
+                                    NULL);
+  ide_workbench_add_perspective (workbench, IDE_PERSPECTIVE (self->perspective));
+
+
+  /*
+   * Add our actions to the workbench so they can be activated via the
+   * headerbar or the perspective.
+   */
+  gtk_widget_insert_action_group (GTK_WIDGET (workbench),
+                                  "profiler",
+                                  G_ACTION_GROUP (self->actions));
+}
+
+static void
+gbp_sysprof_workbench_addin_unload (IdeWorkbenchAddin *addin,
+                                    IdeWorkbench      *workbench)
+{
+  GbpSysprofWorkbenchAddin *self = (GbpSysprofWorkbenchAddin *)addin;
+  IdeRunManager *run_manager;
+  IdeContext *context;
+
+  g_assert (GBP_IS_SYSPROF_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  context = ide_workbench_get_context (workbench);
+
+  run_manager = ide_context_get_run_manager (context);
+  ide_run_manager_remove_handler (run_manager, "profiler");
+
+  ide_workbench_remove_perspective (workbench, IDE_PERSPECTIVE (self->perspective));
+
+  self->perspective = NULL;
+  self->workbench = NULL;
+}
+
+static void
+workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
+{
+  iface->load = gbp_sysprof_workbench_addin_load;
+  iface->unload = gbp_sysprof_workbench_addin_unload;
+}
diff --git a/plugins/sysprof/gbp-sysprof-workbench-addin.h b/plugins/sysprof/gbp-sysprof-workbench-addin.h
new file mode 100644
index 0000000..3df3d93
--- /dev/null
+++ b/plugins/sysprof/gbp-sysprof-workbench-addin.h
@@ -0,0 +1,33 @@
+/* gbp-sysprof-workbench-addin.h
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GBP_SYSPROF_WORKBENCH_ADDIN_H
+#define GBP_SYSPROF_WORKBENCH_ADDIN_H
+
+#include <ide.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
+
+#endif /* GBP_SYSPROF_WORKBENCH_ADDIN_H */
+
diff --git a/plugins/sysprof/gtk/menus.ui b/plugins/sysprof/gtk/menus.ui
new file mode 100644
index 0000000..6004cef
--- /dev/null
+++ b/plugins/sysprof/gtk/menus.ui
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<interface>
+  <menu id="gear-menu">
+    <section id="gear-menu-open-section">
+      <item>
+        <attribute name="label" translatable="yes">Open Profile…</attribute>
+        <attribute name="action">profiler.open-profile</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>
diff --git a/plugins/sysprof/sysprof.gresource.xml b/plugins/sysprof/sysprof.gresource.xml
new file mode 100644
index 0000000..2695fd8
--- /dev/null
+++ b/plugins/sysprof/sysprof.gresource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/builder/plugins/sysprof-plugin">
+    <file>gtk/menus.ui</file>
+    <file>gbp-sysprof-perspective.ui</file>
+  </gresource>
+</gresources>
diff --git a/plugins/sysprof/sysprof.plugin b/plugins/sysprof/sysprof.plugin
new file mode 100644
index 0000000..784959d
--- /dev/null
+++ b/plugins/sysprof/sysprof.plugin
@@ -0,0 +1,7 @@
+[Plugin]
+Module=sysprof-plugin
+Name=Sysprof
+Description=Integration with the Sysprof system profiler
+Authors=Christian Hergert <christian hergert me>
+Copyright=Copyright © 2016 Christian Hergert
+Builtin=true


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