From bf55685000fd744a26eec61c07fd8aa3d084d54c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 19 Mar 2023 05:22:46 +0100 Subject: [PATCH] treelistmodel: Track the item in the row That way, we can return the item even after the row is removed. This is particularly relevant in ListItemFactory::unbind callbacks because they often use gtk_tree_list_row_get_item() and user code never tracks changes to this property. A side effect of this is that the item will survive until the row gets destroyed, but that's what users expect anyway, so we can live with it. Related: #5646 --- gtk/gtktreelistmodel.c | 16 +++++++--------- testsuite/gtk/defaultvalue.c | 6 ++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/gtk/gtktreelistmodel.c b/gtk/gtktreelistmodel.c index 775e311214..fe9240e4b4 100644 --- a/gtk/gtktreelistmodel.c +++ b/gtk/gtktreelistmodel.c @@ -88,6 +88,7 @@ struct _GtkTreeListRow GObject parent_instance; TreeNode *node; /* NULL when the row has been destroyed */ + gpointer item; }; struct _GtkTreeListRowClass @@ -293,6 +294,7 @@ tree_node_get_row (TreeNode *node) { node->row = g_object_new (GTK_TYPE_TREE_LIST_ROW, NULL); node->row->node = node; + node->row->item = g_object_ref (node->item); return node->row; } @@ -947,7 +949,6 @@ gtk_tree_list_row_destroy (GtkTreeListRow *self) g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_DEPTH]); g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_EXPANDABLE]); g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_EXPANDED]); - g_object_notify_by_pspec (G_OBJECT (self), row_properties[ROW_PROP_ITEM]); self->node = NULL; g_object_thaw_notify (G_OBJECT (self)); @@ -1017,6 +1018,8 @@ gtk_tree_list_row_dispose (GObject *object) if (self->node) self->node->row = NULL; + g_clear_object (&self->item); + G_OBJECT_CLASS (gtk_tree_list_row_parent_class)->dispose (object); } @@ -1263,21 +1266,16 @@ gtk_tree_list_row_is_expandable (GtkTreeListRow *self) * * Gets the item corresponding to this row, * - * The value returned by this function never changes until the - * row is destroyed. - * * Returns: (nullable) (type GObject) (transfer full): The item - * of this row or %NULL when the row was destroyed + * of this row. This function is only marked as nullable for backwards + * compatibility reasons. */ gpointer gtk_tree_list_row_get_item (GtkTreeListRow *self) { g_return_val_if_fail (GTK_IS_TREE_LIST_ROW (self), NULL); - if (self->node == NULL) - return NULL; - - return g_object_ref (self->node->item); + return g_object_ref (self->item); } /** diff --git a/testsuite/gtk/defaultvalue.c b/testsuite/gtk/defaultvalue.c index a1ce47c9b0..a9d7053a2d 100644 --- a/testsuite/gtk/defaultvalue.c +++ b/testsuite/gtk/defaultvalue.c @@ -151,6 +151,12 @@ test_type (gconstpointer data) if ((pspec->flags & G_PARAM_READABLE) == 0) continue; + /* This is set by the treelistmodel, plain + * g_object_new() will crash here */ + if (g_type_is_a (type, GTK_TYPE_TREE_LIST_ROW) && + (strcmp (pspec->name, "item") == 0)) + continue; + /* This is set via class_init, and we have a11y tests to verify it */ if (g_type_is_a (type, GTK_TYPE_ACCESSIBLE) && strcmp (pspec->name, "accessible-role") == 0) -- 2.30.2