treelistmodel: Track the item in the row
authorBenjamin Otte <otte@redhat.com>
Sun, 19 Mar 2023 04:22:46 +0000 (05:22 +0100)
committerBenjamin Otte <otte@redhat.com>
Sun, 19 Mar 2023 05:55:05 +0000 (06:55 +0100)
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
testsuite/gtk/defaultvalue.c

index 775e3112149c8c3ea1df84293b90a36131792759..fe9240e4b41158a731b305af739015333ce0681b 100644 (file)
@@ -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);
 }
 
 /**
index a1ce47c9b0c31dae53da000b4acf0539d93d7ab7..a9d7053a2db8363910b004cbdf90d5867624a576 100644 (file)
@@ -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)