[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