[gtk+] Correct GtkTreeModelFilter to never unref an already deleted child node
- From: Kristian Rietveld <kristian src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Correct GtkTreeModelFilter to never unref an already deleted child node
- Date: Mon, 22 Aug 2011 19:39:27 +0000 (UTC)
commit e9c960929b1b9deb003f6f2c62d65878d9b23a75
Author: Kristian Rietveld <kris gtk org>
Date: Mon May 9 10:29:37 2011 +0200
Correct GtkTreeModelFilter to never unref an already deleted child node
gtk/gtktreemodelfilter.c | 90 +++++++++++++++++++++++++++------------------
1 files changed, 54 insertions(+), 36 deletions(-)
---
diff --git a/gtk/gtktreemodelfilter.c b/gtk/gtktreemodelfilter.c
index f86ab6c..29e4c03 100644
--- a/gtk/gtktreemodelfilter.c
+++ b/gtk/gtktreemodelfilter.c
@@ -260,7 +260,8 @@ static void gtk_tree_model_filter_build_level (GtkTr
gboolean emit_inserted);
static void gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
- FilterLevel *filter_level);
+ FilterLevel *filter_level,
+ gboolean unref);
static GtkTreePath *gtk_tree_model_filter_elt_get_path (FilterLevel *level,
FilterElt *elt,
@@ -295,7 +296,8 @@ static void gtk_tree_model_filter_set_model (GtkTr
static void gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
GtkTreePath *path);
static void gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
- GtkTreePath *path);
+ GtkTreePath *path,
+ int depth);
static void gtk_tree_model_filter_set_root (GtkTreeModelFilter *filter,
GtkTreePath *root);
@@ -421,7 +423,8 @@ gtk_tree_model_filter_finalize (GObject *object)
if (filter->priv->virtual_root && !filter->priv->virtual_root_deleted)
{
- gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root);
+ gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root,
+ -1);
filter->priv->virtual_root_deleted = TRUE;
}
@@ -431,7 +434,7 @@ gtk_tree_model_filter_finalize (GObject *object)
gtk_tree_path_free (filter->priv->virtual_root);
if (filter->priv->root)
- gtk_tree_model_filter_free_level (filter, filter->priv->root);
+ gtk_tree_model_filter_free_level (filter, filter->priv->root, TRUE);
g_free (filter->priv->modify_types);
@@ -659,12 +662,13 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
}
else if (new_level->array->len == 0)
- gtk_tree_model_filter_free_level (filter, new_level);
+ gtk_tree_model_filter_free_level (filter, new_level, TRUE);
}
static void
gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
- FilterLevel *filter_level)
+ FilterLevel *filter_level,
+ gboolean unref)
{
gint i;
@@ -674,9 +678,11 @@ gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
{
if (g_array_index (filter_level->array, FilterElt, i).children)
gtk_tree_model_filter_free_level (filter,
- FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children));
+ FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children),
+ unref);
- if (filter_level->parent_level || filter->priv->virtual_root)
+ if (unref &&
+ (filter_level->parent_level || filter->priv->virtual_root))
{
GtkTreeIter f_iter;
@@ -865,7 +871,7 @@ gtk_tree_model_filter_clear_cache_helper (GtkTreeModelFilter *filter,
if (level->ref_count == 0 && level != filter->priv->root)
{
- gtk_tree_model_filter_free_level (filter, level);
+ gtk_tree_model_filter_free_level (filter, level, TRUE);
return;
}
}
@@ -1095,7 +1101,7 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
*/
if (elt->children)
- gtk_tree_model_filter_free_level (filter, elt->children);
+ gtk_tree_model_filter_free_level (filter, elt->children, TRUE);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
elt->visible = FALSE;
@@ -1144,7 +1150,7 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
if (elt->children)
{
- gtk_tree_model_filter_free_level (filter, elt->children);
+ gtk_tree_model_filter_free_level (filter, elt->children, TRUE);
elt->children = NULL;
}
@@ -1171,7 +1177,7 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
iter, FALSE);
- gtk_tree_model_filter_free_level (filter, level);
+ gtk_tree_model_filter_free_level (filter, level, TRUE);
}
if (emit_child_toggled)
@@ -1784,24 +1790,31 @@ gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
}
static void
-gtk_tree_model_filter_virtual_root_deleted (GtkTreeModelFilter *filter)
+gtk_tree_model_filter_virtual_root_deleted (GtkTreeModelFilter *filter,
+ GtkTreePath *c_path)
{
gint i;
GtkTreePath *path;
FilterLevel *level = FILTER_LEVEL (filter->priv->root);
- gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root);
+ /* The virtual root (or one of its ancestors) has been deleted. This
+ * means that all content for our model is now gone. We deal with
+ * this by removing everything in the filter model: we just iterate
+ * over the root level and emit a row-deleted for each FilterElt.
+ * (FIXME: Should we emit row-deleted for child nodes as well? This
+ * has never been fully clear in TreeModel).
+ */
+
+ /* We unref the path of the virtual root, up to and not including the
+ * deleted node which can no longer be unreffed.
+ */
+ gtk_tree_model_filter_unref_path (filter, filter->priv->virtual_root,
+ gtk_tree_path_get_depth (c_path) - 1);
filter->priv->virtual_root_deleted = TRUE;
if (!level)
return;
- /* remove everything in the filter model
- *
- * For now, we just iterate over the root level and emit a
- * row_deleted for each FilterElt. Not sure if this is correct.
- */
-
gtk_tree_model_filter_increment_stamp (filter);
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, 0);
@@ -1810,7 +1823,12 @@ gtk_tree_model_filter_virtual_root_deleted (GtkTreeModelFilter *filter)
gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
gtk_tree_path_free (path);
- gtk_tree_model_filter_free_level (filter, filter->priv->root);
+
+ /* We should not propagate the unref here. An unref for any of these
+ * nodes will fail, since the respective nodes in the child model are
+ * no longer there.
+ */
+ gtk_tree_model_filter_free_level (filter, filter->priv->root, FALSE);
}
static void
@@ -1860,7 +1878,7 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
(gtk_tree_path_is_ancestor (c_path, filter->priv->virtual_root) ||
!gtk_tree_path_compare (c_path, filter->priv->virtual_root)))
{
- gtk_tree_model_filter_virtual_root_deleted (filter);
+ gtk_tree_model_filter_virtual_root_deleted (filter, c_path);
return;
}
@@ -1975,28 +1993,23 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
emit_row_deleted = TRUE;
}
- /* The filter model's reference on the child node is released
- * below.
+ /* Release the references on this node, without propagation because
+ * the node does not exist anymore in the child model. The filter
+ * model's references on the node in case of level->parent or use
+ * of a virtual root are automatically destroyed by the child model.
*/
- while (elt->ref_count > 1)
+ while (elt->ref_count > 0)
gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter, FALSE);
if (level->array->len == 1)
{
/* kill level */
- gtk_tree_model_filter_free_level (filter, level);
+ gtk_tree_model_filter_free_level (filter, level, FALSE);
}
else
{
FilterElt *tmp;
- /* release the filter model's reference on the node */
- if (level->parent_level || filter->priv->virtual_root)
- gtk_tree_model_filter_unref_node (GTK_TREE_MODEL (filter), &iter);
- else if (elt->ref_count > 0)
- gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
- FALSE);
-
/* remove the row */
tmp = bsearch_elt_with_offset (level->array, elt->offset, &i);
@@ -2979,7 +2992,7 @@ gtk_tree_model_filter_set_model (GtkTreeModelFilter *filter,
/* reset our state */
if (filter->priv->root)
- gtk_tree_model_filter_free_level (filter, filter->priv->root);
+ gtk_tree_model_filter_free_level (filter, filter->priv->root, TRUE);
filter->priv->root = NULL;
g_object_unref (filter->priv->child_model);
@@ -3042,12 +3055,17 @@ gtk_tree_model_filter_ref_path (GtkTreeModelFilter *filter,
static void
gtk_tree_model_filter_unref_path (GtkTreeModelFilter *filter,
- GtkTreePath *path)
+ GtkTreePath *path,
+ int depth)
{
int len;
GtkTreePath *p;
- len = gtk_tree_path_get_depth (path);
+ if (depth != -1)
+ len = depth;
+ else
+ len = gtk_tree_path_get_depth (path);
+
p = gtk_tree_path_copy (path);
while (len--)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]