diff --git a/ChangeLog b/ChangeLog index fda592a9cb..b7d8e78c40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-06-29 Johan Dahlin + + * gtk/gtkbuilder.c: (gtk_builder_finalize), + (gtk_builder_get_parameters), (_gtk_builder_construct): + * tests/buildertest.c: + + Improve reference counting, #447967 + 2007-06-29 Ryan Lortie * tests/testgtk.c (create_composited_window): Connect the "destroy" diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c index 213fc9c935..de4e43a3ac 100644 --- a/gtk/gtkbuilder.c +++ b/gtk/gtkbuilder.c @@ -33,6 +33,7 @@ #include "gtkintl.h" #include "gtkprivate.h" #include "gtktypebuiltins.h" +#include "gtkwindow.h" #include "gtkalias.h" static void gtk_builder_class_init (GtkBuilderClass *klass); @@ -62,7 +63,8 @@ struct _GtkBuilderPrivate GHashTable *objects; GHashTable *delayed_properties; GSList *signals; - gchar *current_toplevel; + gchar *current_root; + GSList *root_objects; }; G_DEFINE_TYPE (GtkBuilder, gtk_builder, G_TYPE_OBJECT) @@ -116,12 +118,14 @@ gtk_builder_finalize (GObject *object) g_free (builder->priv->domain); - g_free (builder->priv->current_toplevel); + g_free (builder->priv->current_root); g_hash_table_destroy (builder->priv->delayed_properties); builder->priv->delayed_properties = NULL; g_slist_foreach (builder->priv->signals, (GFunc)_free_signal_info, NULL); g_slist_free (builder->priv->signals); g_hash_table_destroy (builder->priv->objects); + g_slist_foreach (builder->priv->root_objects, (GFunc)g_object_unref, NULL); + g_slist_free (builder->priv->root_objects); } static void @@ -282,21 +286,21 @@ gtk_builder_get_parameters (GtkBuilder *builder, continue; } g_value_init (¶meter.value, G_OBJECT_TYPE (object)); - g_value_set_object (¶meter.value, g_object_ref (object)); + g_value_set_object (¶meter.value, object); } else { GSList *delayed_properties; delayed_properties = g_hash_table_lookup (builder->priv->delayed_properties, - builder->priv->current_toplevel); + builder->priv->current_root); property = g_slice_new (DelayedProperty); property->object = g_strdup (object_name); property->name = g_strdup (prop->name); property->value = g_strdup (prop->data); delayed_properties = g_slist_prepend (delayed_properties, property); g_hash_table_insert (builder->priv->delayed_properties, - g_strdup (builder->priv->current_toplevel), + g_strdup (builder->priv->current_root), delayed_properties); continue; } @@ -371,6 +375,12 @@ _gtk_builder_construct (GtkBuilder *builder, if (object_type == G_TYPE_INVALID) g_error ("Invalid type: %s", info->class_name); + if (!info->parent) + { + g_free (builder->priv->current_root); + builder->priv->current_root = g_strdup (info->id); + } + gtk_builder_get_parameters (builder, object_type, info->id, info->properties, @@ -458,10 +468,14 @@ _gtk_builder_construct (GtkBuilder *builder, g_strdup (info->id), g_free); - if (!info->parent) + + if (!info->parent && !GTK_IS_WINDOW (obj)) { - g_free (builder->priv->current_toplevel); - builder->priv->current_toplevel = g_strdup (info->id); + if (g_object_is_floating (obj)) + g_object_ref_sink (obj); + + builder->priv->root_objects = + g_slist_prepend (builder->priv->root_objects, obj); } g_hash_table_insert (builder->priv->objects, g_strdup (info->id), obj); diff --git a/tests/buildertest.c b/tests/buildertest.c index 833cbf924b..ce46928968 100644 --- a/tests/buildertest.c +++ b/tests/buildertest.c @@ -83,6 +83,7 @@ gboolean test_parser (void) g_return_val_if_fail (error->code == GTK_BUILDER_ERROR_MISSING_PROPERTY_VALUE, FALSE); g_error_free (error); + g_object_unref (builder); return TRUE; } @@ -206,7 +207,7 @@ gboolean test_connect_signals (void) g_return_val_if_fail (after == 1, FALSE); g_return_val_if_fail (object == 1, FALSE); g_return_val_if_fail (object_after == 1, FALSE); - + gtk_widget_destroy (GTK_WIDGET (window)); g_object_unref (builder); builder = builder_new_from_string (buffer_order, -1, NULL); @@ -216,6 +217,8 @@ gboolean test_connect_signals (void) gtk_window_set_title (GTK_WINDOW (window), "test"); g_assert (normal == 20); + gtk_widget_destroy (GTK_WIDGET (window)); + gtk_builder_add_from_string (builder, buffer_extra, strlen (buffer_extra), NULL); gtk_builder_add_from_string (builder, buffer_extra2, @@ -224,10 +227,13 @@ gboolean test_connect_signals (void) window = gtk_builder_get_object (builder, "window2"); gtk_window_set_title (GTK_WINDOW (window), "test"); g_assert (normal == 30); + + gtk_widget_destroy (GTK_WIDGET (window)); window = gtk_builder_get_object (builder, "window3"); gtk_window_set_title (GTK_WINDOW (window), "test"); g_assert (normal == 40); - + gtk_widget_destroy (GTK_WIDGET (window)); + g_object_unref (builder); return TRUE; @@ -236,7 +242,7 @@ gboolean test_connect_signals (void) gboolean test_uimanager_simple (void) { GtkBuilder *builder; - GObject *uimgr, *menubar; + GObject *window, *uimgr, *menubar; GObject *menu, *label; GList *children; const gchar buffer[] = @@ -275,7 +281,6 @@ gboolean test_uimanager_simple (void) uimgr = gtk_builder_get_object (builder, "uimgr1"); g_return_val_if_fail (uimgr != NULL, FALSE); g_return_val_if_fail (GTK_IS_UI_MANAGER (uimgr), FALSE); - g_object_unref (builder); builder = builder_new_from_string (buffer2, -1, NULL); @@ -296,7 +301,9 @@ gboolean test_uimanager_simple (void) g_return_val_if_fail (GTK_IS_LABEL (label), FALSE); g_return_val_if_fail (strcmp (gtk_label_get_text (GTK_LABEL (label)), "File") == 0, FALSE); - + + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); g_object_unref (builder); return TRUE; @@ -349,7 +356,7 @@ gboolean test_translation (void) " " " " ""; - GtkLabel *label; + GtkLabel *window, *label; setlocale (LC_ALL, "sv_SE"); textdomain ("builder"); @@ -358,6 +365,9 @@ gboolean test_translation (void) builder = builder_new_from_string (buffer, -1, NULL); label = GTK_LABEL (gtk_builder_get_object (builder, "label")); g_assert (strcmp (gtk_label_get_text (label), "Arkiv") == 0); + + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); g_object_unref (builder); return TRUE; @@ -452,8 +462,16 @@ gboolean test_sizegroup (void) widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup)); g_return_val_if_fail (g_slist_length (widgets) == 2, FALSE); g_slist_free (widgets); + +#if 0 + { + GObject *window; + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); + } +#endif g_object_unref (builder); - + return TRUE; } @@ -623,6 +641,8 @@ gboolean test_types (void) GtkBuilder *builder; builder = builder_new_from_string (buffer, -1, NULL); + gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "dialog"))); + gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "window"))); g_object_unref (builder); return TRUE; @@ -754,6 +774,8 @@ gboolean test_construct_only_property (void) widget = gtk_builder_get_object (builder, "window1"); g_object_get (widget, "type", &type, NULL); g_return_val_if_fail (type == GTK_WINDOW_POPUP, FALSE); + + gtk_widget_destroy (GTK_WIDGET (widget)); g_object_unref (builder); builder = builder_new_from_string (buffer2, -1, NULL); @@ -761,6 +783,7 @@ gboolean test_construct_only_property (void) g_return_val_if_fail (textbuffer != NULL, FALSE); g_object_get (textbuffer, "tag-table", &tagtable, NULL); g_return_val_if_fail (tagtable == gtk_builder_get_object (builder, "tagtable1"), FALSE); + g_object_unref (tagtable); g_object_unref (builder); return TRUE; @@ -843,6 +866,8 @@ gboolean test_children (void) g_return_val_if_fail (button != NULL, FALSE); g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE); g_return_val_if_fail (strcmp (GTK_WIDGET (GTK_WIDGET (button)->parent)->name, "window1") == 0, FALSE); + + gtk_widget_destroy (GTK_WIDGET (window)); g_object_unref (builder); builder = builder_new_from_string (buffer2, -1, NULL); @@ -871,6 +896,7 @@ gboolean test_children (void) g_return_val_if_fail (GTK_WIDGET (GTK_DIALOG (dialog)->action_area)->name != NULL, FALSE); g_return_val_if_fail (strcmp (GTK_WIDGET (GTK_DIALOG (dialog)->action_area)->name, "dialog1-action_area") == 0, FALSE); + gtk_widget_destroy (GTK_WIDGET (dialog)); g_object_unref (builder); return TRUE; @@ -975,7 +1001,7 @@ gboolean test_treeview_column (void) " " "" ""; - GObject *treeview; + GObject *window, *treeview; GtkTreeViewColumn *column; GList *renderers; GObject *renderer; @@ -1011,6 +1037,9 @@ gboolean test_treeview_column (void) g_free (text); gtk_widget_unrealize (GTK_WIDGET (treeview)); + + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); g_object_unref (builder); return TRUE; @@ -1049,8 +1078,7 @@ gboolean test_icon_view (void) " " " " ""; - GObject *iconview; - GObject *renderer; + GObject *window, *iconview, *renderer; gchar *text; builder = builder_new_from_string (buffer, -1, NULL); @@ -1066,6 +1094,8 @@ gboolean test_icon_view (void) g_return_val_if_fail (strcmp (text, "test") == 0, FALSE); g_free (text); + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); g_object_unref (builder); return TRUE; } @@ -1112,8 +1142,7 @@ gboolean test_combo_box (void) " " " " ""; - GObject *combobox; - GObject *renderer; + GObject *window, *combobox, *renderer; gchar *text; builder = builder_new_from_string (buffer, -1, NULL); @@ -1135,6 +1164,9 @@ gboolean test_combo_box (void) g_return_val_if_fail (strcmp (text, "2") == 0, FALSE); g_free (text); + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); + g_object_unref (builder); return TRUE; } @@ -1181,8 +1213,7 @@ gboolean test_combo_box_entry (void) " " " " ""; - GObject *combobox; - GObject *renderer; + GObject *window, *combobox, *renderer; gchar *text; builder = builder_new_from_string (buffer, -1, NULL); @@ -1203,6 +1234,9 @@ gboolean test_combo_box_entry (void) g_return_val_if_fail (strcmp (text, "2") == 0, FALSE); g_free (text); + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); + g_object_unref (builder); return TRUE; } @@ -1225,33 +1259,34 @@ gboolean test_cell_view (void) " " " " " " - " True" - " liststore1" - " " - " " - " " - " 0" - " " - " " + " True" + " liststore1" + " " + " " + " " + " 0" + " " + " " " " " " " " ""; GObject *cellview; - GObject *model; + GObject *model, *window; GtkTreePath *path; GList *renderers; GObject *renderer; gchar *text; builder = builder_new_from_string (buffer, -1, NULL); - g_assert (builder); cellview = gtk_builder_get_object (builder, "cellview1"); + g_assert (builder); g_assert (cellview); g_return_val_if_fail (GTK_IS_CELL_VIEW (cellview), FALSE); g_object_get (cellview, "model", &model, NULL); g_assert (model); g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE); + g_object_unref (model); path = gtk_tree_path_new_first (); gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (cellview), path); @@ -1268,6 +1303,10 @@ gboolean test_cell_view (void) g_return_val_if_fail (strcmp (text, "test") == 0, FALSE); g_free (text); gtk_tree_path_free (path); + + window = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window)); + g_object_unref (builder); return TRUE; } @@ -1314,6 +1353,7 @@ gboolean test_dialog (void) (GTK_DIALOG (dialog1), GTK_WIDGET (button_cancel)) == -5, FALSE); + gtk_widget_destroy (GTK_WIDGET (dialog1)); g_object_unref (builder); return TRUE; @@ -1357,6 +1397,7 @@ gboolean test_accelerators (void) accel_group = g_slist_nth_data (accel_groups, 0); g_assert (accel_group); + gtk_widget_destroy (GTK_WIDGET (window1)); g_object_unref (builder); builder = builder_new_from_string (buffer2, -1, NULL); @@ -1369,6 +1410,7 @@ gboolean test_accelerators (void) accel_group = g_slist_nth_data (accel_groups, 0); g_assert (accel_group); + gtk_widget_destroy (GTK_WIDGET (window1)); g_object_unref (builder); return TRUE; } @@ -1398,7 +1440,7 @@ gboolean test_widget (void) " " ""; GtkBuilder *builder; - GObject *button1; + GObject *window1, *button1; builder = builder_new_from_string (buffer, -1, NULL); button1 = gtk_builder_get_object (builder, "button1"); @@ -1406,6 +1448,9 @@ gboolean test_widget (void) #if 0 g_return_val_if_fail (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (button1)), FALSE); #endif + window1 = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window1)); + g_object_unref (builder); builder = builder_new_from_string (buffer2, -1, NULL); @@ -1413,6 +1458,8 @@ gboolean test_widget (void) g_return_val_if_fail (GTK_WIDGET_RECEIVES_DEFAULT (GTK_WIDGET (button1)), FALSE); + window1 = gtk_builder_get_object (builder, "window1"); + gtk_widget_destroy (GTK_WIDGET (window1)); g_object_unref (builder); return TRUE; } @@ -1508,6 +1555,62 @@ test_value_from_string (void) return TRUE; } +gboolean model_freed = FALSE; + +static void model_weakref (gpointer data, GObject *model) +{ + model_freed = TRUE; +} + +static gboolean +test_reference_counting (void) +{ + GtkBuilder *builder; + const gchar buffer1[] = + "" + " " + " " + " " + " " + " " + " liststore1" + " " + " " + " " + ""; + const gchar buffer2[] = + "" + " " + " " + " " + " " + " start" + " " + " " + " " + ""; + GObject *window, *treeview, *model; + + builder = builder_new_from_string (buffer1, -1, NULL); + window = gtk_builder_get_object (builder, "window1"); + treeview = gtk_builder_get_object (builder, "treeview1"); + model = gtk_builder_get_object (builder, "liststore1"); + g_object_unref (builder); + + g_object_weak_ref (model, (GWeakNotify)model_weakref, NULL); + + g_assert (model_freed == FALSE); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), NULL); + g_assert (model_freed == TRUE); + + gtk_widget_destroy (GTK_WIDGET (window)); + + builder = builder_new_from_string (buffer2, -1, NULL); + g_object_unref (builder); + + return TRUE; +} + int main (int argc, char **argv) { @@ -1605,5 +1708,9 @@ main (int argc, char **argv) if (!test_value_from_string ()) g_error ("test_value_from_string failed"); + g_print ("Testing reference counting\n"); + if (!test_reference_counting ()) + g_error ("test_reference_counting failed"); + return 0; }