From 975677872f74f215d64682e0309239ea0215a8b9 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 10 May 2014 10:40:38 -0400 Subject: [PATCH] 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 | 229 ++++++++++++++++++++++++++++-- modules/inspector/signals-list.h | 4 +- modules/inspector/signals-list.ui | 150 +++++++++++++------ 3 files changed, 322 insertions(+), 61 deletions(-) diff --git a/modules/inspector/signals-list.c b/modules/inspector/signals-list.c index 276b4e65ae..e132a7df13 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) { - gtk_list_store_clear (sl->priv->model); + if (sl->priv->object == object) + return; - read_signals_from_object (sl, object); + 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", "(untraceable)", 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); + + 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 4332bd220c..9d90f561e5 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 8aae0caab0..a7844420b1 100644 --- a/modules/inspector/signals-list.ui +++ b/modules/inspector/signals-list.ui @@ -2,64 +2,122 @@ + + + + - - - + + -