summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErnestas Kulik <ernestask@gnome.org>2017-07-14 17:24:31 +0300
committerCarlos Soriano <csoriano@gnome.org>2018-01-20 00:24:04 +0100
commitbcfbdc7d2e758ce5a2b44226166a21954dae8eca (patch)
tree8fbc1818f66a0a6ea7423d90b333f712f7b8c6c9
parent0f8c1b37bab150ec99803464fb889a83d155b023 (diff)
downloadnautilus-bcfbdc7d2e758ce5a2b44226166a21954dae8eca.tar.gz
Can’t be arsed to split this :|
-rw-r--r--src-ng/main.c64
-rw-r--r--src-ng/meson.build4
-rw-r--r--src-ng/nautilus-cache.c259
-rw-r--r--src-ng/nautilus-cache.h59
-rw-r--r--src-ng/nautilus-directory.c160
-rw-r--r--src-ng/nautilus-directory.h10
-rw-r--r--src-ng/nautilus-file.c99
-rw-r--r--src-ng/nautilus-file.h9
-rw-r--r--src-ng/nautilus-marshallers.list1
-rw-r--r--src-ng/nautilus-task-manager.c2
-rw-r--r--src-ng/tasks/nautilus-attribute-task.c98
-rw-r--r--src-ng/tasks/nautilus-enumerate-children-task.c141
-rw-r--r--src-ng/tasks/nautilus-enumerate-children-task.h38
13 files changed, 830 insertions, 114 deletions
diff --git a/src-ng/main.c b/src-ng/main.c
index f5474bb79..49a328189 100644
--- a/src-ng/main.c
+++ b/src-ng/main.c
@@ -14,12 +14,51 @@ got_info (NautilusFile *file,
{
g_message ("Got info for %p",
(gpointer) file);
- g_message ("\tDisplay name: %s\n",
+ g_message ("\tDisplay name: %s",
g_file_info_get_display_name (info));
+ g_message ("\tFile is directory: %s\n",
+ NAUTILUS_IS_DIRECTORY (file)? "yes" : "no");
g_object_unref (info);
- g_main_loop_quit ((GMainLoop *) user_data);
+ if (user_data != NULL)
+ {
+ g_main_loop_quit ((GMainLoop *) user_data);
+ }
+}
+
+static void
+got_children (NautilusDirectory *directory,
+ GList *children,
+ GError *error,
+ gpointer user_data)
+{
+ g_message ("Got children for %p", (gpointer) directory);
+
+ if (children == NULL)
+ {
+ g_list_free (children);
+
+ g_main_loop_quit ((GMainLoop *) user_data);
+
+ return;
+ }
+
+ for (GList *i = children; i != NULL; i = i->next)
+ {
+ if (G_UNLIKELY (i->next == NULL))
+ {
+ nautilus_file_query_info (NAUTILUS_FILE (i->data),
+ NULL, got_info, user_data);
+ }
+ else
+ {
+ nautilus_file_query_info (NAUTILUS_FILE (i->data),
+ NULL, got_info, NULL);
+ }
+ }
+
+ g_list_free (children);
}
int
@@ -43,9 +82,7 @@ main (int argc,
g_message ("Creating NautilusFile");
file = nautilus_file_new (location);
- g_message ("\tGot %p", (gpointer) file);
- g_message ("\tFile is directory: %s\n",
- NAUTILUS_IS_DIRECTORY (file)? "yes" : "no");
+ g_message ("\tGot %p\n", (gpointer) file);
g_message ("Creating another NautilusFile for the same location");
duplicate_file = nautilus_file_new (location);
@@ -55,7 +92,22 @@ main (int argc,
loop = g_main_loop_new (NULL, TRUE);
- nautilus_file_query_info (file, NULL, got_info, loop);
+ if (NAUTILUS_IS_DIRECTORY (file))
+ {
+ nautilus_file_query_info (file, NULL, got_info, NULL);
+ }
+ else
+ {
+ nautilus_file_query_info (file, NULL, got_info, loop);
+ }
+
+ if (NAUTILUS_IS_DIRECTORY (file))
+ {
+ nautilus_directory_enumerate_children (NAUTILUS_DIRECTORY (file),
+ NULL,
+ got_children,
+ loop);
+ }
g_main_loop_run (loop);
diff --git a/src-ng/meson.build b/src-ng/meson.build
index 8f1fec6ee..aa6288410 100644
--- a/src-ng/meson.build
+++ b/src-ng/meson.build
@@ -8,6 +8,10 @@ nautilus_ng_sources = ['nautilus-task.c',
'tasks/nautilus-attribute-task.h',
'nautilus-directory.c',
'nautilus-directory.h',
+ 'tasks/nautilus-enumerate-children-task.c',
+ 'tasks/nautilus-enumerate-children-task.h',
+ 'nautilus-cache.c',
+ 'nautilus-cache.h',
'main.c']
nautilus_ng_dependencies = [gio, glib]
diff --git a/src-ng/nautilus-cache.c b/src-ng/nautilus-cache.c
new file mode 100644
index 000000000..f27a6d904
--- /dev/null
+++ b/src-ng/nautilus-cache.c
@@ -0,0 +1,259 @@
+/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nautilus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-cache.h"
+
+typedef struct
+{
+ gpointer value;
+ GDestroyNotify destroy_func;
+
+ NautilusCacheState state;
+
+ GMutex mutex;
+} CacheItemDetails;
+
+struct _NautilusCache
+{
+ GObject parent_instance;
+
+ GHashTable *items;
+};
+
+G_DEFINE_TYPE (NautilusCache, nautilus_cache, G_TYPE_OBJECT)
+
+static CacheItemDetails *
+cache_item_details_new (GDestroyNotify destroy_func)
+{
+ CacheItemDetails *details;
+
+ details = g_new0 (CacheItemDetails, 1);
+
+ details->destroy_func = destroy_func;
+
+ g_mutex_init (&details->mutex);
+
+ return details;
+}
+
+static void
+cache_item_details_destroy (CacheItemDetails *details)
+{
+ if (details->destroy_func != NULL)
+ {
+ details->destroy_func (details->value);
+ }
+ g_mutex_clear (&details->mutex);
+ g_free (details);
+}
+
+static void
+finalize (GObject *object)
+{
+ NautilusCache *self;
+
+ self = NAUTILUS_CACHE (object);
+
+ g_hash_table_destroy (self->items);
+
+ G_OBJECT_CLASS (nautilus_cache_parent_class)->finalize (object);
+}
+
+static void
+nautilus_cache_class_init (NautilusCacheClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = finalize;
+}
+
+static void
+nautilus_cache_init (NautilusCache *self)
+{
+ self->items =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL,
+ (GDestroyNotify) cache_item_details_destroy);
+}
+
+NautilusCacheState
+nautilus_cache_item_get_state (NautilusCache *cache,
+ gssize item)
+{
+ CacheItemDetails *details;
+
+ g_return_val_if_fail (NAUTILUS_IS_CACHE (cache), NAUTILUS_CACHE_INVALID);
+ g_return_val_if_fail (g_hash_table_contains (cache->items,
+ GINT_TO_POINTER (item)),
+ NAUTILUS_CACHE_INVALID);
+
+ details = g_hash_table_lookup (cache->items, GINT_TO_POINTER (item));
+
+ return details->state;
+}
+
+void
+nautilus_cache_item_invalidate (NautilusCache *cache,
+ gssize item,
+ gboolean destroy)
+{
+ CacheItemDetails *details;
+
+ g_return_if_fail (NAUTILUS_IS_CACHE (cache));
+ g_return_if_fail (g_hash_table_contains (cache->items,
+ GINT_TO_POINTER (item)));
+
+ details = g_hash_table_lookup (cache->items, GINT_TO_POINTER (item));
+
+ g_mutex_lock (&details->mutex);
+
+ /* There might be cases where the cache holding a ref on an object is a
+ * problem.
+ */
+ if (destroy &&
+ details->destroy_func != NULL && G_LIKELY (details->value != NULL))
+ {
+ details->destroy_func (details->value);
+ }
+
+ details->state = NAUTILUS_CACHE_INVALID;
+
+ g_mutex_unlock (&details->mutex);
+}
+
+void
+nautilus_cache_item_set_pending (NautilusCache *cache,
+ gssize item)
+{
+ CacheItemDetails *details;
+
+ g_return_if_fail (NAUTILUS_IS_CACHE (cache));
+ g_return_if_fail (g_hash_table_contains (cache->items,
+ GINT_TO_POINTER (item)));
+
+ details = g_hash_table_lookup (cache->items, GINT_TO_POINTER (item));
+
+ g_mutex_lock (&details->mutex);
+
+ /* This whole method feels quite clunky.
+ * Changing the state from valid to pending should probably be treated
+ * as programmer error (or a bug).
+ */
+ g_warn_if_fail (details->state == NAUTILUS_CACHE_INVALID);
+ if (details->state != NAUTILUS_CACHE_INVALID)
+ {
+ g_mutex_unlock (&details->mutex);
+ return;
+ }
+
+ details->state = NAUTILUS_CACHE_PENDING;
+
+ g_mutex_unlock (&details->mutex);
+}
+
+gpointer
+nautilus_cache_item_get_value (NautilusCache *cache,
+ gssize item,
+ NautilusCopyFunc copy_func)
+{
+ CacheItemDetails *details;
+
+ g_return_val_if_fail (NAUTILUS_IS_CACHE (cache), NULL);
+ g_return_val_if_fail (g_hash_table_contains (cache->items,
+ GINT_TO_POINTER (item)),
+ NULL);
+
+ details = g_hash_table_lookup (cache->items, GINT_TO_POINTER (item));
+
+ if (copy_func == NULL)
+ {
+ return details->value;
+ }
+ else
+ {
+ gpointer ret;
+
+ g_mutex_lock (&details->mutex);
+
+ ret = copy_func (details->value);
+
+ g_mutex_unlock (&details->mutex);
+
+ return ret;
+ }
+}
+
+void
+nautilus_cache_item_set_value (NautilusCache *cache,
+ gssize item,
+ gpointer value)
+{
+ CacheItemDetails *details;
+
+ g_return_if_fail (NAUTILUS_IS_CACHE (cache));
+ g_return_if_fail (g_hash_table_contains (cache->items,
+ GINT_TO_POINTER (item)));
+
+ details = g_hash_table_lookup (cache->items, GINT_TO_POINTER (item));
+
+ g_mutex_lock (&details->mutex);
+
+ /* We’ll treat this as a cancellation of the update. */
+ if (details->state != NAUTILUS_CACHE_PENDING)
+ {
+ g_mutex_unlock (&details->mutex);
+
+ return;
+ }
+
+ if (details->destroy_func != NULL && G_LIKELY (details->value != NULL))
+ {
+ g_clear_pointer (&details->value, details->destroy_func);
+ }
+
+ details->value = value;
+ details->state = NAUTILUS_CACHE_VALID;
+
+ g_mutex_unlock (&details->mutex);
+}
+
+gssize
+nautilus_cache_install_item (NautilusCache *cache,
+ GDestroyNotify destroy_func)
+{
+ CacheItemDetails *details;
+ guint size;
+
+ g_return_val_if_fail (NAUTILUS_IS_CACHE (cache), -1);
+
+ details = cache_item_details_new (destroy_func);
+ size = g_hash_table_size (cache->items);
+
+ g_hash_table_insert (cache->items, GUINT_TO_POINTER (size), details);
+
+ /* This is a bit evil, but is unlikely to cause problems… ever. */
+ return (gssize) size;
+}
+
+NautilusCache *
+nautilus_cache_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_CACHE, NULL);
+}
diff --git a/src-ng/nautilus-cache.h b/src-ng/nautilus-cache.h
new file mode 100644
index 000000000..eade4ee89
--- /dev/null
+++ b/src-ng/nautilus-cache.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nautilus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define NAUTILUS_TYPE_CACHE (nautilus_cache_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusCache, nautilus_cache, NAUTILUS, CACHE, GObject)
+
+/* GCopyFunc has too many parameters for our taste. */
+typedef gpointer (*NautilusCopyFunc) (gpointer data);
+#define NAUTILUS_COPY_FUNC(x) ((NautilusCopyFunc) x)
+
+typedef enum
+{
+ NAUTILUS_CACHE_INVALID,
+ NAUTILUS_CACHE_PENDING,
+ NAUTILUS_CACHE_VALID
+} NautilusCacheState;
+
+void nautilus_cache_invalidate_all (NautilusCache *cache);
+
+NautilusCacheState nautilus_cache_item_get_state (NautilusCache *cache,
+ gssize item);
+
+void nautilus_cache_item_invalidate (NautilusCache *cache,
+ gssize item,
+ gboolean destroy);
+void nautilus_cache_item_set_pending (NautilusCache *cache,
+ gssize item);
+
+gpointer nautilus_cache_item_get_value (NautilusCache *cache,
+ gssize item,
+ NautilusCopyFunc copy_func);
+void nautilus_cache_item_set_value (NautilusCache *cache,
+ gssize item,
+ gpointer value);
+
+/* TODO: TTL for highly volatile items? */
+gssize nautilus_cache_install_item (NautilusCache *cache,
+ GDestroyNotify destroy_func);
+
+NautilusCache *nautilus_cache_new (void);
diff --git a/src-ng/nautilus-directory.c b/src-ng/nautilus-directory.c
index e509265a2..9ded88431 100644
--- a/src-ng/nautilus-directory.c
+++ b/src-ng/nautilus-directory.c
@@ -18,7 +18,24 @@
#include "nautilus-directory.h"
-G_DEFINE_TYPE (NautilusDirectory, nautilus_directory, NAUTILUS_TYPE_FILE)
+#include "nautilus-cache.h"
+#include "nautilus-task-manager.h"
+#include "tasks/nautilus-enumerate-children-task.h"
+
+enum
+{
+ CHILDREN,
+ N_ITEMS
+};
+
+typedef struct
+{
+ NautilusCache *cache;
+ gssize cache_items[N_ITEMS];
+} NautilusDirectoryPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (NautilusDirectory, nautilus_directory,
+ NAUTILUS_TYPE_FILE)
static void
nautilus_directory_class_init (NautilusDirectoryClass *klass)
@@ -26,8 +43,149 @@ nautilus_directory_class_init (NautilusDirectoryClass *klass)
}
static void
+file_list_free (gpointer data)
+{
+ g_autoptr (GList) list = NULL;
+
+ list = data;
+
+ for (GList *i = list; i != NULL; i = i->next)
+ {
+ g_object_unref (i->data);
+ }
+}
+
+static void
nautilus_directory_init (NautilusDirectory *self)
{
+ NautilusDirectoryPrivate *priv;
+
+ priv = nautilus_directory_get_instance_private (self);
+
+ priv->cache = nautilus_cache_new ();
+ priv->cache_items[CHILDREN] =
+ nautilus_cache_install_item (priv->cache,
+ (GDestroyNotify) file_list_free);
+}
+
+typedef struct
+{
+ NautilusDirectory *directory;
+
+ NautilusEnumerateChildrenCallback callback;
+ gpointer callback_data;
+} EnumerateChildrenDetails;
+
+static void
+create_file_list (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GList **list;
+
+ list = user_data;
+
+ *list = g_list_prepend (*list,
+ nautilus_file_new_with_info (G_FILE (key),
+ G_FILE_INFO (value)));
+}
+
+static void
+on_enumerate_children_finished (NautilusEnumerateChildrenTask *task,
+ GFile *file,
+ GHashTable *files,
+ GError *error,
+ gpointer user_data)
+{
+ EnumerateChildrenDetails *details;
+ NautilusDirectoryPrivate *priv;
+ NautilusCacheState cache_state;
+ GList *children = NULL;
+
+ details = user_data;
+ priv = nautilus_directory_get_instance_private (details->directory);
+ cache_state = nautilus_cache_item_get_state (priv->cache,
+ priv->cache_items[CHILDREN]);
+
+ if (cache_state == NAUTILUS_CACHE_INVALID)
+ {
+ /* TODO: restart */
+ return;
+ }
+
+ g_hash_table_foreach (files, create_file_list, &children);
+
+ nautilus_cache_item_set_value (priv->cache, priv->cache_items[CHILDREN],
+ children);
+
+ details->callback (details->directory, g_list_copy (children), error,
+ details->callback_data);
+
+ g_free (details);
+}
+
+void
+nautilus_directory_enumerate_children (NautilusDirectory *directory,
+ GCancellable *cancellable,
+ NautilusEnumerateChildrenCallback callback,
+ gpointer user_data)
+{
+ NautilusDirectoryPrivate *priv;
+ NautilusCacheState cache_state;
+ g_autoptr (GFile) location = NULL;
+ g_autoptr (NautilusTask) task = NULL;
+ EnumerateChildrenDetails *details;
+ g_autoptr (NautilusTaskManager) task_manager = NULL;
+
+ g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
+
+ priv = nautilus_directory_get_instance_private (directory);
+ cache_state = nautilus_cache_item_get_state (priv->cache,
+ priv->cache_items[CHILDREN]);
+
+ if (cache_state == NAUTILUS_CACHE_PENDING ||
+ cache_state == NAUTILUS_CACHE_VALID)
+ {
+ callback (directory,
+ nautilus_cache_item_get_value (priv->cache,
+ priv->cache_items[CHILDREN],
+ (NautilusCopyFunc) g_list_copy),
+ NULL, user_data);
+
+ return;
+ }
+
+ nautilus_cache_item_set_pending (priv->cache,
+ priv->cache_items[CHILDREN]);
+
+ location = nautilus_file_get_location (NAUTILUS_FILE (directory));
+ task = nautilus_enumerate_children_task_new (location,
+ "standard::*,"
+ "access::*,"
+ "mountable::*,"
+ "time::*,"
+ "unix::*,"
+ "owner::*,"
+ "selinux::*,"
+ "thumbnail::*,"
+ "id::filesystem,"
+ "trash::orig-path,"
+ "trash::deletion-date,"
+ "metadata::*,"
+ "recent::*",
+ G_FILE_QUERY_INFO_NONE,
+ cancellable);
+ details = g_new0 (EnumerateChildrenDetails, 1);
+ task_manager = nautilus_task_manager_dup_singleton ();
+
+ details->directory = directory;
+ details->callback = callback;
+ details->callback_data = user_data;
+
+ g_signal_connect (task, "finished",
+ G_CALLBACK (on_enumerate_children_finished), details);
+
+ nautilus_task_manager_queue_task (task_manager, task);
}
NautilusFile *
diff --git a/src-ng/nautilus-directory.h b/src-ng/nautilus-directory.h
index be1c33a69..9743467bb 100644
--- a/src-ng/nautilus-directory.h
+++ b/src-ng/nautilus-directory.h
@@ -24,9 +24,19 @@ G_DECLARE_DERIVABLE_TYPE (NautilusDirectory, nautilus_directory,
NAUTILUS, DIRECTORY,
NautilusFile)
+typedef void (*NautilusEnumerateChildrenCallback) (NautilusDirectory *directory,
+ GList *children,
+ GError *error,
+ gpointer user_data);
+
struct _NautilusDirectoryClass
{
NautilusFileClass parent_class;
};
+void nautilus_directory_enumerate_children (NautilusDirectory *directory,
+ GCancellable *cancellable,
+ NautilusEnumerateChildrenCallback callback,
+ gpointer user_data);
+
NautilusFile *nautilus_directory_new (GFile *location);
diff --git a/src-ng/nautilus-file.c b/src-ng/nautilus-file.c
index 65692a83a..b19a1e287 100644
--- a/src-ng/nautilus-file.c
+++ b/src-ng/nautilus-file.c
@@ -18,25 +18,23 @@
#include "nautilus-file.h"
+#include "nautilus-cache.h"
#include "nautilus-directory.h"
#include "nautilus-task-manager.h"
#include "tasks/nautilus-attribute-task.h"
-typedef enum
+enum
{
- INVALID,
- PENDING,
- VALID
-} CacheState;
+ INFO,
+ N_ITEMS
+};
typedef struct
{
GFile *location;
- GFileInfo *info;
- CacheState info_state;
-
- GMutex cache_mutex;
+ NautilusCache *cache;
+ gssize cache_items[N_ITEMS];
} NautilusFilePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (NautilusFile, nautilus_file, G_TYPE_OBJECT)
@@ -135,8 +133,6 @@ finalize (GObject *object)
g_hash_table_remove (files, priv->location);
g_mutex_unlock (&files_mutex);
- g_mutex_clear (&priv->cache_mutex);
-
G_OBJECT_CLASS (nautilus_file_parent_class)->finalize (object);
}
@@ -166,9 +162,9 @@ nautilus_file_init (NautilusFile *self)
priv = nautilus_file_get_instance_private (self);
- priv->info = g_file_info_new ();
-
- g_mutex_init (&priv->cache_mutex);
+ priv->cache = nautilus_cache_new ();
+ priv->cache_items[INFO] = nautilus_cache_install_item (priv->cache,
+ g_object_unref);
}
typedef struct
@@ -188,14 +184,21 @@ on_query_info_finished (NautilusAttributeTask *task,
{
QueryInfoDetails *details;
NautilusFilePrivate *priv;
+ NautilusCacheState cache_state;
details = data;
priv = nautilus_file_get_instance_private (details->file);
+ cache_state = nautilus_cache_item_get_state (priv->cache,
+ priv->cache_items[INFO]);
- g_mutex_lock (&priv->cache_mutex);
- g_file_info_copy_into (info, priv->info);
- priv->info_state = VALID;
- g_mutex_unlock (&priv->cache_mutex);
+ if (cache_state == NAUTILUS_CACHE_INVALID)
+ {
+ /* TODO: restart */
+ return;
+ }
+
+ nautilus_cache_item_set_value (priv->cache, priv->cache_items[INFO],
+ info);
details->callback (details->file, g_file_info_dup (info), error,
details->callback_data);
@@ -210,24 +213,41 @@ nautilus_file_query_info (NautilusFile *file,
gpointer user_data)
{
NautilusFilePrivate *priv;
+ NautilusCacheState cache_state;
g_autoptr (NautilusTask) task = NULL;
QueryInfoDetails *details;
g_autoptr (NautilusTaskManager) manager = NULL;
+ g_return_if_fail (NAUTILUS_IS_FILE (file));
+
+ g_debug ("%s: called for %p", __func__, (gpointer) file);
+
priv = nautilus_file_get_instance_private (file);
+ cache_state = nautilus_cache_item_get_state (priv->cache,
+ priv->cache_items[INFO]);
- g_mutex_lock (&priv->cache_mutex);
/* This is not the right thing to do if a cache update is pending.
* A task reference could be stored and we could connect to the signal,
* but there might be a better way.
*/
- if (priv->info_state == PENDING || priv->info_state == VALID)
+ if (cache_state == NAUTILUS_CACHE_PENDING ||
+ cache_state == NAUTILUS_CACHE_VALID)
{
- g_mutex_unlock (&priv->cache_mutex);
+ GFileInfo *info;
+
+ g_debug ("%s: info for %p is either pending or valid",
+ __func__, (gpointer) file);
+
+ info = nautilus_cache_item_get_value (priv->cache,
+ priv->cache_items[INFO],
+ NAUTILUS_COPY_FUNC (g_file_info_dup));
+
+ callback (file, info, NULL, user_data);
- callback (file, g_file_info_dup (priv->info), NULL, user_data);
+ return;
}
- g_mutex_unlock (&priv->cache_mutex);
+
+ nautilus_cache_item_set_pending (priv->cache, priv->cache_items[INFO]);
task = nautilus_attribute_task_new (priv->location,
"standard::*,"
@@ -258,6 +278,39 @@ nautilus_file_query_info (NautilusFile *file,
nautilus_task_manager_queue_task (manager, task);
}
+GFile *
+nautilus_file_get_location (NautilusFile *file)
+{
+ NautilusFilePrivate *priv;
+
+ g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
+
+ priv = nautilus_file_get_instance_private (file);
+
+ return g_object_ref (priv->location);
+}
+
+NautilusFile *
+nautilus_file_new_with_info (GFile *location,
+ GFileInfo *info)
+{
+ NautilusFile *instance;
+ NautilusFilePrivate *priv;
+
+ g_return_val_if_fail (G_IS_FILE (location), NULL);
+ g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
+
+ instance = nautilus_file_new (location);
+ priv = nautilus_file_get_instance_private (instance);
+
+ /* Ergh. */
+ nautilus_cache_item_set_pending (priv->cache, priv->cache_items[INFO]);
+ nautilus_cache_item_set_value (priv->cache, priv->cache_items[INFO],
+ info);
+
+ return instance;
+}
+
NautilusFile *
nautilus_file_new (GFile *location)
{
diff --git a/src-ng/nautilus-file.h b/src-ng/nautilus-file.h
index 7781f6e68..b0caaaf47 100644
--- a/src-ng/nautilus-file.h
+++ b/src-ng/nautilus-file.h
@@ -42,6 +42,13 @@ void nautilus_file_query_info (NautilusFile *file,
NautilusFileInfoCallback callback,
gpointer user_data);
-NautilusFile *nautilus_file_new (GFile *location);
+GFile *nautilus_file_get_location (NautilusFile *file);
+
+/* Overwrites the info if the file exists in cache.
+ * Used by NautilusDirectory when enumerating children.
+ */
+NautilusFile *nautilus_file_new_with_info (GFile *location,
+ GFileInfo *info);
+NautilusFile *nautilus_file_new (GFile *location);
#endif
diff --git a/src-ng/nautilus-marshallers.list b/src-ng/nautilus-marshallers.list
index 29f507b15..c53470021 100644
--- a/src-ng/nautilus-marshallers.list
+++ b/src-ng/nautilus-marshallers.list
@@ -1 +1,2 @@
VOID:OBJECT,OBJECT,BOXED
+VOID:OBJECT,BOXED,BOXED
diff --git a/src-ng/nautilus-task-manager.c b/src-ng/nautilus-task-manager.c
index 037c7a481..17db97a34 100644
--- a/src-ng/nautilus-task-manager.c
+++ b/src-ng/nautilus-task-manager.c
@@ -65,6 +65,8 @@ finalize (GObject *object)
self = NAUTILUS_TASK_MANAGER (object);
g_thread_pool_free (self->thread_pool, TRUE, TRUE);
+
+ G_OBJECT_CLASS (nautilus_task_manager_parent_class)->finalize (object);
}
static void
diff --git a/src-ng/tasks/nautilus-attribute-task.c b/src-ng/tasks/nautilus-attribute-task.c
index ebc0ddd1a..11af3277a 100644
--- a/src-ng/tasks/nautilus-attribute-task.c
+++ b/src-ng/tasks/nautilus-attribute-task.c
@@ -22,11 +22,10 @@
struct _NautilusAttributeTask
{
- GObject parent_instance;
+ NautilusTask parent_instance;
GFile *file;
const char *attributes;
-
GFileQueryInfoFlags flags;
} NautilusAttributeTaskPrivate;
@@ -35,66 +34,13 @@ G_DEFINE_TYPE (NautilusAttributeTask, nautilus_attribute_task,
enum
{
- PROP_FILE = 1,
- PROP_ATTRIBUTES,
- PROP_FLAGS,
- N_PROPERTIES
-};
-
-enum
-{
FINISHED,
LAST_SIGNAL
};
-static GParamSpec *properties[N_PROPERTIES] = { NULL };
static guint signals[LAST_SIGNAL] = { 0 };
static void
-set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- NautilusAttributeTask *self;
-
- self = NAUTILUS_ATTRIBUTE_TASK (object);
-
- switch (property_id)
- {
- case PROP_FILE:
- {
- if (G_UNLIKELY (self->file != NULL))
- {
- g_clear_object (&self->file);
- }
-
- self->file = g_value_dup_object (value);
- }
- break;
-
- case PROP_ATTRIBUTES:
- {
- g_free ((gpointer) self->attributes);
-
- self->attributes = g_value_dup_string (value);
- }
- break;
-
- case PROP_FLAGS:
- {
- self->flags = g_value_get_int (value);
- }
- break;
-
- default:
- {
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
- }
-}
-
-static void
finalize (GObject *object)
{
NautilusAttributeTask *self;
@@ -138,29 +84,10 @@ nautilus_attribute_task_class_init (NautilusAttributeTaskClass *klass)
object_class = G_OBJECT_CLASS (klass);
task_class = NAUTILUS_TASK_CLASS (klass);
- object_class->set_property = set_property;
object_class->finalize = finalize;
task_class->execute = execute;
- properties[PROP_FILE] =
- g_param_spec_object ("file", "File", "File",
- G_TYPE_FILE,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME);
-
- properties[PROP_ATTRIBUTES] =
- g_param_spec_string ("attributes", "Attributes", "Attributes",
- NULL,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME);
-
- properties[PROP_FLAGS] =
- g_param_spec_int ("flags", "Flags", "Flags",
- G_FILE_QUERY_INFO_NONE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- G_FILE_QUERY_INFO_NONE,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
signals[FINISHED] = g_signal_new ("finished",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
@@ -175,9 +102,6 @@ nautilus_attribute_task_class_init (NautilusAttributeTaskClass *klass)
static void
nautilus_attribute_task_init (NautilusAttributeTask *self)
{
- self->file = NULL;
- self->attributes = NULL;
- self->flags = 0;
}
NautilusTask *
@@ -186,10 +110,18 @@ nautilus_attribute_task_new (GFile *file,
GFileQueryInfoFlags flags,
GCancellable *cancellable)
{
- return g_object_new (NAUTILUS_TYPE_ATTRIBUTE_TASK,
- "file", file,
- "attributes", attributes,
- "flags", flags,
- "cancellable", cancellable,
- NULL);
+ NautilusAttributeTask *instance;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (attributes != NULL, NULL);
+
+ instance = g_object_new (NAUTILUS_TYPE_ATTRIBUTE_TASK,
+ "cancellable", cancellable,
+ NULL);
+
+ instance->file = g_object_ref (file);
+ instance->attributes = g_strdup (attributes);
+ instance->flags = flags;
+
+ return NAUTILUS_TASK (instance);
}
diff --git a/src-ng/tasks/nautilus-enumerate-children-task.c b/src-ng/tasks/nautilus-enumerate-children-task.c
new file mode 100644
index 000000000..ddb0c425e
--- /dev/null
+++ b/src-ng/tasks/nautilus-enumerate-children-task.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nautilus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-enumerate-children-task.h"
+
+#include "nautilus-marshallers.h"
+
+struct _NautilusEnumerateChildrenTask
+{
+ NautilusTask parent_instance;
+
+ GFile *file;
+ const char *attributes;
+ GFileQueryInfoFlags flags;
+};
+
+G_DEFINE_TYPE (NautilusEnumerateChildrenTask, nautilus_enumerate_children_task,
+ NAUTILUS_TYPE_TASK)
+
+enum
+{
+ FINISHED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+execute (NautilusTask *task)
+{
+ NautilusEnumerateChildrenTask *self;
+ g_autoptr (GCancellable) cancellable = NULL;
+ NautilusTaskClass *klass;
+ GError *error = NULL;
+ g_autoptr (GFileEnumerator) enumerator = NULL;
+ GHashTable *hash_table;
+ GFileInfo *info;
+
+ self = NAUTILUS_ENUMERATE_CHILDREN_TASK (task);
+ cancellable = nautilus_task_get_cancellable (NAUTILUS_TASK (self));
+ klass = NAUTILUS_TASK_CLASS (G_OBJECT_GET_CLASS (self));
+ enumerator = g_file_enumerate_children (self->file, self->attributes,
+ self->flags, cancellable, &error);
+
+ if (error != NULL)
+ {
+ klass->emit_signal_in_main_context (task, signals[FINISHED],
+ self->file, NULL, error);
+ }
+
+ hash_table = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
+ g_object_unref, g_object_unref);
+
+ do
+ {
+ GFile *child;
+
+ info = g_file_enumerator_next_file (enumerator, cancellable, &error);
+
+ if (error != NULL)
+ {
+ g_hash_table_destroy (hash_table);
+
+ klass->emit_signal_in_main_context (task, signals[FINISHED],
+ self->file, NULL, error);
+
+ return;
+ }
+
+ if (info != NULL)
+ {
+ child = g_file_enumerator_get_child (enumerator, info);
+
+ g_assert (g_hash_table_insert (hash_table, child, info));
+ }
+ } while (info != NULL);
+
+ klass->emit_signal_in_main_context (task, signals[FINISHED],
+ self->file, hash_table, error);
+}
+
+static void
+nautilus_enumerate_children_task_class_init (NautilusEnumerateChildrenTaskClass *klass)
+{
+ NautilusTaskClass *task_class;
+
+ task_class = NAUTILUS_TASK_CLASS (klass);
+
+ task_class->execute = execute;
+
+ signals[FINISHED] = g_signal_new ("finished",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ nautilus_cclosure_marshal_VOID__OBJECT_BOXED_BOXED,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_FILE, G_TYPE_HASH_TABLE, G_TYPE_ERROR);
+}
+
+static void
+nautilus_enumerate_children_task_init (NautilusEnumerateChildrenTask *self)
+{
+}
+
+NautilusTask *
+nautilus_enumerate_children_task_new (GFile *file,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable)
+{
+ NautilusEnumerateChildrenTask *instance;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (attributes != NULL, NULL);
+
+ instance = g_object_new (NAUTILUS_TYPE_ENUMERATE_CHILDREN_TASK,
+ "cancellable", cancellable,
+ NULL);
+
+ instance->file = g_object_ref (file);
+ instance->attributes = g_strdup (attributes);
+ instance->flags = flags;
+
+ return NAUTILUS_TASK (instance);
+}
diff --git a/src-ng/tasks/nautilus-enumerate-children-task.h b/src-ng/tasks/nautilus-enumerate-children-task.h
new file mode 100644
index 000000000..2aa76ee0d
--- /dev/null
+++ b/src-ng/tasks/nautilus-enumerate-children-task.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nautilus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NAUTILUS_ENUMERATE_CHILDREN_TASK_H_INCLUDED
+#define NAUTILUS_ENUMERATE_CHILDREN_TASK_H_INCLUDED
+
+#include "nautilus-task.h"
+
+#include <gio/gio.h>
+
+#define NAUTILUS_TYPE_ENUMERATE_CHILDREN_TASK (nautilus_enumerate_children_task_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusEnumerateChildrenTask,
+ nautilus_enumerate_children_task,
+ NAUTILUS, ENUMERATE_CHILDREN_TASK,
+ NautilusTask)
+
+NautilusTask *nautilus_enumerate_children_task_new (GFile *file,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable);
+
+#endif