[gtk+] treemodelfilter: correct forgotten unref of parent on level destroy



commit 3db7344f33616983ca0b17b48200cf735679f695
Author: Kristian Rietveld <kris gtk org>
Date:   Sun Sep 11 16:53:27 2011 +0200

    treemodelfilter: correct forgotten unref of parent on level destroy
    
    gtk_tree_model_filter_free_level() should always release ref on parent
    unless the parent has been removed in the child model.  The unit tests
    added in the previous commit test this.

 gtk/gtktreemodelfilter.c |   81 +++++++++++++++++++++++++++++-----------------
 1 files changed, 51 insertions(+), 30 deletions(-)
---
diff --git a/gtk/gtktreemodelfilter.c b/gtk/gtktreemodelfilter.c
index b401a0d..df09dda 100644
--- a/gtk/gtktreemodelfilter.c
+++ b/gtk/gtktreemodelfilter.c
@@ -423,7 +423,8 @@ static void        gtk_tree_model_filter_build_level                      (GtkTr
 
 static void        gtk_tree_model_filter_free_level                       (GtkTreeModelFilter     *filter,
                                                                            FilterLevel            *filter_level,
-                                                                           gboolean                unref,
+                                                                           gboolean                unref_self,
+                                                                           gboolean                unref_parent,
                                                                            gboolean                unref_external);
 
 static GtkTreePath *gtk_tree_model_filter_elt_get_path                    (FilterLevel            *level,
@@ -602,7 +603,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, TRUE, FALSE);
+    gtk_tree_model_filter_free_level (filter, filter->priv->root, TRUE, TRUE, FALSE);
 
   g_free (filter->priv->modify_types);
   
@@ -892,7 +893,7 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
   if (empty &&
        (parent_level && parent_level->ext_ref_count == 0))
     {
-      gtk_tree_model_filter_free_level (filter, new_level, FALSE, FALSE);
+      gtk_tree_model_filter_free_level (filter, new_level, FALSE, TRUE, FALSE);
       return;
     }
 
@@ -931,7 +932,8 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
 static void
 gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
                                   FilterLevel        *filter_level,
-                                  gboolean            unref,
+                                  gboolean            unref_self,
+                                  gboolean            unref_parent,
                                   gboolean            unref_external)
 {
   GSequenceIter *siter;
@@ -947,9 +949,17 @@ gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
       FilterElt *elt = g_sequence_get (siter);
 
       if (elt->children)
-        gtk_tree_model_filter_free_level (filter,
-                                          FILTER_LEVEL (elt->children),
-                                          unref, unref_external);
+        {
+          /* If we recurse and unref_self == FALSE, then unref_parent
+           * must also be FALSE (otherwise a still unref a node in this
+           * level).
+           */
+          gtk_tree_model_filter_free_level (filter,
+                                            FILTER_LEVEL (elt->children),
+                                            unref_self,
+                                            unref_self == FALSE ? FALSE : unref_parent,
+                                            unref_external);
+        }
 
       if (unref_external)
         {
@@ -962,13 +972,13 @@ gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
           while (elt->ext_ref_count > 0)
             gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
                                                    &f_iter,
-                                                   TRUE, unref);
+                                                   TRUE, unref_self);
         }
     }
 
   /* Release the reference on the first item.
    */
-  if (unref)
+  if (unref_self)
     {
       GtkTreeIter f_iter;
 
@@ -1000,17 +1010,14 @@ gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
   if (filter_level->parent_elt)
     {
       /* Release reference on parent */
-      if (unref)
-        {
-          GtkTreeIter parent_iter;
+      GtkTreeIter parent_iter;
 
-          parent_iter.stamp = filter->priv->stamp;
-          parent_iter.user_data = filter_level->parent_level;
-          parent_iter.user_data2 = filter_level->parent_elt;
+      parent_iter.stamp = filter->priv->stamp;
+      parent_iter.user_data = filter_level->parent_level;
+      parent_iter.user_data2 = filter_level->parent_elt;
 
-          gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
-                                                 &parent_iter, FALSE, TRUE);
-        }
+      gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
+                                             &parent_iter, FALSE, unref_parent);
 
       filter_level->parent_elt->children = NULL;
     }
@@ -1052,8 +1059,8 @@ gtk_tree_model_filter_prune_level (GtkTreeModelFilter *filter,
 
       if (elt->children)
         gtk_tree_model_filter_free_level (filter,
-                                          FILTER_LEVEL (elt->children), TRUE,
-                                          TRUE);
+                                          FILTER_LEVEL (elt->children),
+                                          TRUE, TRUE, TRUE);
     }
 
   /* For the first item, only drop the external references */
@@ -1316,7 +1323,7 @@ gtk_tree_model_filter_clear_cache_helper (GtkTreeModelFilter *filter,
       level->parent_level && level->parent_level != filter->priv->root &&
       level->parent_level->ext_ref_count == 0)
     {
-      gtk_tree_model_filter_free_level (filter, level, TRUE, FALSE);
+      gtk_tree_model_filter_free_level (filter, level, TRUE, TRUE, FALSE);
       return;
     }
 }
@@ -1693,7 +1700,7 @@ gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter,
        * the case length == 1.
        */
       if (elt->children)
-        gtk_tree_model_filter_free_level (filter, elt->children, TRUE, TRUE);
+        gtk_tree_model_filter_free_level (filter, elt->children, TRUE, TRUE, TRUE);
 
       /* If the first node is being removed, transfer, the reference */
       if (elt == g_sequence_get (g_sequence_get_begin_iter (level->seq)))
@@ -1751,7 +1758,7 @@ gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter,
              level->parent_level->ext_ref_count > 0))
         {
           /* Otherwise, the level can be removed */
-          gtk_tree_model_filter_free_level (filter, level, TRUE, TRUE);
+          gtk_tree_model_filter_free_level (filter, level, TRUE, TRUE, TRUE);
         }
       else
         {
@@ -1768,7 +1775,7 @@ gtk_tree_model_filter_remove_elt_from_level (GtkTreeModelFilter *filter,
 #endif
               if (elt->children)
                 gtk_tree_model_filter_free_level (filter, elt->children,
-                                                  TRUE, TRUE);
+                                                  TRUE, TRUE, TRUE);
             }
           else
             {
@@ -2422,7 +2429,7 @@ gtk_tree_model_filter_virtual_root_deleted (GtkTreeModelFilter *filter,
    * 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, FALSE);
+  gtk_tree_model_filter_free_level (filter, filter->priv->root, FALSE, TRUE, FALSE);
 
   gtk_tree_model_filter_increment_stamp (filter);
 
@@ -2601,20 +2608,34 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
   while (elt->ext_ref_count > 0)
     gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
                                            TRUE, FALSE);
-  while (elt->ref_count > 0)
-    gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
-                                           FALSE, FALSE);
 
   if (g_sequence_get_length (level->seq) == 1)
     {
+      if (elt->children)
+        /* If this last node has children, then the recursion in free_level
+         * will release this reference.
+         */
+        while (elt->ref_count > 1)
+          gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
+                                                 FALSE, FALSE);
+      else
+        while (elt->ref_count > 0)
+          gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
+                                                 FALSE, FALSE);
+
       /* kill level */
-      gtk_tree_model_filter_free_level (filter, level, FALSE, FALSE);
+      gtk_tree_model_filter_free_level (filter, level, FALSE, TRUE, FALSE);
     }
   else
     {
       GSequenceIter *tmp;
       gboolean is_first;
 
+      /* Release last references, if needed */
+      while (elt->ref_count > 0)
+        gtk_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
+                                               FALSE, FALSE);
+
       lookup_elt_with_offset (level->seq, elt->offset, &siter);
       is_first = g_sequence_get_begin_iter (level->seq) == siter;
 
@@ -3638,7 +3659,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,
-                                          TRUE, FALSE);
+                                          TRUE, TRUE, FALSE);
 
       filter->priv->root = NULL;
       g_object_unref (filter->priv->child_model);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]