[sysprof/wip/chergert/compare] wip: cost change calculation



commit 50903553e2313feb4e329dd6a8d9a179d79e057d
Author: Christian Hergert <chergert redhat com>
Date:   Sun Dec 4 00:15:09 2016 -0800

    wip: cost change calculation

 .gitignore                            |    1 +
 Makefile.am                           |    1 +
 lib/resources/ui/sp-callgraph-view.ui |   12 +++
 lib/sp-callgraph-profile.c            |   34 +++++--
 lib/sp-callgraph-profile.h            |    2 +
 lib/sp-callgraph-view.c               |  164 +++++++++++++++++++++++++++++----
 lib/sp-callgraph-view.h               |    2 +
 lib/sp-cell-renderer-percent.c        |   57 +++++++++++-
 lib/sp-cell-renderer-percent.h        |   13 ++-
 src/resources/ui/sp-window.ui         |   14 +++
 src/sp-window.c                       |  161 +++++++++++++++++++++++++++-----
 11 files changed, 401 insertions(+), 60 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 3a11aad..bada439 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@
 /TAGS
 /aclocal.m4
 /autom4te.cache
+/build
 /build-aux
 /config
 /config.cache
diff --git a/Makefile.am b/Makefile.am
index 3c8802c..bc7a60e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,6 +35,7 @@ GITIGNOREFILES = \
        ABOUT-NLS \
        aclocal.m4 \
        build-aux \
+       build \
        ChangeLog \
        config \
        config.h.in \
diff --git a/lib/resources/ui/sp-callgraph-view.ui b/lib/resources/ui/sp-callgraph-view.ui
index 67cb120..d6e11ab 100644
--- a/lib/resources/ui/sp-callgraph-view.ui
+++ b/lib/resources/ui/sp-callgraph-view.ui
@@ -149,6 +149,18 @@
                   </object>
                 </child>
                 <child>
+                  <object class="GtkTreeViewColumn" id="change_column">
+                    <property name="expand">false</property>
+                    <property name="title" translatable="yes">Change</property>
+                    <property name="visible">false</property>
+                    <child>
+                      <object class="SpCellRendererPercent" id="change_cell">
+                        <property name="ignore-zero">true</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
                   <object class="GtkTreeViewColumn" id="descendants_self_column">
                     <property name="expand">false</property>
                     <property name="sizing">fixed</property>
diff --git a/lib/sp-callgraph-profile.c b/lib/sp-callgraph-profile.c
index 57b0939..703467f 100644
--- a/lib/sp-callgraph-profile.c
+++ b/lib/sp-callgraph-profile.c
@@ -54,19 +54,19 @@
 
 struct _SpCallgraphProfile
 {
-  GObject                parent_instance;
+  GObject          parent_instance;
 
-  SpCaptureReader       *reader;
-  SpSelection *selection;
-  StackStash            *stash;
-  GStringChunk          *symbols;
-  GHashTable            *tags;
+  SpCaptureReader *reader;
+  SpSelection     *selection;
+  StackStash      *stash;
+  GStringChunk    *symbols;
+  GHashTable      *tags;
 };
 
 typedef struct
 {
-  SpCaptureReader       *reader;
-  SpSelection *selection;
+  SpCaptureReader *reader;
+  SpSelection     *selection;
 } Generate;
 
 static void profile_iface_init (SpProfileInterface *iface);
@@ -504,3 +504,21 @@ sp_callgraph_profile_get_tag (SpCallgraphProfile *self,
 
   return GPOINTER_TO_SIZE (g_hash_table_lookup (self->tags, symbol));
 }
+
+gpointer
+sp_callgraph_profile_resolve_name (SpCallgraphProfile *self,
+                                   const gchar        *name)
+{
+  GHashTable *const_table;
+
+  g_return_val_if_fail (SP_IS_CALLGRAPH_PROFILE (self), 0);
+
+  /*
+   * XXX: This is a total hack until we implement string chunk
+   *      with our own fronting hsahtable. But we know the hashtable
+   *      is the first field of the structure.
+   */
+  const_table = *(GHashTable **)self->symbols;
+
+  return g_hash_table_lookup (const_table, name);
+}
diff --git a/lib/sp-callgraph-profile.h b/lib/sp-callgraph-profile.h
index e034748..98eeac5 100644
--- a/lib/sp-callgraph-profile.h
+++ b/lib/sp-callgraph-profile.h
@@ -32,6 +32,8 @@ SpProfile *sp_callgraph_profile_new                (void);
 SpProfile *sp_callgraph_profile_new_with_selection (SpSelection        *selection);
 GQuark     sp_callgraph_profile_get_tag            (SpCallgraphProfile *self,
                                                     const gchar        *symbol);
+gpointer   sp_callgraph_profile_resolve_name       (SpCallgraphProfile *self,
+                                                    const gchar        *name);
 
 G_END_DECLS
 
diff --git a/lib/sp-callgraph-view.c b/lib/sp-callgraph-view.c
index 8ea1683..e5d6c25 100644
--- a/lib/sp-callgraph-view.c
+++ b/lib/sp-callgraph-view.c
@@ -43,16 +43,21 @@
 
 typedef struct
 {
-  SpCallgraphProfile  *profile;
+  SpCallgraphProfile    *profile;
+  SpCallgraphProfile    *compare_to;
 
-  GtkTreeView         *callers_view;
-  GtkTreeView         *functions_view;
-  GtkTreeView         *descendants_view;
-  GtkTreeViewColumn   *descendants_name_column;
+  GtkTreeView           *callers_view;
+  GtkTreeView           *functions_view;
+  GtkTreeView           *descendants_view;
+  GtkTreeViewColumn     *descendants_name_column;
 
-  GQueue              *history;
+  GtkTreeViewColumn     *change_column;
+  SpCellRendererPercent *change_cell;
 
-  guint                profile_size;
+  GQueue                *history;
+
+  guint                  profile_size;
+  guint                  compare_size;
 } SpCallgraphViewPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (SpCallgraphView, sp_callgraph_view, GTK_TYPE_BIN)
@@ -109,6 +114,33 @@ sp_callgraph_view_get_profile_size (SpCallgraphView *self)
   return size;
 }
 
+static guint
+sp_callgraph_view_get_compare_to_size (SpCallgraphView *self)
+{
+  SpCallgraphViewPrivate *priv = sp_callgraph_view_get_instance_private (self);
+  StackStash *stash;
+  StackNode *node;
+  guint size = 0;
+
+  g_assert (SP_IS_CALLGRAPH_VIEW (self));
+
+  if (priv->compare_size != 0)
+    return priv->compare_size;
+
+  if (priv->compare_to == NULL)
+    return 0;
+
+  if (NULL == (stash = sp_callgraph_profile_get_stash (priv->compare_to)))
+    return 0;
+
+  for (node = stack_stash_get_root (stash); node != NULL; node = node->siblings)
+    size += node->total;
+
+  priv->compare_size = size;
+
+  return size;
+}
+
 static void
 build_functions_store (StackNode *node,
                        gpointer   user_data)
@@ -750,9 +782,11 @@ sp_callgraph_view_class_init (SpCallgraphViewClass *klass)
                                                "/org/gnome/sysprof/ui/sp-callgraph-view.ui");
 
   gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, callers_view);
-  gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, functions_view);
-  gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, descendants_view);
+  gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, change_cell);
+  gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, change_column);
   gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, descendants_name_column);
+  gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, descendants_view);
+  gtk_widget_class_bind_template_child_private (widget_class, SpCallgraphView, functions_view);
 
   bindings = gtk_binding_set_by_class (klass);
   gtk_binding_entry_add_signal (bindings, GDK_KEY_Left, GDK_MOD1_MASK, "go-previous", 0);
@@ -965,19 +999,18 @@ sp_callgraph_view_update_descendants (SpCallgraphView *self,
                               G_TYPE_POINTER);
 
   if (priv->profile != NULL)
-  {
-    StackStash *stash;
+    {
+      StackStash *stash = sp_callgraph_profile_get_stash (priv->profile);
 
-    stash = sp_callgraph_profile_get_stash (priv->profile);
-    if (stash != NULL)
-      {
-        Descendant *tree;
+      if (stash != NULL)
+        {
+          Descendant *tree;
 
-        tree = build_tree (node);
-        if (tree != NULL)
-          append_to_tree_and_free (self, stash, store, tree, NULL);
-      }
-  }
+          tree = build_tree (node);
+          if (tree != NULL)
+            append_to_tree_and_free (self, stash, store, tree, NULL);
+        }
+    }
 
   gtk_tree_view_set_model (priv->descendants_view, GTK_TREE_MODEL (store));
   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
@@ -1081,3 +1114,94 @@ sp_callgraph_view_get_n_functions (SpCallgraphView *self)
 
   return ret;
 }
+
+static gboolean
+nodes_equal (StackNode *node,
+             StackNode *other)
+{
+  return TRUE;
+}
+
+static StackNode *
+find_compare_to_node (SpCallgraphView *self,
+                      StackNode       *node)
+{
+  SpCallgraphViewPrivate *priv = sp_callgraph_view_get_instance_private (self);
+  StackStash *other;
+  StackNode *iter;
+  gpointer resolved;
+
+  other = sp_callgraph_profile_get_stash (priv->compare_to);
+  resolved = sp_callgraph_profile_resolve_name (priv->compare_to, (const gchar *)node->data);
+
+  if (resolved == 0)
+    return NULL;
+
+  iter = stack_stash_find_node (other, resolved);
+
+  if (iter == NULL)
+    return NULL;
+
+  for (; iter != NULL; iter = iter->next)
+    {
+      if (nodes_equal (node, iter))
+        return iter;
+    }
+
+  return NULL;
+}
+
+static void
+compare_profiles_cell_data_func (GtkTreeViewColumn *tree_column,
+                                 GtkCellRenderer   *cell,
+                                 GtkTreeModel      *model,
+                                 GtkTreeIter       *iter,
+                                 gpointer           user_data)
+{
+  SpCallgraphView *self = user_data;
+  StackNode *node = NULL;
+  gdouble change = 0.0;
+  gdouble total = 0.0;
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_POINTER, &node,
+                      COLUMN_TOTAL, &total,
+                      -1);
+
+  if G_LIKELY (node != NULL)
+    {
+      StackNode *compare_to_node = find_compare_to_node (self, node);
+      guint profile_size = sp_callgraph_view_get_compare_to_size (self);
+
+      if (compare_to_node != NULL)
+        {
+          gdouble other_total = 100 * compare_to_node->total / (gdouble)profile_size;
+
+          //g_print ("%lf %lf\n", total, other_total);
+
+          change = total - other_total;
+        }
+    }
+
+  sp_cell_renderer_percent_set_percent (SP_CELL_RENDERER_PERCENT (cell), change);
+}
+
+void
+sp_callgraph_view_compare_to (SpCallgraphView    *self,
+                              SpCallgraphProfile *compare_to)
+{
+  SpCallgraphViewPrivate *priv = sp_callgraph_view_get_instance_private (self);
+
+  g_return_if_fail (SP_IS_CALLGRAPH_VIEW (self));
+  g_return_if_fail (SP_IS_CALLGRAPH_PROFILE (compare_to));
+
+  if (g_set_object (&priv->compare_to, compare_to))
+    {
+      gtk_tree_view_column_set_visible (priv->change_column, TRUE);
+      gtk_tree_view_column_set_cell_data_func (priv->change_column,
+                                               GTK_CELL_RENDERER (priv->change_cell),
+                                               compare_profiles_cell_data_func,
+                                               self,
+                                               NULL);
+    }
+}
diff --git a/lib/sp-callgraph-view.h b/lib/sp-callgraph-view.h
index 40495ee..aed8277 100644
--- a/lib/sp-callgraph-view.h
+++ b/lib/sp-callgraph-view.h
@@ -42,6 +42,8 @@ GtkWidget          *sp_callgraph_view_new             (void);
 SpCallgraphProfile *sp_callgraph_view_get_profile     (SpCallgraphView    *self);
 void                sp_callgraph_view_set_profile     (SpCallgraphView    *self,
                                                        SpCallgraphProfile *profile);
+void                sp_callgraph_view_compare_to      (SpCallgraphView    *self,
+                                                       SpCallgraphProfile *compare_to);
 gchar              *sp_callgraph_view_screenshot      (SpCallgraphView    *self);
 guint               sp_callgraph_view_get_n_functions (SpCallgraphView    *self);
 
diff --git a/lib/sp-cell-renderer-percent.c b/lib/sp-cell-renderer-percent.c
index 4f5fe2b..178d00f 100644
--- a/lib/sp-cell-renderer-percent.c
+++ b/lib/sp-cell-renderer-percent.c
@@ -23,11 +23,13 @@
 typedef struct
 {
   gdouble percent;
+  guint ignore_zero : 1;
 } SpCellRendererPercentPrivate;
 
 enum {
   PROP_0,
   PROP_PERCENT,
+  PROP_IGNORE_ZERO,
   N_PROPS
 };
 
@@ -49,6 +51,10 @@ sp_cell_renderer_percent_get_property (GObject    *object,
       g_value_set_double (value, sp_cell_renderer_percent_get_percent (self));
       break;
 
+    case PROP_IGNORE_ZERO:
+      g_value_set_boolean (value, sp_cell_renderer_percent_get_ignore_zero (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -68,6 +74,10 @@ sp_cell_renderer_percent_set_property (GObject      *object,
       sp_cell_renderer_percent_set_percent (self, g_value_get_double (value));
       break;
 
+    case PROP_IGNORE_ZERO:
+      sp_cell_renderer_percent_set_ignore_zero (self, g_value_get_boolean (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -90,6 +100,13 @@ sp_cell_renderer_percent_class_init (SpCellRendererPercentClass *klass)
                          0.0,
                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_IGNORE_ZERO] =
+    g_param_spec_boolean ("ignore-zero",
+                          "Ignore Zero",
+                          "If Zero should be rendered as empty",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
@@ -116,7 +133,7 @@ sp_cell_renderer_percent_set_percent (SpCellRendererPercent *self,
   SpCellRendererPercentPrivate *priv = sp_cell_renderer_percent_get_instance_private (self);
 
   g_return_if_fail (SP_IS_CELL_RENDERER_PERCENT (self));
-  g_return_if_fail (percent >= 0.0);
+  g_return_if_fail (percent >= -100.0);
   g_return_if_fail (percent <= 100.0);
 
   if (percent != priv->percent)
@@ -125,11 +142,45 @@ sp_cell_renderer_percent_set_percent (SpCellRendererPercent *self,
 
       priv->percent = percent;
 
-      g_snprintf (text, sizeof text, "%.2lf<span size='smaller'><span size='smaller'> </span>%%</span>", 
percent);
-      text [sizeof text - 1] = '\0';
+      if (priv->percent != 0.0 || !priv->ignore_zero)
+        {
+          g_snprintf (text, sizeof text, "%.2lf<span size='smaller'><span size='smaller'> </span>%%</span>", 
percent);
+          text [sizeof text - 1] = '\0';
+        }
+      else
+        {
+          text[0] = '\0';
+        }
 
       g_object_set (self, "markup", text, NULL);
 
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PERCENT]);
     }
 }
+
+gboolean
+sp_cell_renderer_percent_get_ignore_zero (SpCellRendererPercent *self)
+{
+  SpCellRendererPercentPrivate *priv = sp_cell_renderer_percent_get_instance_private (self);
+
+  g_return_val_if_fail (SP_IS_CELL_RENDERER_PERCENT (self), FALSE);
+
+  return priv->ignore_zero;
+}
+
+void
+sp_cell_renderer_percent_set_ignore_zero (SpCellRendererPercent *self,
+                                          gboolean               ignore_zero)
+{
+  SpCellRendererPercentPrivate *priv = sp_cell_renderer_percent_get_instance_private (self);
+
+  g_return_if_fail (SP_IS_CELL_RENDERER_PERCENT (self));
+
+  ignore_zero = !!ignore_zero;
+
+  if (ignore_zero != priv->ignore_zero)
+    {
+      priv->ignore_zero = ignore_zero;
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IGNORE_ZERO]);
+    }
+}
diff --git a/lib/sp-cell-renderer-percent.h b/lib/sp-cell-renderer-percent.h
index 5a21fdc..7bbea75 100644
--- a/lib/sp-cell-renderer-percent.h
+++ b/lib/sp-cell-renderer-percent.h
@@ -46,11 +46,14 @@ struct _SpCellRendererPercentClass
   gpointer padding[4];
 };
 
-GType            sp_cell_renderer_percent_get_type    (void);
-GtkCellRenderer *sp_cell_renderer_percent_new         (void);
-gdouble          sp_cell_renderer_percent_get_percent (SpCellRendererPercent *self);
-void             sp_cell_renderer_percent_set_percent (SpCellRendererPercent *self,
-                                                       gdouble                percent);
+GType            sp_cell_renderer_percent_get_type        (void);
+GtkCellRenderer *sp_cell_renderer_percent_new             (void);
+gboolean         sp_cell_renderer_percent_get_ignore_zero (SpCellRendererPercent *self);
+void             sp_cell_renderer_percent_set_ignore_zero (SpCellRendererPercent *self,
+                                                           gboolean               ignore_zero);
+gdouble          sp_cell_renderer_percent_get_percent     (SpCellRendererPercent *self);
+void             sp_cell_renderer_percent_set_percent     (SpCellRendererPercent *self,
+                                                           gdouble                percent);
 
 G_END_DECLS
 
diff --git a/src/resources/ui/sp-window.ui b/src/resources/ui/sp-window.ui
index 005c31e..21689e4 100644
--- a/src/resources/ui/sp-window.ui
+++ b/src/resources/ui/sp-window.ui
@@ -280,6 +280,20 @@
         </child>
         <child>
           <object class="GtkModelButton">
+            <property name="action-name">win.compare-capture</property>
+            <property name="text" translatable="yes">Open for comparison</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkSeparator">
+            <property name="orientation">horizontal</property>
+            <property name="margin-top">6</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkModelButton">
             <property name="action-name">win.save-capture</property>
             <property name="text" translatable="yes">Save As</property>
             <property name="visible">true</property>
diff --git a/src/sp-window.c b/src/sp-window.c
index 9e1569f..b22dae6 100644
--- a/src/sp-window.c
+++ b/src/sp-window.c
@@ -76,8 +76,10 @@ enum {
 
 static guint signals [N_SIGNALS];
 
-static void sp_window_set_profiler (SpWindow   *self,
-                                    SpProfiler *profiler);
+static void sp_window_set_profiler    (SpWindow   *self,
+                                       SpProfiler *profiler);
+static void sp_window_compare_to_file (SpWindow   *self,
+                                       GFile      *file);
 
 static void
 sp_window_notify_user (SpWindow       *self,
@@ -153,6 +155,42 @@ sp_window_update_stats (gpointer data)
   return G_SOURCE_CONTINUE;
 }
 
+static GFile *
+sp_window_request_file (SpWindow    *self,
+                        const gchar *title)
+{
+  GtkFileChooserNative *dialog;
+  GtkFileFilter *filter;
+  GFile *ret = NULL;
+  gint response;
+
+  g_assert (SP_IS_WINDOW (self));
+
+  dialog = gtk_file_chooser_native_new (title,
+                                        GTK_WINDOW (self),
+                                        GTK_FILE_CHOOSER_ACTION_OPEN,
+                                        _("Open"),
+                                        _("Cancel"));
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Sysprof Captures"));
+  gtk_file_filter_add_pattern (filter, "*.syscap");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  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 (dialog), filter);
+
+  response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
+
+  if (response == GTK_RESPONSE_ACCEPT)
+    ret = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+
+  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (dialog));
+
+  return ret;
+}
 
 static void
 sp_window_update_subtitle (SpWindow *self)
@@ -315,6 +353,7 @@ sp_window_set_state (SpWindow      *self,
       gtk_widget_set_visible (GTK_WIDGET (self->stat_label), FALSE);
       g_clear_pointer (&self->reader, sp_capture_reader_unref);
       sp_window_action_set (self, "close-capture", "enabled", FALSE, NULL);
+      sp_window_action_set (self, "compare-capture", "enabled", FALSE, NULL);
       sp_window_action_set (self, "save-capture", "enabled", FALSE, NULL);
       sp_window_action_set (self, "screenshot", "enabled", FALSE, NULL);
       profiler = sp_local_profiler_new ();
@@ -332,6 +371,7 @@ sp_window_set_state (SpWindow      *self,
       g_clear_pointer (&self->reader, sp_capture_reader_unref);
       sp_callgraph_view_set_profile (self->callgraph_view, NULL);
       sp_window_action_set (self, "close-capture", "enabled", FALSE, NULL);
+      sp_window_action_set (self, "compare-capture", "enabled", FALSE, NULL);
       sp_window_action_set (self, "save-capture", "enabled", FALSE, NULL);
       sp_window_action_set (self, "screenshot", "enabled", FALSE, NULL);
       break;
@@ -340,6 +380,7 @@ sp_window_set_state (SpWindow      *self,
       gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), FALSE);
       gtk_label_set_label (self->subtitle, _("Building profileā€¦"));
       sp_window_action_set (self, "close-capture", "enabled", FALSE, NULL);
+      sp_window_action_set (self, "compare-capture", "enabled", FALSE, NULL);
       sp_window_action_set (self, "save-capture", "enabled", FALSE, NULL);
       sp_window_action_set (self, "screenshot", "enabled", FALSE, NULL);
       sp_window_build_profile (self);
@@ -355,6 +396,7 @@ sp_window_set_state (SpWindow      *self,
       sp_window_update_stats (self);
       sp_window_update_subtitle (self);
       sp_window_action_set (self, "close-capture", "enabled", TRUE, NULL);
+      sp_window_action_set (self, "compare-capture", "enabled", TRUE, NULL);
       sp_window_action_set (self, "save-capture", "enabled", TRUE, NULL);
       sp_window_action_set (self, "screenshot", "enabled", TRUE, NULL);
       profiler = sp_local_profiler_new ();
@@ -570,6 +612,23 @@ sp_window_open_capture (GSimpleAction *action,
 }
 
 static void
+sp_window_compare_capture (GSimpleAction *action,
+                           GVariant      *variant,
+                           gpointer       user_data)
+{
+  SpWindow *self = user_data;
+  g_autoptr(GFile) file = NULL;
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (variant == NULL);
+  g_assert (SP_IS_WINDOW (self));
+
+  file = sp_window_request_file (self, _("Open Capture for Comparison"));
+
+  sp_window_compare_to_file (self, file);
+}
+
+static void
 sp_window_save_capture (GSimpleAction *action,
                         GVariant      *variant,
                         gpointer       user_data)
@@ -837,6 +896,7 @@ sp_window_init (SpWindow *self)
   static GActionEntry action_entries[] = {
     { "close-capture", sp_window_close_capture },
     { "open-capture",  sp_window_open_capture },
+    { "compare-capture",  sp_window_compare_capture },
     { "save-capture",  sp_window_save_capture },
     { "screenshot",  sp_window_screenshot },
   };
@@ -991,37 +1051,90 @@ sp_window_get_state (SpWindow *self)
 void
 sp_window_open_from_dialog (SpWindow *self)
 {
-  GtkFileChooserNative *dialog;
-  GtkFileFilter *filter;
-  gint response;
+  g_autoptr(GFile) file = NULL;
 
   g_assert (SP_IS_WINDOW (self));
 
-  dialog = gtk_file_chooser_native_new (_("Open Capture"),
-                                        GTK_WINDOW (self),
-                                        GTK_FILE_CHOOSER_ACTION_OPEN,
-                                        _("Open"),
-                                        _("Cancel"));
+  file = sp_window_request_file (self, _("Open Capture"));
 
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("Sysprof Captures"));
-  gtk_file_filter_add_pattern (filter, "*.syscap");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+  if (file != NULL)
+    sp_window_open (self, file);
+}
 
-  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 (dialog), filter);
+static void
+sp_window_compare_to_generate_cb (GObject      *object,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  SpCallgraphProfile *profile = (SpCallgraphProfile *)object;
+  g_autoptr(SpWindow) self = user_data;
+  g_autoptr(GError) error = NULL;
 
-  response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
+  g_assert (SP_IS_WINDOW (self));
+  g_assert (SP_IS_CALLGRAPH_PROFILE (profile));
 
-  if (response == GTK_RESPONSE_ACCEPT)
+  if (!sp_profile_generate_finish (SP_PROFILE (profile), result, &error))
     {
-      g_autoptr(GFile) file = NULL;
+      sp_window_notify_user (self,
+                             GTK_MESSAGE_ERROR,
+                             "%s", error->message);
+      return;
+    }
+
+  sp_callgraph_view_compare_to (self->callgraph_view, SP_CALLGRAPH_PROFILE (profile));
+}
 
-      file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
-      sp_window_open (self, file);
+static void
+sp_window_compare_to_read_cb (GObject      *object,
+                              GAsyncResult *result,
+                              gpointer      user_data)
+{
+  SpWindow *self = (SpWindow *)object;
+  g_autoptr(SpProfile) profile = NULL;
+  g_autoptr(SpCaptureReader) reader = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (SP_IS_WINDOW (self));
+  g_assert (G_IS_TASK (result));
+
+  reader = g_task_propagate_pointer (G_TASK (result), &error);
+
+  if (reader == NULL)
+    {
+      sp_window_notify_user (self,
+                             GTK_MESSAGE_ERROR,
+                             "%s", error->message);
+      return;
     }
 
-  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (dialog));
+  profile = sp_callgraph_profile_new ();
+  sp_profile_set_reader (profile, reader);
+
+  sp_profile_generate (profile,
+                       NULL,
+                       sp_window_compare_to_generate_cb,
+                       g_object_ref (self));
+}
+
+static void
+sp_window_compare_to_file (SpWindow *self,
+                           GFile    *file)
+{
+  g_autoptr(GTask) task = NULL;
+
+  g_return_if_fail (SP_IS_WINDOW (self));
+  g_return_if_fail (G_IS_FILE (file));
+
+  if (!g_file_is_native (file))
+    {
+      sp_window_notify_user (self,
+                             GTK_MESSAGE_ERROR,
+                             _("The file \"%s\" could not be opened. Only local files are supported."),
+                             g_file_get_uri (file));
+      return;
+    }
+
+  task = g_task_new (self, NULL, sp_window_compare_to_read_cb, NULL);
+  g_task_set_task_data (task, g_object_ref (file), g_object_unref);
+  g_task_run_in_thread (task, sp_window_open_worker);
 }


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