Author: jannis
Date: 2008-11-26 16:50:36 +0000 (Wed, 26 Nov 2008)
New Revision: 28917

Modified:
   thunar/trunk/ChangeLog
   thunar/trunk/thunar-vfs/thunar-vfs-monitor.c
   thunar/trunk/thunar/thunar-tree-model.c
   thunar/trunk/thunar/thunar-tree-model.h
   thunar/trunk/thunar/thunar-tree-view.c
Log:
        * thunar-vfs/thunar-vfs-monitor.c, thunar/thunar-tree-model.{c,h},
          thunar/thunar-tree-view.c: Apply tree view pane improvements written
          by Nick. It implements a GtkTreeModelFilter inside the tree model
          and improves CPU performance when expanding folders in the tree
          view. It also stops monitoring tree view folders when they are
          closed. It improves thread safety in ThunarVfsMonitor and a few
          other things. Should fix bug #4051.

Modified: thunar/trunk/ChangeLog
===================================================================
--- thunar/trunk/ChangeLog      2008-11-26 06:46:25 UTC (rev 28916)
+++ thunar/trunk/ChangeLog      2008-11-26 16:50:36 UTC (rev 28917)
@@ -1,3 +1,13 @@
+2008-11-26     Jannis Pohlmann <[EMAIL PROTECTED]>
+
+       * thunar-vfs/thunar-vfs-monitor.c, thunar/thunar-tree-model.{c,h},
+         thunar/thunar-tree-view.c: Apply tree view pane improvements written
+         by Nick. It implements a GtkTreeModelFilter inside the tree model
+         and improves CPU performance when expanding folders in the tree
+         view. It also stops monitoring tree view folders when they are
+         closed. It improves thread safety in ThunarVfsMonitor and a few
+         other things. Should fix bug #4051.
+
 2008-11-25     Jannis Pohlmann <[EMAIL PROTECTED]>
 
        * thunar/thunar-standard-view.c: Make the location selector pop up

Modified: thunar/trunk/thunar/thunar-tree-model.c
===================================================================
--- thunar/trunk/thunar/thunar-tree-model.c     2008-11-26 06:46:25 UTC (rev 
28916)
+++ thunar/trunk/thunar/thunar-tree-model.c     2008-11-26 16:50:36 UTC (rev 
28917)
@@ -40,6 +40,9 @@
 /* convenience macros */
 #define G_NODE(node)                 ((GNode *) (node))
 #define THUNAR_TREE_MODEL_ITEM(item) ((ThunarTreeModelItem *) (item))
+#define G_NODE_HAS_DUMMY(node)       (node->children != NULL \
+                                      && node->children->data == NULL \
+                                      && node->children->next == NULL)
 
 
 
@@ -106,6 +109,9 @@
                                                                        
gpointer                user_data);
 static void                 thunar_tree_model_sort                    
(ThunarTreeModel        *model,
                                                                        GNode   
               *node);
+static void                 thunar_tree_model_unload                  
(ThunarTreeModel        *model);
+static gboolean             thunar_tree_model_unload_idle             
(gpointer                user_data);
+static void                 thunar_tree_model_unload_idle_destroy     
(gpointer                user_data);
 static void                 thunar_tree_model_file_changed            
(ThunarFileMonitor      *file_monitor,
                                                                        
ThunarFile             *file,
                                                                        
ThunarTreeModel        *model);
@@ -127,7 +133,6 @@
 static void                 thunar_tree_model_item_free               
(ThunarTreeModelItem    *item);
 static void                 thunar_tree_model_item_reset              
(ThunarTreeModelItem    *item);
 static void                 thunar_tree_model_item_load_folder        
(ThunarTreeModelItem    *item);
-static void                 thunar_tree_model_item_unload_folder      
(ThunarTreeModelItem    *item);
 static void                 thunar_tree_model_item_files_added        
(ThunarTreeModelItem    *item,
                                                                        GList   
               *files,
                                                                        
ThunarFolder           *folder);
@@ -139,8 +144,12 @@
 static void                 thunar_tree_model_item_notify_loading     
(ThunarTreeModelItem    *item,
                                                                        
GParamSpec             *pspec,
                                                                        
ThunarFolder           *folder);
+static void                 thunar_tree_model_node_insert_dummy       (GNode   
               *parent,
+                                                                       
ThunarTreeModel        *model);
 static void                 thunar_tree_model_node_drop_dummy         (GNode   
               *node,
                                                                        
ThunarTreeModel        *model);
+static gboolean             thunar_tree_model_node_traverse_unload    (GNode   
               *node,
+                                                                       
gpointer                user_data);
 static gboolean             thunar_tree_model_node_traverse_changed   (GNode   
               *node,
                                                                        
gpointer                user_data);
 static gboolean             thunar_tree_model_node_traverse_remove    (GNode   
               *node,
@@ -149,6 +158,8 @@
                                                                        
gpointer                user_data);
 static gboolean             thunar_tree_model_node_traverse_free      (GNode   
               *node,
                                                                        
gpointer                user_data);
+static gboolean             thunar_tree_model_node_traverse_visible   (GNode   
               *node,
+                                                                       
gpointer                user_data);
 
 
 
@@ -159,41 +170,44 @@
 
 struct _ThunarTreeModel
 {
-  GObject                 __parent__;
+  GObject                     __parent__;
 
   /* the model stamp is only used when debugging is
    * enabled, to make sure we don't accept iterators
    * generated by another model.
    */
 #ifndef NDEBUG
-  gint                    stamp;
+  gint                        stamp;
 #endif
 
   /* removable volumes */
-  ThunarVfsVolumeManager *volume_manager;
-  GList                  *hidden_volumes;
+  ThunarVfsVolumeManager     *volume_manager;
+  GList                      *hidden_volumes;
 
-  ThunarFileMonitor      *file_monitor;
+  ThunarFileMonitor          *file_monitor;
 
-  gboolean                sort_case_sensitive;
+  gboolean                    sort_case_sensitive;
 
-  GNode                  *root;
-  
-  /* when this setting is enabled, we do not ref nodes. this is
-   * used to avoid a race condition when gtk traverses the tree
-   * and reads the iter data. See bug #2502.
-   */
-  gboolean                lock_ref_node;
+  ThunarTreeModelVisibleFunc  visible_func;
+  gpointer                    visible_data;
+
+  GNode                      *root;
+
+  guint                       unload_idle_id;
 };
 
 struct _ThunarTreeModelItem
 {
   gint             ref_count;
-  gint             load_idle_id;
+  guint            load_idle_id;
   ThunarFile      *file;
   ThunarFolder    *folder;
   ThunarVfsVolume *volume;
   ThunarTreeModel *model;
+
+  /* list of children of this node that are
+   * not visible in the treeview */
+  GSList          *invisible_children;
 };
 
 typedef struct
@@ -313,7 +327,8 @@
 
   /* initialize the model data */
   model->sort_case_sensitive = TRUE;
-  model->lock_ref_node = FALSE;
+  model->visible_func = (ThunarTreeModelVisibleFunc) exo_noop_true;
+  model->visible_data = NULL;
 
   /* connect to the file monitor */
   model->file_monitor = thunar_file_monitor_get_default ();
@@ -366,6 +381,10 @@
   ThunarTreeModel *model = THUNAR_TREE_MODEL (object);
   GList           *lp;
 
+  /* remove unload idle */
+  if (model->unload_idle_id != 0)
+    g_source_remove (model->unload_idle_id);
+
   /* disconnect from the file monitor */
   g_signal_handlers_disconnect_by_func (G_OBJECT (model->file_monitor), 
thunar_tree_model_file_changed, model);
   g_object_unref (G_OBJECT (model->file_monitor));
@@ -712,7 +731,7 @@
 {
   ThunarTreeModel *model = THUNAR_TREE_MODEL (tree_model);
   GNode           *child;
-  
+
   _thunar_return_val_if_fail (parent == NULL || parent->user_data != NULL, 
FALSE);
   _thunar_return_val_if_fail (parent == NULL || parent->stamp == model->stamp, 
FALSE);
 
@@ -767,10 +786,6 @@
   _thunar_return_if_fail (iter->user_data != NULL);
   _thunar_return_if_fail (iter->stamp == model->stamp);
 
-  /* leave when locked */
-  if (model->lock_ref_node)
-    return;
-
   /* determine the node for the iterator */
   node = G_NODE (iter->user_data);
   if (G_UNLIKELY (node == model->root))
@@ -785,6 +800,10 @@
     }
   else
     {
+      /* schedule a reload of the folder if it is unloaded earlier */
+      if (item->ref_count == 0)
+        thunar_tree_model_item_load_folder (item);
+
       /* increment the reference count */
       item->ref_count += 1;
     }
@@ -812,15 +831,12 @@
   item = node->data;
   if (G_LIKELY (item != NULL))
     {
-      /* check if this was the last reference */
-      if (G_UNLIKELY (item->ref_count == 1))
-        {
-          /* schedule to unload the folder contents */
-          thunar_tree_model_item_unload_folder (item);
-        }
-
       /* decrement the reference count */
       item->ref_count -= 1;
+
+      /* schedule an unload of the tree if an item is released by the treeview 
*/
+      if (G_UNLIKELY (item->ref_count == 0))
+        thunar_tree_model_unload (model);
     }
 }
 
@@ -847,9 +863,9 @@
   GtkTreeIter  iter;
   SortTuple   *sort_array;
   GNode       *child_node;
-  gint         n_children;
+  guint        n_children;
   gint        *new_order;
-  gint         n;
+  guint        n;
 
   /* determine the number of children of the node */
   n_children = g_node_n_children (node);
@@ -905,6 +921,48 @@
 
 
 static void
+thunar_tree_model_unload (ThunarTreeModel *model)
+{
+  /* schedule an idle unload, if not already done */
+  if (model->unload_idle_id == 0)
+    {
+      /* the unload idle has a delay of 500 ms to make sure all the nodes
+       * are unreffed by the treeview. this allows the traverse unref work
+       * more efficiently */
+      model->unload_idle_id = g_timeout_add_full (G_PRIORITY_LOW, 500, 
thunar_tree_model_unload_idle,
+                                                  model, 
thunar_tree_model_unload_idle_destroy);
+    }
+}
+
+
+
+static gboolean
+thunar_tree_model_unload_idle (gpointer user_data)
+{
+  ThunarTreeModel *model = THUNAR_TREE_MODEL (user_data);
+
+  GDK_THREADS_ENTER ();
+
+  /* walk through the tree and release all the nodes with a ref count of 0 */
+  g_node_traverse (model->root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+                   thunar_tree_model_node_traverse_unload, model);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+
+
+static void
+thunar_tree_model_unload_idle_destroy (gpointer user_data)
+{
+  THUNAR_TREE_MODEL (user_data)->unload_idle_id = 0;
+}
+
+
+
+static void
 thunar_tree_model_file_changed (ThunarFileMonitor *file_monitor,
                                 ThunarFile        *file,
                                 ThunarTreeModel   *model)
@@ -915,7 +973,8 @@
   _thunar_return_if_fail (THUNAR_IS_FILE (file));
 
   /* traverse the model and emit "row-changed" for the file's nodes */
-  g_node_traverse (model->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, 
thunar_tree_model_node_traverse_changed, file);
+  if (thunar_file_is_directory (file))
+    g_node_traverse (model->root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, 
thunar_tree_model_node_traverse_changed, file);
 }
 
 
@@ -927,7 +986,6 @@
   ThunarTreeModelItem *item = NULL;
   GtkTreePath         *path;
   GtkTreeIter          iter;
-  GNode               *dummy;
   GNode               *node;
   GList                list;
   GList               *lp;
@@ -961,16 +1019,8 @@
           gtk_tree_path_free (path);
 
           /* add the dummy node */
-          node = g_node_append_data (node, NULL);
+          thunar_tree_model_node_insert_dummy (node, model);
 
-          /* determine the iterator for the dummy node */
-          GTK_TREE_ITER_INIT (iter, model->stamp, node);
-
-          /* tell the view about the dummy node */
-          path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
-          gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
-          gtk_tree_path_free (path);
-
           /* drop our reference on the volume */
           g_object_unref (G_OBJECT (volume));
         }
@@ -1026,15 +1076,7 @@
                 g_node_traverse (node->children, G_POST_ORDER, G_TRAVERSE_ALL, 
-1, thunar_tree_model_node_traverse_remove, model);
 
               /* append the dummy node */
-              dummy = g_node_append_data (node, NULL);
-
-              /* determine the iterator for the dummy node */
-              GTK_TREE_ITER_INIT (iter, model->stamp, dummy);
-
-              /* tell the view about the dummy node */
-              path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
-              gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, 
&iter);
-              gtk_tree_path_free (path);
+              thunar_tree_model_node_insert_dummy (node, model);
             }
 
           /* generate an iterator for the item */
@@ -1055,9 +1097,7 @@
                                       ThunarVfsVolume        *volume,
                                       ThunarTreeModel        *model)
 {
-  GtkTreePath *path;
-  GtkTreeIter  iter;
-  GNode       *node;
+  GNode *node;
 
   _thunar_return_if_fail (THUNAR_VFS_IS_VOLUME_MANAGER (volume_manager));
   _thunar_return_if_fail (THUNAR_VFS_IS_VOLUME (volume));
@@ -1080,15 +1120,7 @@
     g_node_traverse (node->children, G_POST_ORDER, G_TRAVERSE_ALL, -1, 
thunar_tree_model_node_traverse_remove, model);
 
   /* add the dummy node */
-  node = g_node_append_data (node, NULL);
-
-  /* determine the iterator for the dummy node */
-  GTK_TREE_ITER_INIT (iter, model->stamp, node);
-
-  /* tell the view about the dummy node */
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
-  gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
-  gtk_tree_path_free (path);
+  thunar_tree_model_node_insert_dummy (node, model);
 }
 
 
@@ -1240,6 +1272,14 @@
       item->folder = NULL;
     }
 
+  /* free all the invisible children */
+  if (item->invisible_children != NULL)
+    {
+      g_slist_foreach (item->invisible_children, (GFunc) g_object_unref, NULL);
+      g_slist_free (item->invisible_children);
+      item->invisible_children = NULL;
+    }
+
   /* disconnect from the file */
   if (G_LIKELY (item->file != NULL))
     {
@@ -1269,14 +1309,6 @@
 
 
 static void
-thunar_tree_model_item_unload_folder (ThunarTreeModelItem *item)
-{
-  // FIXME: Unload the children of item and add a dummy child
-}
-
-
-
-static void
 thunar_tree_model_item_files_added (ThunarTreeModelItem *item,
                                     GList               *files,
                                     ThunarFolder        *folder)
@@ -1292,6 +1324,7 @@
 
   _thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
   _thunar_return_if_fail (item->folder == folder);
+  _thunar_return_if_fail (model->visible_func != NULL);
 
   /* process all specified files */
   for (lp = files; lp != NULL; lp = lp->next)
@@ -1301,6 +1334,15 @@
       if (!thunar_file_is_directory (file))
         continue;
 
+      /* if this file should be visible */
+      if (!model->visible_func (model, file, model->visible_data))
+        {
+          /* file is invisible, insert it in the invisible list and continue */
+          item->invisible_children = g_slist_prepend (item->invisible_children,
+                                                      g_object_ref (G_OBJECT 
(file)));
+          continue;
+        }
+
       /* lookup the node for the item (on-demand) */
       if (G_UNLIKELY (node == NULL))
         node = g_node_find (model->root, G_POST_ORDER, G_TRAVERSE_ALL, item);
@@ -1309,7 +1351,7 @@
       child_item = thunar_tree_model_item_new_with_file (model, file);
 
       /* check if the node has only the dummy child */
-      if (g_node_n_children (node) == 1 && g_node_first_child (node)->data == 
NULL)
+      if (G_NODE_HAS_DUMMY (node))
         {
           /* replace the dummy node with the new node */
           child_node = g_node_first_child (node);
@@ -1338,15 +1380,7 @@
         }
 
       /* add a dummy child node */
-      child_node = g_node_append_data (child_node, NULL);
-
-      /* determine the tree iter for the dummy */
-      GTK_TREE_ITER_INIT (child_iter, model->stamp, child_node);
-
-      /* emit a "row-inserted" for the dummy node */
-      child_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), 
&child_iter);
-      gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), child_path, 
&child_iter);
-      gtk_tree_path_free (child_path);
+      thunar_tree_model_node_insert_dummy (child_node, model);
     }
 
   /* sort the folders if any new ones were added */
@@ -1367,6 +1401,7 @@
   GNode           *child_node;
   GNode           *node;
   GList           *lp;
+  GSList          *link;
 
   _thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
   _thunar_return_if_fail (item->folder == folder);
@@ -1402,6 +1437,24 @@
           gtk_tree_path_free (path);
         }
     }
+
+  /* we also need to release all the invisible folders */
+  if (item->invisible_children != NULL)
+    {
+      for (lp = files; lp != NULL; lp = lp->next)
+        {
+          /* find the file in the hidden list */
+          link = g_slist_find (item->invisible_children, lp->data);
+          if (link != NULL)
+            {
+              /* release the file */
+              g_object_unref (G_OBJECT (lp->data));
+
+              /* remove from the list */
+              item->invisible_children = g_slist_delete_link 
(item->invisible_children, link);
+            }
+        }
+    }
 }
 
 
@@ -1423,7 +1476,8 @@
       node = g_node_find (item->model->root, G_POST_ORDER, G_TRAVERSE_ALL, 
item);
 
       /* ...and drop the dummy for the node */
-      thunar_tree_model_node_drop_dummy (node, item->model);
+      if (G_NODE_HAS_DUMMY (node))
+        thunar_tree_model_node_drop_dummy (node, item->model);
     }
 }
 
@@ -1436,7 +1490,17 @@
   GList               *files;
 
   _thunar_return_val_if_fail (item->folder == NULL, FALSE);
+  
+#ifndef NDEBUG
+      /* find the node in the tree */
+      GNode *node = g_node_find (item->model->root, G_POST_ORDER, 
G_TRAVERSE_ALL, item);
 
+      /* debug check to make sure the node is empty or contains a dummy node.
+       * if this is not true, the node already contains sub folders which means
+       * something went wrong. */
+      _thunar_return_val_if_fail (node->children == NULL || G_NODE_HAS_DUMMY 
(node), FALSE);
+#endif
+
   GDK_THREADS_ENTER ();
 
   /* check if we don't have a file yet and this is a mounted volume */
@@ -1485,41 +1549,93 @@
 
 
 static void
+thunar_tree_model_node_insert_dummy (GNode           *parent,
+                                     ThunarTreeModel *model)
+{
+  GNode       *node;
+  GtkTreeIter  iter;
+  GtkTreePath *path;
+
+  _thunar_return_if_fail (THUNAR_IS_TREE_MODEL (model));
+  _thunar_return_if_fail (g_node_n_children (parent) == 0);
+
+  /* add the dummy node */
+  node = g_node_append_data (parent, NULL);
+
+  /* determine the iterator for the dummy node */
+  GTK_TREE_ITER_INIT (iter, model->stamp, node);
+
+  /* tell the view about the dummy node */
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+  gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+  gtk_tree_path_free (path);
+}
+
+
+
+static void
 thunar_tree_model_node_drop_dummy (GNode           *node,
                                    ThunarTreeModel *model)
 {
   GtkTreePath *path;
   GtkTreeIter  iter;
 
-  /* check if we still have the dummy child node */
-  if (g_node_n_children (node) == 1 && node->children->data == NULL)
+  _thunar_return_if_fail (THUNAR_IS_TREE_MODEL (model));
+  _thunar_return_if_fail (G_NODE_HAS_DUMMY (node));
+
+  /* determine the iterator for the dummy */
+  GTK_TREE_ITER_INIT (iter, model->stamp, node->children);
+
+  /* determine the path for the iterator */
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+  if (G_LIKELY (path != NULL))
     {
-      /* determine the iterator for the dummy */
-      GTK_TREE_ITER_INIT (iter, model->stamp, node->children);
+      /* notify the view */
+      gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
 
-      /* determine the path for the iterator */
-      path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
-      if (G_LIKELY (path != NULL))
-        {
-          /* notify the view */
-          gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+      /* drop the dummy from the model */
+      g_node_destroy (node->children);
 
-          /* drop the dummy from the model */
-          g_node_destroy (node->children);
+      /* determine the iter to the parent node */
+      GTK_TREE_ITER_INIT (iter, model->stamp, node);
 
-          /* determine the iter to the parent node */
-          GTK_TREE_ITER_INIT (iter, model->stamp, node);
+      /* determine the path to the parent node */
+      gtk_tree_path_up (path);
 
-          /* determine the path to the parent node */
-          gtk_tree_path_up (path);
+      /* emit a "row-has-child-toggled" for the parent */
+      gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, 
&iter);
 
-          /* emit a "row-has-child-toggled" for the parent */
-          gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, 
&iter);
+      /* release the path */
+      gtk_tree_path_free (path);
+    }
+}
 
-          /* release the path */
-          gtk_tree_path_free (path);
-        }
+
+
+static gboolean
+thunar_tree_model_node_traverse_unload (GNode *node,
+                                        gpointer user_data)
+{
+  ThunarTreeModelItem *item = node->data;
+  ThunarTreeModel     *model = THUNAR_TREE_MODEL (user_data);
+
+  if (item && item->folder != NULL && item->ref_count == 0)
+    {
+      /* disconnect from the folder */
+      g_signal_handlers_disconnect_matched (G_OBJECT (item->folder), 
G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, item);
+      g_object_unref (G_OBJECT (item->folder));
+      item->folder = NULL;
+
+      /* remove all the children of the node */
+      while (node->children)
+        g_node_traverse (node->children, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+                         thunar_tree_model_node_traverse_remove, model);
+
+      /* insert a dummy node */
+      thunar_tree_model_node_insert_dummy (node, model);
     }
+
+  return FALSE;
 }
 
 
@@ -1528,13 +1644,14 @@
 thunar_tree_model_node_traverse_changed (GNode   *node,
                                          gpointer user_data)
 {
-  ThunarTreeModel *model;
-  GtkTreePath     *path;
-  GtkTreeIter      iter;
-  ThunarFile      *file = THUNAR_FILE (user_data);
+  ThunarTreeModel     *model;
+  GtkTreePath         *path;
+  GtkTreeIter          iter;
+  ThunarFile          *file = THUNAR_FILE (user_data);
+  ThunarTreeModelItem *item = THUNAR_TREE_MODEL_ITEM (node->data);
 
   /* check if the node's file is the file that changed */
-  if (node->data != NULL && THUNAR_TREE_MODEL_ITEM (node->data)->file == file)
+  if (G_UNLIKELY (item != NULL && item->file == file))
     {
       /* determine the tree model from the item */
       model = THUNAR_TREE_MODEL_ITEM (node->data)->model;
@@ -1557,8 +1674,12 @@
           gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
           gtk_tree_path_free (path);
         }
+
+      /* stop traversing */
+      return TRUE;
     }
 
+  /* continue traversing */
   return FALSE;
 }
 
@@ -1623,6 +1744,96 @@
 
 
 
+static gboolean
+thunar_tree_model_node_traverse_visible (GNode    *node,
+                                         gpointer  user_data)
+{
+  ThunarTreeModelItem *item = node->data;
+  ThunarTreeModel     *model = THUNAR_TREE_MODEL (user_data);
+  GtkTreePath         *path;
+  GtkTreeIter          iter;
+  GNode               *child_node;
+  GSList              *lp, *lnext;
+  ThunarTreeModelItem *parent, *child;
+  ThunarFile          *file;
+
+  _thunar_return_val_if_fail (model->visible_func != NULL, FALSE);
+
+  if (G_LIKELY (item))
+    {
+      /* check if this file should be visibily in the treeview */
+      if (!model->visible_func (model, item->file, model->visible_data))
+        {
+          /* delete all the children of the node */
+          while (node->children)
+            g_node_traverse (node->children, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+                             thunar_tree_model_node_traverse_remove, model);
+
+          /* generate an iterator for the item */
+          GTK_TREE_ITER_INIT (iter, model->stamp, node);
+
+          /* remove this item from the tree */
+          path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+          gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+          gtk_tree_path_free (path);
+
+          /* insert the file in the invisible list of the parent */
+          parent = node->parent->data;
+          if (G_LIKELY (parent))
+            parent->invisible_children = g_slist_prepend 
(parent->invisible_children,
+                                                          g_object_ref 
(G_OBJECT (item->file)));
+
+          /* free the item and destroy the node */
+          thunar_tree_model_item_free (item);
+          g_node_destroy (node);
+        }
+      else
+        {
+          /* this node should be visible. check if the node has invisible
+           * files that should be visible too */
+          for (lp = item->invisible_children, child_node = NULL; lp != NULL; 
lp = lnext)
+            {
+              lnext = lp->next;
+              file = THUNAR_FILE (lp->data);
+
+              if (model->visible_func (model, file, model->visible_data))
+                {
+                  /* allocate a new item for the file */
+                  child = thunar_tree_model_item_new_with_file (model, file);
+
+                  /* insert a new node for the child */
+                  child_node = g_node_append_data (node, child);
+
+                  /* determine the tree iter for the child */
+                  GTK_TREE_ITER_INIT (iter, model->stamp, child_node);
+
+                  /* emit a "row-inserted" for the new node */
+                  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), 
&iter);
+                  gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, 
&iter);
+                  gtk_tree_path_free (path);
+
+                  /* release the reference on the file hold by the invisible 
list */
+                  g_object_unref (G_OBJECT (file));
+
+                  /* delete the file in the list */
+                  item->invisible_children = g_slist_delete_link 
(item->invisible_children, lp);
+
+                  /* insert dummy */
+                  thunar_tree_model_node_insert_dummy (child_node, model);
+                }
+            }
+
+          /* sort this node if one of new children have been added */
+          if (child_node != NULL)
+            thunar_tree_model_sort (model, node);
+        }
+    }
+
+  return FALSE;
+}
+
+
+
 /**
  * thunar_tree_model_get_default:
  *
@@ -1712,11 +1923,44 @@
 
 
 
+/**
+ * thunar_tree_model_set_visible_func:
+ * @model : a #ThunarTreeModel.
+ * @func  : a #ThunarTreeModelVisibleFunc, the visible function.
+ * @data  : User data to pass to the visible function, or %NULL.
+ *
+ * Sets the visible function used when filtering the #ThunarTreeModel.
+ * The function should return %TRUE if the given row should be visible
+ * and %FALSE otherwise.
+ **/
 void
-thunar_tree_model_set_lock_ref_node (ThunarTreeModel *model,
-                                     gboolean         lock_ref_node)
+thunar_tree_model_set_visible_func (ThunarTreeModel            *model,
+                                    ThunarTreeModelVisibleFunc  func,
+                                    gpointer                    data)
 {
   _thunar_return_if_fail (THUNAR_IS_TREE_MODEL (model));
-  
-  model->lock_ref_node = !!lock_ref_node;
+  _thunar_return_if_fail (func != NULL);
+
+  /* set the new visiblity function and user data */
+  model->visible_func = func;
+  model->visible_data = data;
 }
+
+
+
+/**
+ * thunar_tree_model_refilter:
+ * @model : a #ThunarTreeModel.
+ *
+ * Walks all the folders in the #ThunarTreeModel and updates their
+ * visibility.
+ **/
+void
+thunar_tree_model_refilter (ThunarTreeModel *model)
+{
+  _thunar_return_if_fail (THUNAR_IS_TREE_MODEL (model));
+
+  /* traverse all nodes to update their visibility */
+  g_node_traverse (model->root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+                   thunar_tree_model_node_traverse_visible, model);
+}

Modified: thunar/trunk/thunar/thunar-tree-model.h
===================================================================
--- thunar/trunk/thunar/thunar-tree-model.h     2008-11-26 06:46:25 UTC (rev 
28916)
+++ thunar/trunk/thunar/thunar-tree-model.h     2008-11-26 16:50:36 UTC (rev 
28917)
@@ -27,6 +27,10 @@
 typedef struct _ThunarTreeModelClass ThunarTreeModelClass;
 typedef struct _ThunarTreeModel      ThunarTreeModel;
 
+typedef gboolean (* ThunarTreeModelVisibleFunc) (ThunarTreeModel *model,
+                                                 ThunarFile      *file,
+                                                 gpointer         data);
+
 #define THUNAR_TYPE_TREE_MODEL            (thunar_tree_model_get_type ())
 #define THUNAR_TREE_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
THUNAR_TYPE_TREE_MODEL, ThunarTreeModel))
 #define THUNAR_TREE_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
THUNAR_TYPE_TREE_MODEL, ThunarTreeModelClass))
@@ -57,12 +61,14 @@
 
 ThunarTreeModel *thunar_tree_model_get_default        (void);
 
-gboolean         thunar_tree_model_get_case_sensitive (ThunarTreeModel *model);
-void             thunar_tree_model_set_case_sensitive (ThunarTreeModel *model,
-                                                       gboolean         
case_sensitive);
+gboolean         thunar_tree_model_get_case_sensitive (ThunarTreeModel         
   *model);
+void             thunar_tree_model_set_case_sensitive (ThunarTreeModel         
   *model,
+                                                       gboolean                
    case_sensitive);
 
-void             thunar_tree_model_set_lock_ref_node  (ThunarTreeModel *model,
-                                                       gboolean         
lock_ref_node);
+void             thunar_tree_model_set_visible_func   (ThunarTreeModel         
   *model,
+                                                       
ThunarTreeModelVisibleFunc  func,
+                                                       gpointer                
    data);
+void             thunar_tree_model_refilter           (ThunarTreeModel         
   *model);
 
 G_END_DECLS;
 

Modified: thunar/trunk/thunar/thunar-tree-view.c
===================================================================
--- thunar/trunk/thunar/thunar-tree-view.c      2008-11-26 06:46:25 UTC (rev 
28916)
+++ thunar/trunk/thunar/thunar-tree-view.c      2008-11-26 16:50:36 UTC (rev 
28917)
@@ -118,7 +118,7 @@
 static gboolean         thunar_tree_view_delete_selected_files      
(ThunarTreeView       *view);
 static void             thunar_tree_view_context_menu               
(ThunarTreeView       *view,
                                                                      
GdkEventButton       *event,
-                                                                     
GtkTreeModel         *filter,
+                                                                     
GtkTreeModel         *model,
                                                                      
GtkTreeIter          *iter);
 static GdkDragAction    thunar_tree_view_get_dest_actions           
(ThunarTreeView       *view,
                                                                      
GdkDragContext       *context,
@@ -148,8 +148,8 @@
 static void             thunar_tree_view_new_files                  
(ThunarVfsJob         *job,
                                                                      GList     
           *path_list,
                                                                      
ThunarTreeView       *view);
-static gboolean         thunar_tree_view_filter_visible_func        
(GtkTreeModel         *filter,
-                                                                     
GtkTreeIter          *iter,
+static gboolean         thunar_tree_view_visible_func               
(ThunarTreeModel      *model,
+                                                                     
ThunarFile           *file,
                                                                      gpointer  
            user_data);
 static gboolean         thunar_tree_view_selection_func             
(GtkTreeSelection     *selection,
                                                                      
GtkTreeModel         *model,
@@ -361,7 +361,6 @@
   GtkTreeViewColumn *column;
   GtkTreeSelection  *selection;
   GtkCellRenderer   *renderer;
-  GtkTreeModel      *filter;
 
   /* initialize the view internals */
   view->cursor_idle_id = -1;
@@ -376,13 +375,9 @@
 
   /* connect to the default tree model */
   view->model = thunar_tree_model_get_default ();
+  thunar_tree_model_set_visible_func (view->model, 
thunar_tree_view_visible_func, view);
+  gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (view->model));
 
-  /* setup the filter for the tree view */
-  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (view->model), NULL);
-  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), 
thunar_tree_view_filter_visible_func, view, NULL);
-  gtk_tree_view_set_model (GTK_TREE_VIEW (view), filter);
-  g_object_unref (G_OBJECT (filter));
-
   /* configure the tree view */
   gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
@@ -543,7 +538,7 @@
                                         ThunarFile      *current_directory)
 {
   ThunarTreeView *view = THUNAR_TREE_VIEW (navigator);
-  GtkTreeModel   *filter;
+  ThunarFile     *file, *file_parent;
 
   /* check if we already use that directory */
   if (G_UNLIKELY (view->current_directory == current_directory))
@@ -562,11 +557,30 @@
       /* take a reference on the directory */
       g_object_ref (G_OBJECT (current_directory));
 
-      /* update the filter if the new current directory is hidden */
-      if (!view->show_hidden && thunar_file_is_hidden (current_directory))
+      /* update the filter if the new current directory, or one of it's 
parents, is hidden */
+      if (!view->show_hidden)
         {
-          filter = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
-          gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
+          /* look if the file or one of it's parents is hidden */
+          for (file = g_object_ref (G_OBJECT (current_directory)); file != 
NULL; file = file_parent)
+            {
+              /* check if this file is hidden */
+              if (thunar_file_is_hidden (file))
+                {
+                  /* update the filter */
+                  thunar_tree_model_refilter (view->model);
+
+                  /* release the file */
+                  g_object_unref (G_OBJECT (file));
+
+                  break;
+                }
+
+              /* get the file parent */
+              file_parent = thunar_file_get_parent (file, NULL);
+
+              /* release the file */
+              g_object_unref (G_OBJECT (file));
+            }
         }
 
       /* schedule an idle source to set the cursor to the current directory */
@@ -624,7 +638,6 @@
                                      GdkEventButton *event)
 {
   ThunarTreeView *view = THUNAR_TREE_VIEW (widget);
-  GtkTreeModel   *filter;
   GtkTreePath    *path;
   GtkTreeIter     iter;
   gboolean        result;
@@ -646,11 +659,10 @@
       if (G_UNLIKELY (event->button == 3 && event->type == GDK_BUTTON_PRESS))
         {
           /* determine the iterator for the path */
-          filter = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
-          if (gtk_tree_model_get_iter (filter, &iter, path))
+          if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->model), &iter, 
path))
             {
               /* popup the context menu */
-              thunar_tree_view_context_menu (view, event, filter, &iter);
+              thunar_tree_view_context_menu (view, event, GTK_TREE_MODEL 
(view->model), &iter);
 
               /* we effectively handled the event */
               result = TRUE;
@@ -875,15 +887,15 @@
 {
   GtkTreeSelection *selection;
   ThunarTreeView   *view = THUNAR_TREE_VIEW (widget);
-  GtkTreeModel     *filter;
+  GtkTreeModel     *model;
   GtkTreeIter       iter;
 
   /* determine the selected row */
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
-  if (gtk_tree_selection_get_selected (selection, &filter, &iter))
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
     {
       /* popup the context menu */
-      thunar_tree_view_context_menu (view, NULL, filter, &iter);
+      thunar_tree_view_context_menu (view, NULL, model, &iter);
       return TRUE;
     }
   else if (GTK_WIDGET_CLASS (thunar_tree_view_parent_class)->popup_menu != 
NULL)
@@ -927,14 +939,12 @@
 {
   ThunarVfsVolume *volume;
   ThunarTreeView  *view = THUNAR_TREE_VIEW (tree_view);
-  GtkTreeModel    *filter;
   GtkWidget       *window;
   gboolean         expandable = TRUE;
   GError          *error = NULL;
 
   /* determine the volume for the iterator */
-  filter = gtk_tree_view_get_model (tree_view);
-  gtk_tree_model_get (filter, iter, THUNAR_TREE_MODEL_COLUMN_VOLUME, &volume, 
-1);
+  gtk_tree_model_get (GTK_TREE_MODEL (view->model), iter, 
THUNAR_TREE_MODEL_COLUMN_VOLUME, &volume, -1);
 
   /* check if we have a volume */
   if (G_UNLIKELY (volume != NULL))
@@ -985,7 +995,7 @@
 static void
 thunar_tree_view_context_menu (ThunarTreeView *view,
                                GdkEventButton *event,
-                               GtkTreeModel   *filter,
+                               GtkTreeModel   *model,
                                GtkTreeIter    *iter)
 {
   ThunarVfsVolume *volume;
@@ -1000,7 +1010,7 @@
     return;
 
   /* determine the file and volume for the given iter */
-  gtk_tree_model_get (filter, iter,
+  gtk_tree_model_get (model, iter,
                       THUNAR_TREE_MODEL_COLUMN_FILE, &file,
                       THUNAR_TREE_MODEL_COLUMN_VOLUME, &volume,
                       -1);
@@ -1209,7 +1219,6 @@
 {
   GdkDragAction actions = 0;
   GdkDragAction action = 0;
-  GtkTreeModel *filter;
   GtkTreePath  *path = NULL;
   GtkTreeIter   iter;
   ThunarFile   *file = NULL;
@@ -1221,14 +1230,11 @@
   /* determine the path for x/y */
   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), x, y, &path, NULL, 
NULL, NULL))
     {
-      /* determine the tree model filter */
-      filter = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
-
       /* determine the iter for the given path */
-      if (gtk_tree_model_get_iter (filter, &iter, path))
+      if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->model), &iter, path))
         {
           /* determine the file for the given path */
-          gtk_tree_model_get (filter, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, 
&file, -1);
+          gtk_tree_model_get (GTK_TREE_MODEL (view->model), &iter, 
THUNAR_TREE_MODEL_COLUMN_FILE, &file, -1);
           if (G_LIKELY (file != NULL))
             {
               /* check if the file accepts the drop */
@@ -1288,7 +1294,7 @@
                                         GtkTreePath   **ancestor_return,
                                         gboolean       *exact_return)
 {
-  GtkTreeModel *filter;
+  GtkTreeModel *model = GTK_TREE_MODEL (view->model);
   GtkTreePath  *child_path;
   GtkTreeIter   child_iter;
   GtkTreeIter   iter;
@@ -1296,15 +1302,14 @@
   gboolean      found = FALSE;
 
   /* determine the iter for the current path */
-  filter = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
-  if (!gtk_tree_model_get_iter (filter, &iter, path))
+  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (view->model), &iter, path))
     return FALSE;
 
   /* process all items at this level */
   do
     {
       /* check if the file for iter is an ancestor of the current directory */
-      gtk_tree_model_get (filter, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, 
-1);
+      gtk_tree_model_get (model, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, 
-1);
       if (G_UNLIKELY (file == NULL))
         continue;
 
@@ -1312,16 +1317,16 @@
       if (G_UNLIKELY (file == view->current_directory))
         {
           /* we found the very best ancestor iter! */
-          *ancestor_return = gtk_tree_model_get_path (filter, &iter);
+          *ancestor_return = gtk_tree_model_get_path (model, &iter);
           *exact_return = TRUE;
           found = TRUE;
         }
       else if (thunar_file_is_ancestor (view->current_directory, file))
         {
           /* check if we can find an even better ancestor below this node */
-          if (gtk_tree_model_iter_children (filter, &child_iter, &iter))
+          if (gtk_tree_model_iter_children (model, &child_iter, &iter))
             {
-              child_path = gtk_tree_model_get_path (filter, &child_iter);
+              child_path = gtk_tree_model_get_path (model, &child_iter);
               found = thunar_tree_view_find_closest_ancestor (view, 
child_path, ancestor_return, exact_return);
               gtk_tree_path_free (child_path);
             }
@@ -1330,7 +1335,7 @@
           if (G_UNLIKELY (!found))
             {
               /* we found an ancestor, not an exact match */
-              *ancestor_return = gtk_tree_model_get_path (filter, &iter);
+              *ancestor_return = gtk_tree_model_get_path (model, &iter);
               *exact_return = FALSE;
               found = TRUE;
             }
@@ -1339,7 +1344,7 @@
       /* release the file reference */
       g_object_unref (G_OBJECT (file));
     }
-  while (!found && gtk_tree_model_iter_next (filter, &iter));
+  while (!found && gtk_tree_model_iter_next (model, &iter));
 
   return found;
 }
@@ -1350,14 +1355,14 @@
 thunar_tree_view_get_selected_file (ThunarTreeView *view)
 {
   GtkTreeSelection *selection;
-  GtkTreeModel     *filter;
+  GtkTreeModel     *model;
   GtkTreeIter       iter;
   ThunarFile       *file = NULL;
 
   /* determine file for the selected row */
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
-  if (gtk_tree_selection_get_selected (selection, &filter, &iter))
-    gtk_tree_model_get (filter, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, 
-1);
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    gtk_tree_model_get (model, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, 
-1);
 
   return file;
 }
@@ -1369,13 +1374,13 @@
 {
   GtkTreeSelection *selection;
   ThunarVfsVolume  *volume = NULL;
-  GtkTreeModel     *filter;
+  GtkTreeModel     *model;
   GtkTreeIter       iter;
 
   /* determine file for the selected row */
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
-  if (gtk_tree_selection_get_selected (selection, &filter, &iter))
-    gtk_tree_model_get (filter, &iter, THUNAR_TREE_MODEL_COLUMN_VOLUME, 
&volume, -1);
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    gtk_tree_model_get (model, &iter, THUNAR_TREE_MODEL_COLUMN_VOLUME, 
&volume, -1);
 
   return volume;
 }
@@ -1538,7 +1543,7 @@
     {
       /* determine the toplevel window */
       window = gtk_widget_get_toplevel (GTK_WIDGET (view));
-      
+
       /* try to eject the volume */
       if (!thunar_vfs_volume_eject (volume, window, &error))
         {
@@ -1789,28 +1794,22 @@
 
 
 static gboolean
-thunar_tree_view_filter_visible_func (GtkTreeModel *filter,
-                                      GtkTreeIter  *iter,
-                                      gpointer      user_data)
+thunar_tree_view_visible_func (ThunarTreeModel *model,
+                               ThunarFile      *file,
+                               gpointer         user_data)
 {
   ThunarTreeView *view = THUNAR_TREE_VIEW (user_data);
-  ThunarFile     *file;
   gboolean        visible = TRUE;
 
+  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
+  _thunar_return_val_if_fail (THUNAR_IS_TREE_MODEL (model), FALSE);
+
   /* if show_hidden is TRUE, nothing is filtered */
   if (G_LIKELY (!view->show_hidden))
     {
-      /* check if we should display this row */
-      gtk_tree_model_get (filter, iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, 
-1);
-      if (G_LIKELY (file != NULL))
-        {
-          /* we display all non-hidden file and hidden files that are 
ancestors of the current directory */
-          visible = !thunar_file_is_hidden (file) || (view->current_directory 
== file)
-                 || (view->current_directory != NULL && 
thunar_file_is_ancestor (view->current_directory, file));
-
-          /* release the reference on the file */
-          g_object_unref (G_OBJECT (file));
-        }
+      /* we display all non-hidden file and hidden files that are ancestors of 
the current directory */
+      visible = !thunar_file_is_hidden (file) || (view->current_directory == 
file)
+                || (view->current_directory != NULL && thunar_file_is_ancestor 
(view->current_directory, file));
     }
 
   return visible;
@@ -1820,7 +1819,7 @@
 
 static gboolean
 thunar_tree_view_selection_func (GtkTreeSelection *selection,
-                                 GtkTreeModel     *filter,
+                                 GtkTreeModel     *model,
                                  GtkTreePath      *path,
                                  gboolean          path_currently_selected,
                                  gpointer          user_data)
@@ -1835,10 +1834,10 @@
     return TRUE;
 
   /* determine the iterator for the path */
-  if (gtk_tree_model_get_iter (filter, &iter, path))
+  if (gtk_tree_model_get_iter (model, &iter, path))
     {
       /* determine the file for the iterator */
-      gtk_tree_model_get (filter, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, 
-1);
+      gtk_tree_model_get (model, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, 
-1);
       if (G_LIKELY (file != NULL))
         {
           /* rows with files can be selected */
@@ -1850,7 +1849,7 @@
       else
         {
           /* but maybe the row has a volume */
-          gtk_tree_model_get (filter, &iter, THUNAR_TREE_MODEL_COLUMN_VOLUME, 
&volume, -1);
+          gtk_tree_model_get (model, &iter, THUNAR_TREE_MODEL_COLUMN_VOLUME, 
&volume, -1);
           if (G_LIKELY (volume != NULL))
             {
               /* rows with volumes can also be selected */
@@ -2120,9 +2119,8 @@
 thunar_tree_view_set_show_hidden (ThunarTreeView *view,
                                   gboolean        show_hidden)
 {
-  GtkTreeModel *filter;
-
   _thunar_return_if_fail (THUNAR_IS_TREE_VIEW (view));
+  _thunar_return_if_fail (THUNAR_IS_TREE_MODEL (view->model));
 
   /* normalize the value */
   show_hidden = !!show_hidden;
@@ -2133,19 +2131,10 @@
       /* apply the new setting */
       view->show_hidden = show_hidden;
 
-      /* lock loading nodes in the tree, see bug #2505 */
-      thunar_tree_model_set_lock_ref_node (THUNAR_TREE_MODEL (view->model), 
TRUE);
+      /* update the model */
+      thunar_tree_model_refilter (view->model);
 
-      /* update the filter */
-      filter = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
-      gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
-
-      /* release the lock */
-      thunar_tree_model_set_lock_ref_node (THUNAR_TREE_MODEL (view->model), 
FALSE);
-
       /* notify listeners */
       g_object_notify (G_OBJECT (view), "show-hidden");
     }
 }
-
-

Modified: thunar/trunk/thunar-vfs/thunar-vfs-monitor.c
===================================================================
--- thunar/trunk/thunar-vfs/thunar-vfs-monitor.c        2008-11-26 06:46:25 UTC 
(rev 28916)
+++ thunar/trunk/thunar-vfs/thunar-vfs-monitor.c        2008-11-26 16:50:36 UTC 
(rev 28917)
@@ -68,6 +68,7 @@
 static gboolean thunar_vfs_monitor_notifications_timer  (gpointer              
 user_data);
 #ifdef HAVE_LIBFAM
 static void     thunar_vfs_monitor_fam_cancel           (ThunarVfsMonitor      
*monitor);
+static gboolean thunar_vfs_monitor_fam_process_events   (ThunarVfsMonitor      
*monitor);
 static gboolean thunar_vfs_monitor_fam_watch            (GIOChannel            
*channel,
                                                          GIOCondition          
 condition,
                                                          gpointer              
 user_data);
@@ -409,32 +410,26 @@
 
 
 static gboolean
-thunar_vfs_monitor_fam_watch (GIOChannel  *channel,
-                              GIOCondition condition,
-                              gpointer     user_data)
+thunar_vfs_monitor_fam_process_events (ThunarVfsMonitor *monitor)
 {
   ThunarVfsMonitorEvent event;
-  ThunarVfsMonitor     *monitor = THUNAR_VFS_MONITOR (user_data);
   FAMEvent              fe;
 
-  /* check for an error on the FAM connection */
-  if (G_UNLIKELY ((condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) != 0))
-    {
-error:
-      /* terminate the FAM connection */
-      thunar_vfs_monitor_fam_cancel (monitor);
+  _thunar_vfs_return_val_if_fail (THUNAR_VFS_IS_MONITOR (monitor), FALSE);
 
-      /* thats it, no more FAM */
-      return FALSE;
-    }
-
   /* process all pending FAM events */
   while (FAMPending (&monitor->fc))
     {
       /* query the next pending event */
       if (G_UNLIKELY (FAMNextEvent (&monitor->fc, &fe) < 0))
-        goto error;
+        {
+          /* terminate the FAM connection */
+          thunar_vfs_monitor_fam_cancel (monitor);
 
+          /* thats it, no more FAM */
+          return FALSE;
+        }
+
       /* translate the event code */
       switch (fe.code)
         {
@@ -456,13 +451,42 @@
         }
 
       /* schedule a notification for the monitor */
-      g_mutex_lock (monitor->lock);
       thunar_vfs_monitor_queue_notification (monitor, fe.fr.reqnum, 
THUNAR_VFS_MONITOR_TAG_FAM, event, fe.filename);
-      g_mutex_unlock (monitor->lock);
     }
 
   return TRUE;
 }
+
+
+
+static gboolean
+thunar_vfs_monitor_fam_watch (GIOChannel  *channel,
+                              GIOCondition condition,
+                              gpointer     user_data)
+{
+  ThunarVfsMonitor *monitor = THUNAR_VFS_MONITOR (user_data);
+  gboolean          result = FALSE;
+  
+  /* acquire the monitor lock */
+  g_mutex_lock (monitor->lock);
+
+  /* check for an error on the FAM connection */
+  if (G_UNLIKELY ((condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) != 0))
+    {
+      /* terminate the FAM connection */
+      thunar_vfs_monitor_fam_cancel (monitor);
+    }
+  else
+    {
+      /* process all pending FAM events */
+      result = thunar_vfs_monitor_fam_process_events (monitor);
+    }
+
+  /* release the monitor lock */
+  g_mutex_unlock (monitor->lock);
+
+  return result;
+}
 #endif
 
 
@@ -634,8 +658,14 @@
   /* drop the FAM request from the daemon */
   if (G_LIKELY (monitor->fc_watch_id >= 0 && _thunar_vfs_path_is_local 
(handle->path)))
     {
-      if (FAMCancelMonitor (&monitor->fc, &handle->fr) < 0)
-        thunar_vfs_monitor_fam_cancel (monitor);
+      /* make sure there are no pending events before removing the request.
+       * if we don't do this, fam will lock up when a lot of requests are
+       * removed in a short time (collapse a treeview node for example) */
+      if (thunar_vfs_monitor_fam_process_events (monitor))
+        {
+          if (FAMCancelMonitor (&monitor->fc, &handle->fr) < 0)
+            thunar_vfs_monitor_fam_cancel (monitor);
+        }
     }
 #endif
 

_______________________________________________
Xfce4-commits mailing list
Xfce4-commits@xfce.org
http://foo-projects.org/mailman/listinfo/xfce4-commits

Reply via email to