[nautilus/wip/ernestask/tasks: 23/23] Can’t be arsed to split this :|



commit 634b34ed39a6525ef12887acc65cf2f8b291ea47
Author: Ernestas Kulik <ernestask gnome org>
Date:   Fri Jul 14 17:24:31 2017 +0300

    Can’t be arsed to split this :|

 src-ng/main.c                                   |   64 +++++-
 src-ng/meson.build                              |    4 +
 src-ng/nautilus-cache.c                         |  259 +++++++++++++++++++++++
 src-ng/nautilus-cache.h                         |   59 +++++
 src-ng/nautilus-directory.c                     |  160 ++++++++++++++-
 src-ng/nautilus-directory.h                     |   10 +
 src-ng/nautilus-file.c                          |   99 +++++++--
 src-ng/nautilus-file.h                          |    9 +-
 src-ng/nautilus-marshallers.list                |    1 +
 src-ng/nautilus-task-manager.c                  |    2 +
 src-ng/tasks/nautilus-attribute-task.c          |   98 ++-------
 src-ng/tasks/nautilus-enumerate-children-task.c |  141 ++++++++++++
 src-ng/tasks/nautilus-enumerate-children-task.h |   38 ++++
 13 files changed, 830 insertions(+), 114 deletions(-)
---
diff --git a/src-ng/main.c b/src-ng/main.c
index f5474bb..49a3281 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 8f1fec6..aa62884 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 0000000..f27a6d9
--- /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 0000000..eade4ee
--- /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 e509265..9ded884 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 be1c33a..9743467 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 65692a8..b19a1e2 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 7781f6e..b0caaaf 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 29f507b..c534700 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 037c7a4..17db97a 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 ebc0ddd..11af327 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 0000000..ddb0c42
--- /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 0000000..2aa76ee
--- /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



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