[gtk+] inspector: Add minimal signal tracing



commit 975677872f74f215d64682e0309239ea0215a8b9
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat May 10 10:40:38 2014 -0400

    inspector: Add minimal signal tracing
    
    Add rudimentary signal tracing. The signals tab can now count signal
    emissions for all signals of the current object.

 modules/inspector/signals-list.c  |  227 +++++++++++++++++++++++++++++++++++--
 modules/inspector/signals-list.h  |    4 +-
 modules/inspector/signals-list.ui |  132 +++++++++++++++------
 3 files changed, 312 insertions(+), 51 deletions(-)
---
diff --git a/modules/inspector/signals-list.c b/modules/inspector/signals-list.c
index 276b4e6..e132a7d 100644
--- a/modules/inspector/signals-list.c
+++ b/modules/inspector/signals-list.c
@@ -21,26 +21,30 @@
 
 enum
 {
-  COLUMN_ENABLED,
   COLUMN_NAME,
   COLUMN_CLASS,
-  COLUMN_CONNECTED
+  COLUMN_CONNECTED,
+  COLUMN_COUNT,
+  COLUMN_NO_HOOKS,
+  COLUMN_SIGNAL_ID,
+  COLUMN_HOOK_ID
 };
 
 struct _GtkInspectorSignalsListPrivate
 {
   GtkWidget *view;
   GtkListStore *model;
+  GtkTextBuffer *text;
+  GtkWidget *log_win;
+  GtkWidget *trace_button;
+  GtkTreeViewColumn *count_column;
+  GtkCellRenderer *count_renderer;
+  GObject *object;
+  GHashTable *iters;
+  gboolean tracing;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorSignalsList, gtk_inspector_signals_list, GTK_TYPE_BOX)
-
-static void
-gtk_inspector_signals_list_init (GtkInspectorSignalsList *sl)
-{
-  sl->priv = gtk_inspector_signals_list_get_instance_private (sl);
-  gtk_widget_init_template (GTK_WIDGET (sl));
-}
+G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorSignalsList, gtk_inspector_signals_list, GTK_TYPE_PANED)
 
 static GType *
 get_types (GObject *object, guint *length)
@@ -92,11 +96,16 @@ add_signals (GtkInspectorSignalsList *sl,
       has_handler = g_signal_has_handler_pending (object, ids[i], 0, TRUE);
       gtk_list_store_append (sl->priv->model, &iter);
       gtk_list_store_set (sl->priv->model, &iter,
-                          COLUMN_ENABLED, FALSE,
                           COLUMN_NAME, query.signal_name,
                           COLUMN_CLASS, g_type_name (type),
                           COLUMN_CONNECTED, has_handler ? _("Yes") : "",
+                          COLUMN_COUNT, 0,
+                          COLUMN_NO_HOOKS, (query.signal_flags & G_SIGNAL_NO_HOOKS) != 0,
+                          COLUMN_SIGNAL_ID, ids[i],
+                          COLUMN_HOOK_ID, 0,
                           -1);
+      g_hash_table_insert (sl->priv->iters,
+                           GINT_TO_POINTER (ids[i]), gtk_tree_iter_copy (&iter));
     }
   g_free (ids);
 }
@@ -115,13 +124,200 @@ read_signals_from_object (GtkInspectorSignalsList *sl,
   g_free (types);
 }
 
+static void stop_tracing (GtkInspectorSignalsList *sl);
+
 void
 gtk_inspector_signals_list_set_object (GtkInspectorSignalsList *sl,
                                        GObject                 *object)
 {
+  if (sl->priv->object == object)
+    return;
+
+  stop_tracing (sl);
   gtk_list_store_clear (sl->priv->model);
+  g_hash_table_remove_all (sl->priv->iters);
+
+  sl->priv->object = object;
+
+  if (object)
+    read_signals_from_object (sl, object);
+}
+
+static void
+render_count (GtkTreeViewColumn *column,
+              GtkCellRenderer   *renderer,
+              GtkTreeModel      *model,
+              GtkTreeIter       *iter,
+              gpointer           data)
+{
+  gint count;
+  gboolean no_hooks;
+  gchar text[100];
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_COUNT, &count,
+                      COLUMN_NO_HOOKS, &no_hooks,
+                      -1);
+  if (no_hooks)
+    {
+      g_object_set (renderer, "markup", "<i>(untraceable)</i>", NULL);
+    }
+  else if (count != 0)
+    {
+      g_snprintf (text, 100, "%d", count);
+      g_object_set (renderer, "text", text, NULL);
+    }
+  else
+    g_object_set (renderer, "text", "", NULL);
+}
+
+static void
+gtk_inspector_signals_list_init (GtkInspectorSignalsList *sl)
+{
+  sl->priv = gtk_inspector_signals_list_get_instance_private (sl);
+  gtk_widget_init_template (GTK_WIDGET (sl));
+
+  gtk_tree_view_column_set_cell_data_func (sl->priv->count_column,
+                                           sl->priv->count_renderer,
+                                           render_count,
+                                           NULL, NULL);
+
+  sl->priv->iters = g_hash_table_new_full (g_direct_hash, 
+                                           g_direct_equal,
+                                           NULL,
+                                           (GDestroyNotify) gtk_tree_iter_free);
+}
+
+static gboolean
+trace_hook (GSignalInvocationHint *ihint,
+            guint                  n_param_values,
+            const GValue          *param_values,
+            gpointer               data)
+{
+  GtkInspectorSignalsList *sl = data;
+  GObject *object;
+
+  object = g_value_get_object (param_values);
+
+  if (object == sl->priv->object)
+    {
+      gint count;
+      GtkTreeIter *iter;
+
+      iter = (GtkTreeIter *)g_hash_table_lookup (sl->priv->iters, GINT_TO_POINTER (ihint->signal_id));
+
+      gtk_tree_model_get (GTK_TREE_MODEL (sl->priv->model), iter, COLUMN_COUNT, &count, -1);
+      gtk_list_store_set (sl->priv->model, iter, COLUMN_COUNT, count + 1, -1);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+start_tracing_cb (GtkTreeModel *model,
+                  GtkTreePath  *path,
+                  GtkTreeIter  *iter,
+                  gpointer      data)
+{
+  GtkInspectorSignalsList *sl = data;
+  guint signal_id;
+  gulong hook_id;
+  gboolean no_hooks;
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_SIGNAL_ID, &signal_id,
+                      COLUMN_HOOK_ID, &hook_id,
+                      COLUMN_NO_HOOKS, &no_hooks,
+                      -1);
+
+  g_assert (signal_id != 0);
+  g_assert (hook_id == 0);
+
+  if (!no_hooks)
+    {
+      hook_id = g_signal_add_emission_hook (signal_id, 0, trace_hook, sl, NULL);
+
+      gtk_list_store_set (GTK_LIST_STORE (model), iter,
+                          COLUMN_COUNT, 0,
+                          COLUMN_HOOK_ID, hook_id,
+                          -1);
+    }
+
+  return FALSE;
+}
+
+static gboolean
+stop_tracing_cb (GtkTreeModel *model,
+                 GtkTreePath  *path,
+                 GtkTreeIter  *iter,
+                 gpointer      data)
+{
+  guint signal_id;
+  gulong hook_id;
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_SIGNAL_ID, &signal_id,
+                      COLUMN_HOOK_ID, &hook_id,
+                      -1);
+
+  g_assert (signal_id != 0);
+
+  if (hook_id != 0)
+    {
+      g_signal_remove_emission_hook (signal_id, hook_id);
+      gtk_list_store_set (GTK_LIST_STORE (model), iter,
+                          COLUMN_HOOK_ID, 0,
+                          -1);
+    }
+
+  return FALSE;
+}
+
+static void
+start_tracing (GtkInspectorSignalsList *sl)
+{
+  sl->priv->tracing = TRUE;
+  gtk_tree_model_foreach (GTK_TREE_MODEL (sl->priv->model), start_tracing_cb, sl);
+}
+
+static void
+stop_tracing (GtkInspectorSignalsList *sl)
+{
+  sl->priv->tracing = FALSE;
+  gtk_tree_model_foreach (GTK_TREE_MODEL (sl->priv->model), stop_tracing_cb, sl);
+  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (sl->priv->trace_button), FALSE);
+}
+
+static void
+toggle_tracing (GtkToggleToolButton *button, GtkInspectorSignalsList *sl)
+{
+  if (gtk_toggle_tool_button_get_active (button) == sl->priv->tracing)
+    return;
+
+  //gtk_widget_show (sl->priv->log_win);
+
+  if (gtk_toggle_tool_button_get_active (button))
+    start_tracing (sl);
+  else
+    stop_tracing (sl);
+}
+
+static gboolean
+clear_log_cb (GtkTreeModel *model,
+              GtkTreePath  *path,
+              GtkTreeIter  *iter,
+              gpointer      data)
+{
+  gtk_list_store_set (GTK_LIST_STORE (model), iter, COLUMN_COUNT, 0, -1);
+  return FALSE;
+}
+
+static void
+clear_log (GtkToolButton *button, GtkInspectorSignalsList *sl)
+{
+  gtk_text_buffer_set_text (sl->priv->text, "", -1);
 
-  read_signals_from_object (sl, object);
+  gtk_tree_model_foreach (GTK_TREE_MODEL (sl->priv->model), clear_log_cb, sl);
 }
 
 static void
@@ -132,6 +328,13 @@ gtk_inspector_signals_list_class_init (GtkInspectorSignalsListClass *klass)
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/inspector/signals-list.ui");
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorSignalsList, view);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorSignalsList, model);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorSignalsList, text);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorSignalsList, log_win);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorSignalsList, count_column);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorSignalsList, count_renderer);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorSignalsList, trace_button);
+  gtk_widget_class_bind_template_callback (widget_class, toggle_tracing);
+  gtk_widget_class_bind_template_callback (widget_class, clear_log);
 }
 
 GtkWidget *
diff --git a/modules/inspector/signals-list.h b/modules/inspector/signals-list.h
index 4332bd2..9d90f56 100644
--- a/modules/inspector/signals-list.h
+++ b/modules/inspector/signals-list.h
@@ -32,13 +32,13 @@ typedef struct _GtkInspectorSignalsListPrivate GtkInspectorSignalsListPrivate;
 
 typedef struct _GtkInspectorSignalsList
 {
-  GtkBox parent;
+  GtkPaned parent;
   GtkInspectorSignalsListPrivate *priv;
 } GtkInspectorSignalsList;
 
 typedef struct _GtkInspectorSignalsListClass
 {
-  GtkBoxClass parent;
+  GtkPanedClass parent;
 } GtkInspectorSignalsListClass;
 
 G_BEGIN_DECLS
diff --git a/modules/inspector/signals-list.ui b/modules/inspector/signals-list.ui
index 8aae0ca..a784442 100644
--- a/modules/inspector/signals-list.ui
+++ b/modules/inspector/signals-list.ui
@@ -2,64 +2,122 @@
 <interface domain="gtk30">
   <object class="GtkListStore" id="model">
     <columns>
-      <column type="gboolean"/>
       <column type="gchararray"/>
       <column type="gchararray"/>
       <column type="gchararray"/>
+      <column type="gint"/>
+      <column type="gboolean"/>
+      <column type="guint"/>
+      <column type="gulong"/>
     </columns>
   </object>
-  <template class="GtkInspectorSignalsList" parent="GtkBox">
+  <object class="GtkTextBuffer" id="text">
+  </object>
+  <template class="GtkInspectorSignalsList" parent="GtkPaned">
     <property name="orientation">vertical</property>
     <child>
-      <object class="GtkScrolledWindow">
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
         <property name="visible">True</property>
-        <property name="expand">True</property>
-        <property name="hscrollbar-policy">automatic</property>
-        <property name="vscrollbar-policy">always</property>
-        <property name="shadow-type">in</property>
         <child>
-          <object class="GtkTreeView" id="view">
+          <object class="GtkToolbar" id="toolbar">
             <property name="visible">True</property>
-            <property name="model">model</property>
+            <property name="icon-size">small-toolbar</property>
             <child>
-              <object class="GtkTreeViewColumn">
-                <property name="title" translatable="yes">Name</property>
-                <child>
-                  <object class="GtkCellRendererText">
-                    <property name="scale">0.8</property>
-                  </object>
-                  <attributes>
-                    <attribute name="text">1</attribute>
-                  </attributes>
-                </child>
+              <object class="GtkToggleToolButton" id="trace_button">
+                <property name="visible">True</property>
+                <property name="icon-name">media-record</property>
+                <property name="tooltip-text" translatable="yes">Trace signal emissions on this 
object</property>
+                <signal name="toggled" handler="toggle_tracing"/>
               </object>
             </child>
             <child>
-              <object class="GtkTreeViewColumn">
-                <property name="title" translatable="yes">Defined At</property>
+              <object class="GtkToolButton" id="clear_button">
+                <property name="visible">True</property>
+                <property name="icon-name">edit-clear</property>
+                <property name="tooltip-text" translatable="yes">Clear log</property>
+                <signal name="clicked" handler="clear_log"/>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow">
+            <property name="visible">True</property>
+            <property name="expand">True</property>
+            <property name="hscrollbar-policy">automatic</property>
+            <property name="vscrollbar-policy">always</property>
+            <property name="shadow-type">in</property>
+            <child>
+              <object class="GtkTreeView" id="view">
+                <property name="visible">True</property>
+                <property name="model">model</property>
                 <child>
-                  <object class="GtkCellRendererText">
-                    <property name="scale">0.8</property>
+                  <object class="GtkTreeViewColumn">
+                    <property name="title" translatable="yes">Name</property>
+                    <child>
+                      <object class="GtkCellRendererText">
+                        <property name="scale">0.8</property>
+                      </object>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
                   </object>
-                  <attributes>
-                    <attribute name="text">2</attribute>
-                  </attributes>
                 </child>
-              </object>
-            </child>  
-            <child>
-              <object class="GtkTreeViewColumn">
-                <property name="title" translatable="yes">Connected</property>
                 <child>
-                  <object class="GtkCellRendererText">
-                    <property name="scale">0.8</property>
+                  <object class="GtkTreeViewColumn">
+                    <property name="title" translatable="yes">Connected</property>
+                    <child>
+                      <object class="GtkCellRendererText">
+                        <property name="scale">0.8</property>
+                      </object>
+                      <attributes>
+                        <attribute name="text">2</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="count_column">
+                    <property name="title" translatable="yes">Count</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="count_renderer">
+                        <property name="scale">0.8</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn">
+                    <property name="title" translatable="yes">Defined At</property>
+                    <child>
+                      <object class="GtkCellRendererText">
+                        <property name="scale">0.8</property>
+                      </object>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
                   </object>
-                  <attributes>
-                    <attribute name="text">3</attribute>
-                  </attributes>
                 </child>
               </object>
-            </child>  
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkScrolledWindow" id="log_win">
+        <property name="expand">True</property>
+        <property name="hscrollbar-policy">automatic</property>
+        <property name="vscrollbar-policy">always</property>
+        <property name="shadow-type">in</property>
+        <child>
+          <object class="GtkTextView">
+            <property name="visible">True</property>
+            <property name="buffer">text</property>
+            <property name="editable">False</property>
           </object>
         </child>
       </object>


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