[Xfce4-commits] [xfce/thunar] 01/01: Thunar utilizes 100%CPU when the parent directory is not readable (Bug #14900) - as well fixes tree-view not showing the related folder

noreply at xfce.org noreply at xfce.org
Thu Dec 27 23:03:39 CET 2018


This is an automated email from the git hooks/post-receive script.

a   l   e   x       p   u   s   h   e   d       a       c   o   m   m   i   t       t   o       b   r   a   n   c   h       x   f   c   e   -   4   .   1   4   
   in repository xfce/thunar.

commit d75fa9dd5ec3f995551a6d9817e0ffdeeb3b3c5d
Author: Alexander Schwinn <alexxcons at xfce.org>
Date:   Thu Dec 13 23:12:47 2018 +0100

    Thunar utilizes 100%CPU when the parent directory is not readable
    (Bug #14900) - as well fixes tree-view not showing the related folder
---
 thunar/thunar-tree-model.c | 117 +++++++++++++++++++----------
 thunar/thunar-tree-model.h |   5 ++
 thunar/thunar-tree-view.c  | 180 +++++++++++++++------------------------------
 3 files changed, 144 insertions(+), 158 deletions(-)

diff --git a/thunar/thunar-tree-model.c b/thunar/thunar-tree-model.c
index 61f56f2..3424f48 100644
--- a/thunar/thunar-tree-model.c
+++ b/thunar/thunar-tree-model.c
@@ -1239,12 +1239,8 @@ thunar_tree_model_item_files_added (ThunarTreeModelItem *item,
                                     GList               *files,
                                     ThunarFolder        *folder)
 {
-  ThunarTreeModelItem *child_item;
   ThunarTreeModel     *model = THUNAR_TREE_MODEL (item->model);
-  GtkTreePath         *child_path;
-  GtkTreeIter          child_iter;
   ThunarFile          *file;
-  GNode               *child_node;
   GNode               *node = NULL;
   GList               *lp;
 
@@ -1274,40 +1270,7 @@ thunar_tree_model_item_files_added (ThunarTreeModelItem *item,
         node = g_node_find (model->root, G_POST_ORDER, G_TRAVERSE_ALL, item);
       _thunar_return_if_fail (node != NULL);
 
-      /* allocate a new item for the file */
-      child_item = thunar_tree_model_item_new_with_file (model, file);
-
-      /* check if the node has only the dummy child */
-      if (G_UNLIKELY (G_NODE_HAS_DUMMY (node)))
-        {
-          /* replace the dummy node with the new node */
-          child_node = g_node_first_child (node);
-          child_node->data = child_item;
-
-          /* determine the tree iter for the child */
-          GTK_TREE_ITER_INIT (child_iter, model->stamp, child_node);
-
-          /* emit a "row-changed" for the new node */
-          child_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &child_iter);
-          gtk_tree_model_row_changed (GTK_TREE_MODEL (model), child_path, &child_iter);
-          gtk_tree_path_free (child_path);
-        }
-      else
-        {
-          /* insert a new item for the child */
-          child_node = g_node_append_data (node, child_item);
-
-          /* determine the tree iter for the child */
-          GTK_TREE_ITER_INIT (child_iter, model->stamp, child_node);
-
-          /* emit a "row-inserted" for the new 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);
-        }
-
-      /* add a dummy child node */
-      thunar_tree_model_node_insert_dummy (child_node, model);
+      thunar_tree_model_add_child (model, node, file);
     }
 
   /* sort the folders if any new ones were added */
@@ -1893,3 +1856,81 @@ thunar_tree_model_cleanup (ThunarTreeModel *model)
     }
 }
 
+
+
+/**
+ * thunar_tree_model_node_has_dummy:
+ * @model : a #ThunarTreeModel.
+ * @node : GNode to check
+ *
+ * Checks if node is a dummy node ( if it only has a dummy item )
+ *
+ * Return value: %TRUE if @node has a dummy item
+ **/
+gboolean
+thunar_tree_model_node_has_dummy (ThunarTreeModel *model,
+                                  GNode           *node)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_TREE_MODEL (model), TRUE);
+  return G_NODE_HAS_DUMMY(node);
+}
+
+
+
+/**
+ * thunar_tree_model_add_child:
+ * @model : a #ThunarTreeModel.
+ * @node : GNode to add a child
+ * @file : #ThunarFile to be added
+ *
+ * Creates a new #ThunarTreeModelItem as a child of @node and stores a reference to the passed @file
+ * Automatically creates/removes dummy items if required
+ **/
+void
+thunar_tree_model_add_child (ThunarTreeModel *model,
+                             GNode           *node,
+                             ThunarFile      *file)
+{
+  ThunarTreeModelItem *child_item;
+  GNode               *child_node;
+  GtkTreeIter          child_iter;
+  GtkTreePath         *child_path;
+
+  _thunar_return_if_fail (THUNAR_IS_TREE_MODEL (model));
+  _thunar_return_if_fail (THUNAR_IS_FILE (file));
+
+  /* allocate a new item for the file */
+  child_item = thunar_tree_model_item_new_with_file (model, file);
+
+  /* check if the node has only the dummy child */
+  if (G_UNLIKELY (G_NODE_HAS_DUMMY (node)))
+    {
+      /* replace the dummy node with the new node */
+      child_node = g_node_first_child (node);
+      child_node->data = child_item;
+
+      /* determine the tree iter for the child */
+      GTK_TREE_ITER_INIT (child_iter, model->stamp, child_node);
+
+      /* emit a "row-changed" for the new node */
+      child_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &child_iter);
+      gtk_tree_model_row_changed (GTK_TREE_MODEL (model), child_path, &child_iter);
+      gtk_tree_path_free (child_path);
+    }
+  else
+    {
+      /* insert a new item for the child */
+      child_node = g_node_append_data (node, child_item);
+
+      /* determine the tree iter for the child */
+      GTK_TREE_ITER_INIT (child_iter, model->stamp, child_node);
+
+      /* emit a "row-inserted" for the new 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);
+    }
+
+  /* add a dummy to the new child */
+  thunar_tree_model_node_insert_dummy (child_node, model);
+}
diff --git a/thunar/thunar-tree-model.h b/thunar/thunar-tree-model.h
index 0bc0cf2..97b9ecc 100644
--- a/thunar/thunar-tree-model.h
+++ b/thunar/thunar-tree-model.h
@@ -65,6 +65,11 @@ void             thunar_tree_model_set_visible_func   (ThunarTreeModel
 void             thunar_tree_model_refilter           (ThunarTreeModel            *model);
 
 void             thunar_tree_model_cleanup            (ThunarTreeModel            *model);
+gboolean         thunar_tree_model_node_has_dummy     (ThunarTreeModel            *model,
+                                                       GNode                      *node);
+void             thunar_tree_model_add_child          (ThunarTreeModel            *model,
+                                                       GNode                      *node,
+                                                       ThunarFile                 *file);
 
 G_END_DECLS;
 
diff --git a/thunar/thunar-tree-view.c b/thunar/thunar-tree-view.c
index 77048d7..1241bcf 100644
--- a/thunar/thunar-tree-view.c
+++ b/thunar/thunar-tree-view.c
@@ -140,10 +140,6 @@ static GdkDragAction            thunar_tree_view_get_dest_actions             (T
                                                                                gint                     y,
                                                                                guint                    time,
                                                                                ThunarFile             **file_return);
-static gboolean                 thunar_tree_view_find_closest_ancestor        (ThunarTreeView          *view,
-                                                                               GtkTreePath             *path,
-                                                                               GtkTreePath            **ancestor_return,
-                                                                               gboolean                *exact_return);
 static ThunarFile              *thunar_tree_view_get_selected_file            (ThunarTreeView          *view);
 static ThunarDevice            *thunar_tree_view_get_selected_device          (ThunarTreeView          *view);
 static void                     thunar_tree_view_action_copy                  (ThunarTreeView          *view);
@@ -1669,69 +1665,6 @@ thunar_tree_view_get_dest_actions (ThunarTreeView *view,
 
 
 
-static gboolean
-thunar_tree_view_find_closest_ancestor (ThunarTreeView *view,
-                                        GtkTreePath    *path,
-                                        GtkTreePath   **ancestor_return,
-                                        gboolean       *exact_return)
-{
-  GtkTreeModel *model = GTK_TREE_MODEL (view->model);
-  GtkTreePath  *child_path;
-  GtkTreeIter   child_iter;
-  GtkTreeIter   iter;
-  ThunarFile   *file;
-  gboolean      found = FALSE;
-
-  /* determine the iter for the current 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 (model, &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, -1);
-      if (G_UNLIKELY (file == NULL))
-        continue;
-
-      /* check if this is the file we're looking for */
-      if (G_UNLIKELY (file == view->current_directory))
-        {
-          /* we found the very best ancestor 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 (model, &child_iter, &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);
-            }
-
-          /* maybe not exact, but still an ancestor */
-          if (G_UNLIKELY (!found))
-            {
-              /* we found an ancestor, not an exact match */
-              *ancestor_return = gtk_tree_model_get_path (model, &iter);
-              *exact_return = FALSE;
-              found = TRUE;
-            }
-        }
-
-      /* release the file reference */
-      g_object_unref (G_OBJECT (file));
-    }
-  while (!found && gtk_tree_model_iter_next (model, &iter));
-
-  return found;
-}
-
-
-
 static ThunarFile*
 thunar_tree_view_get_selected_file (ThunarTreeView *view)
 {
@@ -2565,12 +2498,14 @@ static gboolean
 thunar_tree_view_cursor_idle (gpointer user_data)
 {
   ThunarTreeView *view = THUNAR_TREE_VIEW (user_data);
-  GtkTreePath    *ancestor = NULL;
-  GtkTreePath    *parent;
   GtkTreePath    *path;
   GtkTreeIter     iter;
   ThunarFile     *file;
+  GtkTreeIter     child_iter;
+  ThunarFile     *file_in_tree;
   gboolean        done = TRUE;
+  GList          *lp;
+  GList          *path_as_list = NULL;
 
 THUNAR_THREADS_ENTER
 
@@ -2580,73 +2515,78 @@ THUNAR_THREADS_ENTER
       gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), view->select_path, NULL, FALSE);
       gtk_tree_path_free (view->select_path);
       view->select_path = NULL;
+      return done;
     }
 
   /* verify that we still have a current directory */
-  else if (G_LIKELY (view->current_directory != NULL))
+  if (G_UNLIKELY (view->current_directory == NULL))
+    return done;
+
+  /* get the preferred toplevel path for the current directory */
+  path = thunar_tree_view_get_preferred_toplevel_path (view, view->current_directory);
+
+  /* fallback to a newly created root node */
+  if (path == NULL)
+    path = gtk_tree_path_new_first ();
+
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (view->model), &iter, path);
+  gtk_tree_path_free (path);
+
+  /* collect all ThunarFiles in the path of current_directory in a List. root is on the very left side */
+  for (file = view->current_directory; file != NULL; file = thunar_file_get_parent (file, NULL))
+      path_as_list = g_list_prepend (path_as_list, file);
+
+  /* note that iter may start at e.g. $HOME where "path_as_list" usually starts at "/" */
+  /* So the first few iterations most times will do nothing */
+  for (lp = path_as_list; lp != NULL; lp = lp->next)
     {
-      /* use the current cursor to limit the search to only the top-level of the selected node */
-      gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &path, NULL);
+      file = THUNAR_FILE (lp->data);
 
-      /* if we have a path from the cursor but the current directory does not match it,
-       * unset it so that the correct toplevel item will be selected later */
-      if (path)
+      /* check if iter has only a dummy node (tree not fully loaded yet) */
+      if( thunar_tree_model_node_has_dummy (view->model, iter.user_data) )
         {
-          gtk_tree_model_get_iter (GTK_TREE_MODEL (view->model), &iter, path);
-          gtk_tree_model_get (GTK_TREE_MODEL (view->model), &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file, -1);
-          if (file != view->current_directory)
+          done = FALSE;
+          break;
+        }
+
+      /* initialize child_iter */
+      if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (view->model), &child_iter, &iter))
+        {
+          /* E.g. folders for which we dont have read permission dont have any child in the tree */
+          /* Make sure that missing read permissions are the problem */
+          if (!g_file_info_get_attribute_boolean (thunar_file_get_info (thunar_file_get_parent (file, NULL)), G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
             {
-              gtk_tree_path_free (path);
-              path = NULL;
+              /* We know that there is a File. Lets just create the required tree-node */
+              thunar_tree_model_add_child (view->model, iter.user_data, file);
+              done = FALSE;
             }
-          if (file)
-            g_object_unref (file);
+          break;
         }
 
-      /* no cursor set, get the preferred toplevel path for the current directory */
-      if (path == NULL)
-        path = thunar_tree_view_get_preferred_toplevel_path (view, view->current_directory);
-
-      /* fallback to a newly created root node */
-      if (path == NULL)
-        path = gtk_tree_path_new_first ();
-
-      /* look for the closest ancestor in the whole tree, starting from the current path */
-      for (; gtk_tree_path_get_depth (path) > 0; gtk_tree_path_up (path))
+      /* loop on children to see if any folder matches  */
+      while (TRUE)
         {
-          /* try to find the closest ancestor relative to the current path */
-          if (thunar_tree_view_find_closest_ancestor (view, path, &ancestor, &done))
+          gtk_tree_model_get (GTK_TREE_MODEL (view->model), &child_iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file_in_tree, -1);
+          if (file == file_in_tree)
             {
-              /* expand to the best ancestor if not an exact match */
-              if (G_LIKELY (!done))
-                {
-                  /* just expand everything up to the row and its children */
-                  gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), ancestor);
-                }
-              else if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), ancestor))
-                {
-                  /* just expand everything up to the row, but not the children */
-                  parent = gtk_tree_path_copy (ancestor);
-                  if (gtk_tree_path_up (parent))
-                    gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), parent);
-                  gtk_tree_path_free (parent);
-                }
-
-              /* place cursor on the ancestor */
-              gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), ancestor, NULL, FALSE);
-
-              /* release the ancestor path */
-              gtk_tree_path_free (ancestor);
-
-              /* we did it */
+              g_object_unref (file_in_tree);
+              path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->model), &child_iter);
+              gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), path);
+              gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, NULL, FALSE);
+              gtk_tree_path_free (path);
+              iter = child_iter; /* next tree level */
               break;
             }
-        }
+          if (file_in_tree)
+            g_object_unref (file_in_tree);
 
-      /* release the tree path */
-      gtk_tree_path_free (path);
+          if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (view->model), &child_iter))
+            break;
+        }
     }
 
+  g_list_free (path_as_list);
+
 THUNAR_THREADS_LEAVE
 
   return !done;
@@ -2896,7 +2836,7 @@ thunar_tree_view_set_show_hidden (ThunarTreeView *view,
  *   4) the root filesystem
  *
  * Returns the #GtkTreePath for the matching toplevel item,
- * or %NULL if not found.
+ * or %NULL if not found. The path should be freed with gtk_tree_path_free().
  **/
 static GtkTreePath *
 thunar_tree_view_get_preferred_toplevel_path (ThunarTreeView *view,

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list