diff options
author | Matthias Clasen <mclasen@redhat.com> | 2014-05-08 22:58:43 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2014-05-10 22:04:28 -0400 |
commit | 700657ad19f4444ed6a2f3f66ad54afc1dac3a29 (patch) | |
tree | 651e3b656ffbf989ad310d426c80154d752a4015 /modules | |
parent | 0dbfef5696db760f7840202a7453bec441fe379d (diff) | |
download | gtk+-700657ad19f4444ed6a2f3f66ad54afc1dac3a29.tar.gz |
inspector: Deal with dying objects
The widget-tree was not safe against object just going away.
Fix this by using row references instead of iters where
necessary, and by using weak refs to clean up when objects
die.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/inspector/classes-list.c | 89 | ||||
-rw-r--r-- | modules/inspector/classes-list.ui | 8 | ||||
-rw-r--r-- | modules/inspector/css-editor.c | 17 | ||||
-rw-r--r-- | modules/inspector/css-editor.h | 2 | ||||
-rw-r--r-- | modules/inspector/prop-list.c | 51 | ||||
-rw-r--r-- | modules/inspector/widget-tree.c | 44 |
6 files changed, 155 insertions, 56 deletions
diff --git a/modules/inspector/classes-list.c b/modules/inspector/classes-list.c index 7c0d52a744..cc5efbcff2 100644 --- a/modules/inspector/classes-list.c +++ b/modules/inspector/classes-list.c @@ -39,18 +39,28 @@ typedef struct struct _GtkInspectorClassesListPrivate { - GtkWidget *toolbar; - GtkWidget *view; - GtkTreeViewColumn *column; - GtkCellRenderer *name_renderer; GtkListStore *model; - GHashTable *contexts; - GtkStyleContext *current_context; + GtkStyleContext *context; }; G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorClassesList, gtk_inspector_classes_list, GTK_TYPE_BOX) static void +set_hash_context (GtkInspectorClassesList *cl, GHashTable *hash_context) +{ + g_object_set_data_full (G_OBJECT (cl->priv->context), + "gtk-inspector-hash-context", + hash_context, (GDestroyNotify)g_hash_table_unref); +} + +static GHashTable * +get_hash_context (GtkInspectorClassesList *cl) +{ + return (GHashTable *)g_object_get_data (G_OBJECT (cl->priv->context), + "gtk-inspector-hash-context"); +} + +static void enabled_toggled (GtkCellRendererToggle *renderer, const gchar *path, GtkInspectorClassesList *cl) @@ -76,7 +86,7 @@ enabled_toggled (GtkCellRendererToggle *renderer, COLUMN_ENABLED, enabled, -1); - context = g_hash_table_lookup (cl->priv->contexts, cl->priv->current_context); + context = get_hash_context (cl); if (context) { c = g_hash_table_lookup (context, name); @@ -84,9 +94,9 @@ enabled_toggled (GtkCellRendererToggle *renderer, { c->enabled = enabled; if (enabled) - gtk_style_context_add_class (cl->priv->current_context, name); + gtk_style_context_add_class (cl->priv->context, name); else - gtk_style_context_remove_class (cl->priv->current_context, name); + gtk_style_context_remove_class (cl->priv->context, name); } else g_warning ("GtkInspector: Couldn't find the css class %s in the class hash table.", name); @@ -120,14 +130,16 @@ add_clicked (GtkButton *button, if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { - const gchar *name = gtk_entry_get_text (GTK_ENTRY (entry)); - GHashTable *context = g_hash_table_lookup (cl->priv->contexts, cl->priv->current_context); + const gchar *name; + GHashTable *context; + context = get_hash_context (cl); + name = gtk_entry_get_text (GTK_ENTRY (entry)); if (*name && !g_hash_table_contains (context, name)) { GtkTreeIter tree_iter; - gtk_style_context_add_class (cl->priv->current_context, name); + gtk_style_context_add_class (cl->priv->context, name); GtkInspectorClassesListByContext *c = g_new0 (GtkInspectorClassesListByContext, 1); c->enabled = TRUE; @@ -155,7 +167,7 @@ read_classes_from_style_context (GtkInspectorClassesList *cl) GHashTable *hash_context; hash_context = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - classes = gtk_style_context_list_classes (cl->priv->current_context); + classes = gtk_style_context_list_classes (cl->priv->context); for (l = classes; l; l = l->next) { @@ -171,7 +183,7 @@ read_classes_from_style_context (GtkInspectorClassesList *cl) -1); } g_list_free (classes); - g_hash_table_replace (cl->priv->contexts, cl->priv->current_context, hash_context); + set_hash_context (cl, hash_context); } static void @@ -181,15 +193,16 @@ restore_defaults_clicked (GtkButton *button, GHashTableIter hash_iter; gchar *name; GtkInspectorClassesListByContext *c; - GHashTable *hash_context = g_hash_table_lookup (cl->priv->contexts, cl->priv->current_context); + GHashTable *hash_context; + hash_context = get_hash_context (cl); g_hash_table_iter_init (&hash_iter, hash_context); while (g_hash_table_iter_next (&hash_iter, (gpointer *)&name, (gpointer *)&c)) { if (c->style == PANGO_STYLE_ITALIC) - gtk_style_context_remove_class (cl->priv->current_context, name); + gtk_style_context_remove_class (cl->priv->context, name); else if (!c->enabled) - gtk_style_context_add_class (cl->priv->current_context, name); + gtk_style_context_add_class (cl->priv->context, name); } gtk_list_store_clear (cl->priv->model); @@ -201,27 +214,47 @@ gtk_inspector_classes_list_init (GtkInspectorClassesList *cl) { cl->priv = gtk_inspector_classes_list_get_instance_private (cl); gtk_widget_init_template (GTK_WIDGET (cl)); - cl->priv->contexts = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_destroy); +} + +static void remove_dead_object (gpointer data, GObject *dead_object); + +static void +cleanup_context (GtkInspectorClassesList *cl) +{ + if (cl->priv->context) + g_object_weak_unref (G_OBJECT (cl->priv->context), remove_dead_object, cl); + + gtk_list_store_clear (cl->priv->model); + cl->priv->context = NULL; + gtk_widget_set_sensitive (GTK_WIDGET (cl), FALSE); +} + +static void +remove_dead_object (gpointer data, GObject *dead_object) +{ + GtkInspectorClassesList *cl = data; + + cl->priv->context = NULL; + cleanup_context (cl); } void gtk_inspector_classes_list_set_widget (GtkInspectorClassesList *cl, GtkWidget *widget) { - GtkStyleContext *widget_context; GHashTable *hash_context; GtkTreeIter tree_iter; GtkInspectorClassesListByContext *c; - gtk_list_store_clear (cl->priv->model); + cleanup_context (cl); gtk_widget_set_sensitive (GTK_WIDGET (cl), TRUE); - widget_context = gtk_widget_get_style_context (widget); - cl->priv->current_context = widget_context; - gtk_widget_set_sensitive (cl->priv->toolbar, TRUE); + cl->priv->context = gtk_widget_get_style_context (widget); - hash_context = g_hash_table_lookup (cl->priv->contexts, widget_context); + g_object_weak_ref (G_OBJECT (cl->priv->context), remove_dead_object, cl); + + hash_context = get_hash_context (cl); if (hash_context) { GHashTableIter hash_iter; @@ -239,9 +272,7 @@ gtk_inspector_classes_list_set_widget (GtkInspectorClassesList *cl, } } else - { - read_classes_from_style_context (cl); - } + read_classes_from_style_context (cl); } static void @@ -250,11 +281,7 @@ gtk_inspector_classes_list_class_init (GtkInspectorClassesListClass *klass) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/inspector/classes-list.ui"); - gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorClassesList, toolbar); - gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorClassesList, view); gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorClassesList, model); - gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorClassesList, column); - gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorClassesList, name_renderer); gtk_widget_class_bind_template_callback (widget_class, add_clicked); gtk_widget_class_bind_template_callback (widget_class, restore_defaults_clicked); gtk_widget_class_bind_template_callback (widget_class, enabled_toggled); diff --git a/modules/inspector/classes-list.ui b/modules/inspector/classes-list.ui index e26700ff3f..0835eefe61 100644 --- a/modules/inspector/classes-list.ui +++ b/modules/inspector/classes-list.ui @@ -10,7 +10,7 @@ <template class="GtkInspectorClassesList" parent="GtkBox"> <property name="orientation">vertical</property> <child> - <object class="GtkToolbar" id="toolbar"> + <object class="GtkToolbar"> <property name="visible">True</property> <property name="icon-size">small-toolbar</property> <property name="sensitive">False</property> @@ -37,11 +37,11 @@ <property name="visible">True</property> <property name="expand">True</property> <child> - <object class="GtkTreeView" id="view"> + <object class="GtkTreeView"> <property name="visible">True</property> <property name="model">model</property> <child> - <object class="GtkTreeViewColumn" id="column"> + <object class="GtkTreeViewColumn"> <property name="title" translatable="yes">Name</property> <child> <object class="GtkCellRendererToggle"> @@ -53,7 +53,7 @@ </attributes> </child> <child> - <object class="GtkCellRendererText" id="name_renderer"> + <object class="GtkCellRendererText"> <property name="scale">0.8</property> </object> <attributes> diff --git a/modules/inspector/css-editor.c b/modules/inspector/css-editor.c index b993e24fa3..d5a59b9fa8 100644 --- a/modules/inspector/css-editor.c +++ b/modules/inspector/css-editor.c @@ -205,8 +205,9 @@ create_provider (GtkInspectorCssEditor *ce) gtk_style_context_add_provider (ce->priv->context, GTK_STYLE_PROVIDER (provider), G_MAXUINT); - g_object_set_data (G_OBJECT (ce->priv->context), - GTK_INSPECTOR_CSS_EDITOR_PROVIDER, provider); + g_object_set_data_full (G_OBJECT (ce->priv->context), + GTK_INSPECTOR_CSS_EDITOR_PROVIDER, provider, + g_object_unref); } g_signal_connect (provider, "parsing-error", @@ -302,6 +303,15 @@ gtk_inspector_css_editor_new (gboolean global) NULL)); } +static void +remove_dead_object (gpointer data, GObject *dead_object) +{ + GtkInspectorCssEditor *ce = data; + + ce->priv->context = NULL; + gtk_widget_set_sensitive (GTK_WIDGET (ce), ce->priv->global); +} + void gtk_inspector_css_editor_set_widget (GtkInspectorCssEditor *ce, GtkWidget *widget) @@ -316,6 +326,7 @@ gtk_inspector_css_editor_set_widget (GtkInspectorCssEditor *ce, if (ce->priv->context) { + g_object_weak_unref (G_OBJECT (ce->priv->context), remove_dead_object, ce); text = get_current_text (GTK_TEXT_BUFFER (ce->priv->text)); g_object_set_data_full (G_OBJECT (ce->priv->context), GTK_INSPECTOR_CSS_EDITOR_TEXT, @@ -331,6 +342,8 @@ gtk_inspector_css_editor_set_widget (GtkInspectorCssEditor *ce, set_initial_text (ce); disable_toggled (ce->priv->disable_button, ce); + + g_object_weak_ref (G_OBJECT (ce->priv->context), remove_dead_object, ce); } // vim: set et sw=2 ts=2: diff --git a/modules/inspector/css-editor.h b/modules/inspector/css-editor.h index 80be3099dd..08ee4e0526 100644 --- a/modules/inspector/css-editor.h +++ b/modules/inspector/css-editor.h @@ -50,7 +50,7 @@ G_BEGIN_DECLS GType gtk_inspector_css_editor_get_type (void); GtkWidget *gtk_inspector_css_editor_new (gboolean global); -void gtk_inspector_css_editor_set_widget (GtkInspectorCssEditor *editor, +void gtk_inspector_css_editor_set_widget (GtkInspectorCssEditor *ce, GtkWidget *widget); G_END_DECLS diff --git a/modules/inspector/prop-list.c b/modules/inspector/prop-list.c index d58cbc3aea..6c78777ddc 100644 --- a/modules/inspector/prop-list.c +++ b/modules/inspector/prop-list.c @@ -232,6 +232,38 @@ gtk_inspector_prop_list_new (GtkWidget *widget_tree, NULL); } +static void remove_dead_object (gpointer data, GObject *dead_object); + +static void +cleanup_object (GtkInspectorPropList *pl) +{ + gtk_widget_set_sensitive (GTK_WIDGET (pl), FALSE); + + if (pl->priv->object) + g_object_weak_unref (pl->priv->object, remove_dead_object, pl); + + if (pl->priv->object && pl->priv->notify_handler_id != 0) + { + g_signal_handler_disconnect (pl->priv->object, pl->priv->notify_handler_id); + pl->priv->notify_handler_id = 0; + } + + pl->priv->object = NULL; + + g_hash_table_remove_all (pl->priv->prop_iters); + gtk_list_store_clear (pl->priv->model); +} + +static void +remove_dead_object (gpointer data, GObject *dead_object) +{ + GtkInspectorPropList *pl = data; + + pl->priv->notify_handler_id = 0; + pl->priv->object = NULL; + cleanup_object (pl); +} + gboolean gtk_inspector_prop_list_set_object (GtkInspectorPropList *pl, GObject *object) @@ -244,18 +276,16 @@ gtk_inspector_prop_list_set_object (GtkInspectorPropList *pl, if (pl->priv->object == object) return FALSE; - if (pl->priv->notify_handler_id != 0) - { - g_signal_handler_disconnect (pl->priv->object, pl->priv->notify_handler_id); - pl->priv->notify_handler_id = 0; - } - - g_hash_table_remove_all (pl->priv->prop_iters); - gtk_list_store_clear (pl->priv->model); - gtk_widget_set_sensitive (GTK_WIDGET (pl), FALSE); + cleanup_object (pl); pl->priv->object = object; + g_object_weak_ref (object, remove_dead_object, pl); + + g_object_set (pl->priv->attribute_column, + "visible", !pl->priv->child_properties && GTK_IS_CELL_RENDERER (object), + NULL); + if (pl->priv->child_properties) { GtkWidget *parent; @@ -294,9 +324,6 @@ gtk_inspector_prop_list_set_object (GtkInspectorPropList *pl, G_CALLBACK (gtk_inspector_prop_list_prop_changed_cb), pl); - g_object_set (pl->priv->attribute_column, - "visible", !pl->priv->child_properties && GTK_IS_CELL_RENDERER (object), - NULL); return TRUE; } diff --git a/modules/inspector/widget-tree.c b/modules/inspector/widget-tree.c index 165339a2a2..4b63cb838a 100644 --- a/modules/inspector/widget-tree.c +++ b/modules/inspector/widget-tree.c @@ -63,20 +63,42 @@ on_widget_selected (GtkTreeSelection *selection, typedef struct { + GtkInspectorWidgetTree *wt; GObject *object; - GtkTreeIter *iter; + GtkTreeRowReference *row; gulong map_handler; gulong unmap_handler; } ObjectData; static void +remove_dead_object (gpointer data, GObject *dead_object) +{ + ObjectData *od = data; + + if (gtk_tree_row_reference_valid (od->row)) + { + GtkTreePath *path; + GtkTreeIter iter; + path = gtk_tree_row_reference_get_path (od->row); + gtk_tree_model_get_iter (GTK_TREE_MODEL (od->wt->priv->model), &iter, path); + gtk_tree_store_remove (od->wt->priv->model, &iter); + gtk_tree_path_free (path); + } + od->object = NULL; + g_hash_table_remove (od->wt->priv->iters, dead_object); +} + +static void object_data_free (gpointer data) { ObjectData *od = data; - gtk_tree_iter_free (od->iter); + gtk_tree_row_reference_free (od->row); - if (g_signal_handler_is_connected (od->object, od->map_handler)) + if (od->object) + g_object_weak_unref (od->object, remove_dead_object, od); + + if (od->object && od->map_handler) { g_signal_handler_disconnect (od->object, od->map_handler); g_signal_handler_disconnect (od->object, od->unmap_handler); @@ -181,6 +203,7 @@ gtk_inspector_widget_tree_append_object (GtkInspectorWidgetTree *wt, const gchar *name) { GtkTreeIter iter; + GtkTreePath *path; const gchar *class_name = G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)); gchar *address; gboolean mapped; @@ -231,8 +254,11 @@ gtk_inspector_widget_tree_append_object (GtkInspectorWidgetTree *wt, -1); od = g_new0 (ObjectData, 1); + od->wt = wt; od->object = object; - od->iter = gtk_tree_iter_copy (&iter); + path = gtk_tree_model_get_path (GTK_TREE_MODEL (wt->priv->model), &iter); + od->row = gtk_tree_row_reference_new (GTK_TREE_MODEL (wt->priv->model), path); + gtk_tree_path_free (path); if (GTK_IS_WIDGET (object)) { od->map_handler = g_signal_connect (object, "map", G_CALLBACK (map_or_unmap), wt); @@ -240,6 +266,7 @@ gtk_inspector_widget_tree_append_object (GtkInspectorWidgetTree *wt, } g_hash_table_insert (wt->priv->iters, object, od); + g_object_weak_ref (object, remove_dead_object, od); g_free (address); @@ -306,9 +333,14 @@ gtk_inspector_widget_tree_find_object (GtkInspectorWidgetTree *wt, ObjectData *od; od = g_hash_table_lookup (wt->priv->iters, object); - if (od) + if (od && gtk_tree_row_reference_valid (od->row)) { - *iter = *od->iter; + GtkTreePath *path; + + path = gtk_tree_row_reference_get_path (od->row); + gtk_tree_model_get_iter (GTK_TREE_MODEL (wt->priv->model), iter, path); + gtk_tree_path_free (path); + return TRUE; } |