]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilesystem.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkfilesystem.c
index d76808372bd04df8040411d60a7d41ca4c146115..2fdfa3df9dd448a1d14a08bb376e80c055e8a856 100644 (file)
@@ -3,32 +3,33 @@
  * Copyright (C) 2003, Red Hat, Inc.
  * Copyright (C) 2007-2008 Carlos Garnacho
  *
- * This program is free software; you can redistribute it and/or modify
+ * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
+ * This library 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.
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  *
  * Authors: Carlos Garnacho <carlos@imendio.com>
  */
 
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
+#include "config.h"
+
 #include <string.h>
 
+#include <glib/gi18n-lib.h>
+
+#include "gtkfilechooser.h"
 #include "gtkfilesystem.h"
+#include "gtkicontheme.h"
 #include "gtkprivate.h"
 
-#include "gtkalias.h"
-
 /* #define DEBUG_MODE */
 #ifdef DEBUG_MODE
 #define DEBUG(x) g_debug (x);
@@ -36,8 +37,6 @@
 #define DEBUG(x)
 #endif
 
-#define GTK_FILE_SYSTEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_FILE_SYSTEM, GtkFileSystemPrivate))
-#define GTK_FOLDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_FOLDER, GtkFolderPrivate))
 #define FILES_PER_QUERY 100
 
 /* The pointers we return for a GtkFileSystemVolume are opaque tokens; they are
@@ -71,10 +70,7 @@ enum {
 };
 
 static guint fs_signals [FS_LAST_SIGNAL] = { 0, };
-static guint folder_signals [FOLDER_LAST_SIGNAL] = { 0, };
 
-typedef struct GtkFileSystemPrivate GtkFileSystemPrivate;
-typedef struct GtkFolderPrivate GtkFolderPrivate;
 typedef struct AsyncFuncData AsyncFuncData;
 
 struct GtkFileSystemPrivate
@@ -92,23 +88,10 @@ struct GtkFileSystemPrivate
   GFileMonitor *bookmarks_monitor;
 };
 
-struct GtkFolderPrivate
-{
-  GFile *folder_file;
-  GHashTable *children;
-  GFileMonitor *directory_monitor;
-  GFileEnumerator *enumerator;
-  GCancellable *cancellable;
-  gchar *attributes;
-
-  guint finished_loading : 1;
-};
-
 struct AsyncFuncData
 {
   GtkFileSystem *file_system;
   GFile *file;
-  GtkFolder *folder;
   GCancellable *cancellable;
   gchar *attributes;
 
@@ -124,15 +107,6 @@ struct GtkFileSystemBookmark
 
 G_DEFINE_TYPE (GtkFileSystem, _gtk_file_system, G_TYPE_OBJECT)
 
-G_DEFINE_TYPE (GtkFolder, _gtk_folder, G_TYPE_OBJECT)
-
-
-static void gtk_folder_set_finished_loading (GtkFolder *folder,
-                                            gboolean   finished_loading);
-static void gtk_folder_add_file             (GtkFolder *folder,
-                                            GFile     *file,
-                                            GFileInfo *info);
-
 
 /* GtkFileSystemBookmark methods */
 void
@@ -161,12 +135,11 @@ volumes_changed (GVolumeMonitor *volume_monitor,
 static void
 gtk_file_system_dispose (GObject *object)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystem *file_system = GTK_FILE_SYSTEM (object);
+  GtkFileSystemPrivate *priv = file_system->priv;
 
   DEBUG ("dispose");
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (object);
-
   if (priv->volumes)
     {
       g_slist_foreach (priv->volumes, (GFunc) g_object_unref, NULL);
@@ -187,12 +160,11 @@ gtk_file_system_dispose (GObject *object)
 static void
 gtk_file_system_finalize (GObject *object)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystem *file_system = GTK_FILE_SYSTEM (object);
+  GtkFileSystemPrivate *priv = file_system->priv;
 
   DEBUG ("finalize");
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (object);
-
   if (priv->bookmarks_monitor)
     g_object_unref (priv->bookmarks_monitor);
 
@@ -235,7 +207,7 @@ _gtk_file_system_class_init (GtkFileSystemClass *class)
 }
 
 static GFile *
-get_bookmarks_file (void)
+get_legacy_bookmarks_file (void)
 {
   GFile *file;
   gchar *filename;
@@ -247,6 +219,19 @@ get_bookmarks_file (void)
   return file;
 }
 
+static GFile *
+get_bookmarks_file (void)
+{
+  GFile *file;
+  gchar *filename;
+
+  filename = g_build_filename (g_get_user_config_dir (), "gtk-3.0", "bookmarks", NULL);
+  file = g_file_new_for_path (filename);
+  g_free (filename);
+
+  return file;
+}
+
 static GSList *
 read_bookmarks (GFile *file)
 {
@@ -268,6 +253,9 @@ read_bookmarks (GFile *file)
       if (!*lines[i])
        continue;
 
+      if (!g_utf8_validate (lines[i], -1, NULL))
+       continue;
+
       bookmark = g_slice_new0 (GtkFileSystemBookmark);
 
       if ((space = strchr (lines[i], ' ')) != NULL)
@@ -293,36 +281,46 @@ save_bookmarks (GFile  *bookmarks_file,
 {
   GError *error = NULL;
   GString *contents;
+  GSList *l;
+  GFile *parent_file;
+  gchar *path;
 
   contents = g_string_new ("");
 
-  while (bookmarks)
+  for (l = bookmarks; l; l = l->next)
     {
-      GtkFileSystemBookmark *bookmark;
+      GtkFileSystemBookmark *bookmark = l->data;
       gchar *uri;
 
-      bookmark = bookmarks->data;
       uri = g_file_get_uri (bookmark->file);
+      if (!uri)
+       continue;
+
       g_string_append (contents, uri);
 
       if (bookmark->label)
        g_string_append_printf (contents, " %s", bookmark->label);
 
       g_string_append_c (contents, '\n');
-      bookmarks = bookmarks->next;
       g_free (uri);
     }
 
-  if (!g_file_replace_contents (bookmarks_file,
-                               contents->str,
-                               strlen (contents->str),
-                               NULL, FALSE, 0, NULL,
-                               NULL, &error))
+  parent_file = g_file_get_parent (bookmarks_file);
+  path = g_file_get_path (parent_file);
+  if (g_mkdir_with_parents (path, 0700) == 0)
     {
-      g_critical (error->message);
-      g_error_free (error);
+      if (!g_file_replace_contents (bookmarks_file,
+                                    contents->str,
+                                    strlen (contents->str),
+                                    NULL, FALSE, 0, NULL,
+                                    NULL, &error))
+        {
+          g_critical ("%s", error->message);
+          g_error_free (error);
+        }
     }
-
+  g_free (path);
+  g_object_unref (parent_file);
   g_string_free (contents, TRUE);
 }
 
@@ -333,9 +331,8 @@ bookmarks_file_changed (GFileMonitor      *monitor,
                        GFileMonitorEvent  event,
                        gpointer           data)
 {
-  GtkFileSystemPrivate *priv;
-
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (data);
+  GtkFileSystem *file_system = GTK_FILE_SYSTEM (data);
+  GtkFileSystemPrivate *priv = file_system->priv;
 
   switch (event)
     {
@@ -358,10 +355,43 @@ bookmarks_file_changed (GFileMonitor      *monitor,
     }
 }
 
+static gboolean
+mount_referenced_by_volume_activation_root (GList *volumes, GMount *mount)
+{
+  GList *l;
+  GFile *mount_root;
+  gboolean ret;
+
+  ret = FALSE;
+
+  mount_root = g_mount_get_root (mount);
+
+  for (l = volumes; l != NULL; l = l->next)
+    {
+      GVolume *volume = G_VOLUME (l->data);
+      GFile *volume_activation_root;
+
+      volume_activation_root = g_volume_get_activation_root (volume);
+      if (volume_activation_root != NULL)
+        {
+          if (g_file_has_prefix (volume_activation_root, mount_root))
+            {
+              ret = TRUE;
+              g_object_unref (volume_activation_root);
+              break;
+            }
+          g_object_unref (volume_activation_root);
+        }
+    }
+
+  g_object_unref (mount_root);
+  return ret;
+}
+
 static void
 get_volumes_list (GtkFileSystem *file_system)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystemPrivate *priv = file_system->priv;
   GList *l, *ll;
   GList *drives;
   GList *volumes;
@@ -370,8 +400,6 @@ get_volumes_list (GtkFileSystem *file_system)
   GVolume *volume;
   GMount *mount;
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
-
   if (priv->volumes)
     {
       g_slist_foreach (priv->volumes, (GFunc) g_object_unref, NULL);
@@ -415,6 +443,8 @@ get_volumes_list (GtkFileSystem *file_system)
 
              g_object_unref (volume);
             }
+  
+           g_list_free (volumes);
         }
       else if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive))
        {
@@ -429,6 +459,8 @@ get_volumes_list (GtkFileSystem *file_system)
 
          priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (drive));
        }
+
+      g_object_unref (drive);
     }
 
   g_list_free (drives);
@@ -460,9 +492,9 @@ get_volumes_list (GtkFileSystem *file_system)
           /* see comment above in why we add an icon for a volume */
           priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (volume));
         }
-    }
 
-  g_list_free (volumes);
+      g_object_unref (volume);
+    }
 
   /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
   mounts = g_volume_monitor_get_mounts (priv->volume_monitor);
@@ -478,10 +510,22 @@ get_volumes_list (GtkFileSystem *file_system)
           continue;
         }
 
+      /* if there's exists one or more volumes with an activation root inside the mount,
+       * don't display the mount
+       */
+      if (mount_referenced_by_volume_activation_root (volumes, mount))
+        {
+          g_object_unref (mount);
+          continue;
+        }
+
       /* show this mount */
       priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (mount));
+      g_object_unref (mount);
     }
 
+  g_list_free (volumes);
+
   g_list_free (mounts);
 }
 
@@ -494,7 +538,10 @@ _gtk_file_system_init (GtkFileSystem *file_system)
 
   DEBUG ("init");
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
+  file_system->priv = G_TYPE_INSTANCE_GET_PRIVATE (file_system,
+                                                   GTK_TYPE_FILE_SYSTEM,
+                                                   GtkFileSystemPrivate);
+  priv = file_system->priv;
 
   /* Volumes */
   priv->volume_monitor = g_volume_monitor_get ();
@@ -521,11 +568,26 @@ _gtk_file_system_init (GtkFileSystem *file_system)
   /* Bookmarks */
   bookmarks_file = get_bookmarks_file ();
   priv->bookmarks = read_bookmarks (bookmarks_file);
+  if (!priv->bookmarks)
+    {
+      GFile *legacy_bookmarks_file;
+
+      /* Read the legacy one and write it to the new one */
+      legacy_bookmarks_file = get_legacy_bookmarks_file ();
+      priv->bookmarks = read_bookmarks (legacy_bookmarks_file);
+      save_bookmarks (bookmarks_file, priv->bookmarks);
+
+      g_object_unref (legacy_bookmarks_file);
+    }
+
   priv->bookmarks_monitor = g_file_monitor_file (bookmarks_file,
                                                 G_FILE_MONITOR_NONE,
                                                 NULL, &error);
   if (error)
-    g_warning (error->message);
+    {
+      g_warning ("%s", error->message);
+      g_error_free (error);
+    }
   else
     g_signal_connect (priv->bookmarks_monitor, "changed",
                      G_CALLBACK (bookmarks_file_changed), file_system);
@@ -543,15 +605,12 @@ _gtk_file_system_new (void)
 GSList *
 _gtk_file_system_list_volumes (GtkFileSystem *file_system)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystemPrivate *priv = file_system->priv;
   GSList *list;
 
   DEBUG ("list_volumes");
 
-  g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
-
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
-  get_volumes_list (GTK_FILE_SYSTEM (file_system));
+  get_volumes_list (file_system);
 
   list = g_slist_copy (priv->volumes);
 
@@ -566,12 +625,11 @@ _gtk_file_system_list_volumes (GtkFileSystem *file_system)
 GSList *
 _gtk_file_system_list_bookmarks (GtkFileSystem *file_system)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystemPrivate *priv = file_system->priv;
   GSList *bookmarks, *files = NULL;
 
   DEBUG ("list_bookmarks");
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
   bookmarks = priv->bookmarks;
 
   while (bookmarks)
@@ -587,79 +645,6 @@ _gtk_file_system_list_bookmarks (GtkFileSystem *file_system)
   return g_slist_reverse (files);
 }
 
-gboolean
-_gtk_file_system_parse (GtkFileSystem     *file_system,
-                       GFile             *base_file,
-                       const gchar       *str,
-                       GFile            **folder,
-                       gchar            **file_part,
-                       GError           **error)
-{
-  GFile *file;
-  gboolean result = FALSE;
-  gboolean is_dir = FALSE;
-  gchar *last_slash = NULL;
-
-  DEBUG ("parse");
-
-  if (str && *str)
-    is_dir = (str [strlen (str) - 1] == G_DIR_SEPARATOR);
-
-  last_slash = strrchr (str, G_DIR_SEPARATOR);
-
-  if (str[0] == '~')
-    file = g_file_parse_name (str);
-  else
-    file = g_file_resolve_relative_path (base_file, str);
-
-  if (g_file_equal (base_file, file))
-    {
-      /* this is when user types '.', could be the
-       * beginning of a hidden file, ./ or ../
-       */
-      *folder = g_object_ref (file);
-      *file_part = g_strdup (str);
-      result = TRUE;
-    }
-  else if (is_dir)
-    {
-      /* it's a dir, or at least it ends with the dir separator */
-      *folder = g_object_ref (file);
-      *file_part = g_strdup ("");
-      result = TRUE;
-    }
-  else
-    {
-      GFile *parent_file;
-
-      parent_file = g_file_get_parent (file);
-
-      if (!parent_file)
-       {
-         g_set_error (error,
-                      GTK_FILE_CHOOSER_ERROR,
-                      GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
-                      "Could not get parent file");
-         *folder = NULL;
-         *file_part = NULL;
-       }
-      else
-       {
-         *folder = parent_file;
-         result = TRUE;
-
-         if (last_slash)
-           *file_part = g_strdup (last_slash + 1);
-         else
-           *file_part = g_strdup (str);
-       }
-    }
-
-  g_object_unref (file);
-
-  return result;
-}
-
 static void
 free_async_data (AsyncFuncData *async_data)
 {
@@ -667,83 +652,10 @@ free_async_data (AsyncFuncData *async_data)
   g_object_unref (async_data->file);
   g_object_unref (async_data->cancellable);
 
-  if (async_data->folder)
-    g_object_unref (async_data->folder);
-
   g_free (async_data->attributes);
   g_free (async_data);
 }
 
-static void
-enumerate_children_callback (GObject      *source_object,
-                            GAsyncResult *result,
-                            gpointer      user_data)
-{
-  GFileEnumerator *enumerator;
-  AsyncFuncData *async_data;
-  GtkFolder *folder = NULL;
-  GFile *file;
-  GError *error = NULL;
-
-  file = G_FILE (source_object);
-  async_data = (AsyncFuncData *) user_data;
-  enumerator = g_file_enumerate_children_finish (file, result, &error);
-
-  if (enumerator)
-    {
-      folder = g_object_new (GTK_TYPE_FOLDER,
-                            "file", source_object,
-                            "enumerator", enumerator,
-                            "attributes", async_data->attributes,
-                            NULL);
-      g_object_unref (enumerator);
-    }
-
-  gdk_threads_enter ();
-  ((GtkFileSystemGetFolderCallback) async_data->callback) (async_data->cancellable,
-                                                          folder, error, async_data->data);
-  gdk_threads_leave ();
-
-  free_async_data (async_data);
-
-  if (error)
-    g_error_free (error);
-}
-
-GCancellable *
-_gtk_file_system_get_folder (GtkFileSystem                  *file_system,
-                            GFile                          *file,
-                            const gchar                    *attributes,
-                            GtkFileSystemGetFolderCallback  callback,
-                            gpointer                        data)
-{
-  GCancellable *cancellable;
-  AsyncFuncData *async_data;
-
-  g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
-  g_return_val_if_fail (G_IS_FILE (file), NULL);
-
-  cancellable = g_cancellable_new ();
-
-  async_data = g_new0 (AsyncFuncData, 1);
-  async_data->file_system = g_object_ref (file_system);
-  async_data->file = g_object_ref (file);
-  async_data->cancellable = g_object_ref (cancellable);
-  async_data->attributes = g_strdup (attributes);
-
-  async_data->callback = callback;
-  async_data->data = data;
-
-  g_file_enumerate_children_async (file,
-                                  attributes,
-                                  G_FILE_QUERY_INFO_NONE,
-                                  G_PRIORITY_DEFAULT,
-                                  cancellable,
-                                  enumerate_children_callback,
-                                  async_data);
-  return cancellable;
-}
-
 static void
 query_info_callback (GObject      *source_object,
                     GAsyncResult *result,
@@ -909,6 +821,11 @@ enclosing_volume_mount_cb (GObject      *source_object,
   g_file_mount_enclosing_volume_finish (G_FILE (source_object), result, &error);
   volume = _gtk_file_system_get_volume_for_file (async_data->file_system, G_FILE (source_object));
 
+  /* Silently drop G_IO_ERROR_ALREADY_MOUNTED error for gvfs backends without visible mounts. */
+  /* Better than doing query_info with additional I/O every time. */
+  if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED))
+    g_clear_error (&error);
+
   gdk_threads_enter ();
   ((GtkFileSystemVolumeMountCallback) async_data->callback) (async_data->cancellable, volume,
                                                             error, async_data->data);
@@ -916,6 +833,8 @@ enclosing_volume_mount_cb (GObject      *source_object,
 
   if (error)
     g_error_free (error);
+
+  _gtk_file_system_volume_unref (volume);
 }
 
 GCancellable *
@@ -958,13 +877,12 @@ _gtk_file_system_insert_bookmark (GtkFileSystem  *file_system,
                                  gint            position,
                                  GError        **error)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystemPrivate *priv = file_system->priv;
   GSList *bookmarks;
   GtkFileSystemBookmark *bookmark;
   gboolean result = TRUE;
   GFile *bookmarks_file;
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
   bookmarks = priv->bookmarks;
 
   while (bookmarks)
@@ -1014,14 +932,12 @@ _gtk_file_system_remove_bookmark (GtkFileSystem  *file_system,
                                  GFile          *file,
                                  GError        **error)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystemPrivate *priv = file_system->priv;
   GtkFileSystemBookmark *bookmark;
   GSList *bookmarks;
   gboolean result = FALSE;
   GFile *bookmarks_file;
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
-
   if (!priv->bookmarks)
     return FALSE;
 
@@ -1071,13 +987,12 @@ gchar *
 _gtk_file_system_get_bookmark_label (GtkFileSystem *file_system,
                                     GFile         *file)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystemPrivate *priv = file_system->priv;
   GSList *bookmarks;
   gchar *label = NULL;
 
   DEBUG ("get_bookmark_label");
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
   bookmarks = priv->bookmarks;
 
   while (bookmarks)
@@ -1102,14 +1017,13 @@ _gtk_file_system_set_bookmark_label (GtkFileSystem *file_system,
                                     GFile         *file,
                                     const gchar   *label)
 {
-  GtkFileSystemPrivate *priv;
+  GtkFileSystemPrivate *priv = file_system->priv;
   gboolean changed = FALSE;
   GFile *bookmarks_file;
   GSList *bookmarks;
 
   DEBUG ("set_bookmark_label");
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
   bookmarks = priv->bookmarks;
 
   while (bookmarks)
@@ -1121,7 +1035,7 @@ _gtk_file_system_set_bookmark_label (GtkFileSystem *file_system,
 
       if (g_file_equal (file, bookmark->file))
        {
-         g_free (bookmark->file);
+          g_free (bookmark->label);
          bookmark->label = g_strdup (label);
          changed = TRUE;
          break;
@@ -1140,12 +1054,10 @@ GtkFileSystemVolume *
 _gtk_file_system_get_volume_for_file (GtkFileSystem *file_system,
                                      GFile         *file)
 {
-  GtkFileSystemPrivate *priv;
   GMount *mount;
 
   DEBUG ("get_volume_for_file");
 
-  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
   mount = g_file_find_enclosing_mount (file, NULL, NULL);
 
   if (!mount && g_file_is_native (file))
@@ -1154,406 +1066,6 @@ _gtk_file_system_get_volume_for_file (GtkFileSystem *file_system,
   return (GtkFileSystemVolume *) mount;
 }
 
-/* GtkFolder methods */
-static void
-gtk_folder_set_property (GObject      *object,
-                        guint         prop_id,
-                        const GValue *value,
-                        GParamSpec   *pspec)
-{
-  GtkFolderPrivate *priv;
-
-  priv = GTK_FOLDER_GET_PRIVATE (object);
-
-  switch (prop_id)
-    {
-    case PROP_FILE:
-      priv->folder_file = g_value_dup_object (value);
-      break;
-    case PROP_ENUMERATOR:
-      priv->enumerator = g_value_dup_object (value);
-      break;
-    case PROP_ATTRIBUTES:
-      priv->attributes = g_value_dup_string (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_folder_get_property (GObject    *object,
-                        guint       prop_id,
-                        GValue     *value,
-                        GParamSpec *pspec)
-{
-  GtkFolderPrivate *priv;
-
-  priv = GTK_FOLDER_GET_PRIVATE (object);
-
-  switch (prop_id)
-    {
-    case PROP_FILE:
-      g_value_set_object (value, priv->folder_file);
-      break;
-    case PROP_ENUMERATOR:
-      g_value_set_object (value, priv->enumerator);
-      break;
-    case PROP_ATTRIBUTES:
-      g_value_set_string (value, priv->attributes);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-query_created_file_info_callback (GObject      *source_object,
-                                 GAsyncResult *result,
-                                 gpointer      user_data)
-{
-  GFile *file = G_FILE (source_object);
-  GError *error = NULL;
-  GFileInfo *info;
-  GtkFolder *folder;
-  GSList *files;
-
-  info = g_file_query_info_finish (file, result, &error);
-
-  if (error)
-    {
-      g_error_free (error);
-      return;
-    }
-
-  folder = GTK_FOLDER (user_data);
-  gtk_folder_add_file (folder, file, info);
-
-  files = g_slist_prepend (NULL, file);
-  g_signal_emit (folder, folder_signals[FILES_ADDED], 0, files);
-  g_slist_free (files);
-
-  g_object_unref (info);
-}
-
-static void
-directory_monitor_changed (GFileMonitor      *monitor,
-                          GFile             *file,
-                          GFile             *other_file,
-                          GFileMonitorEvent  event,
-                          gpointer           data)
-{
-  GtkFolderPrivate *priv;
-  GtkFolder *folder;
-  GSList *files;
-
-  folder = GTK_FOLDER (data);
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-  files = g_slist_prepend (NULL, file);
-
-  gdk_threads_enter ();
-
-  switch (event)
-    {
-    case G_FILE_MONITOR_EVENT_CREATED:
-      g_file_query_info_async (file,
-                              priv->attributes,
-                              G_FILE_QUERY_INFO_NONE,
-                              G_PRIORITY_DEFAULT,
-                              priv->cancellable,
-                              query_created_file_info_callback,
-                              folder);
-      break;
-    case G_FILE_MONITOR_EVENT_DELETED:
-      if (g_file_equal (file, priv->folder_file))
-       g_signal_emit (folder, folder_signals[DELETED], 0);
-      else
-       g_signal_emit (folder, folder_signals[FILES_REMOVED], 0, files);
-      break;
-    default:
-      break;
-    }
-
-  gdk_threads_leave ();
-
-  g_slist_free (files);
-}
-
-static void
-enumerator_files_callback (GObject      *source_object,
-                          GAsyncResult *result,
-                          gpointer      user_data)
-{
-  GFileEnumerator *enumerator;
-  GtkFolderPrivate *priv;
-  GtkFolder *folder;
-  GError *error = NULL;
-  GSList *files = NULL;
-  GList *file_infos, *f;
-
-  enumerator = G_FILE_ENUMERATOR (source_object);
-  file_infos = g_file_enumerator_next_files_finish (enumerator, result, &error);
-
-  if (error)
-    {
-      g_warning (error->message);
-      g_error_free (error);
-      return;
-    }
-
-  folder = GTK_FOLDER (user_data);
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-
-  if (!file_infos)
-    {
-      g_file_enumerator_close_async (enumerator,
-                                    G_PRIORITY_DEFAULT,
-                                    NULL, NULL, NULL);
-
-      gtk_folder_set_finished_loading (folder, TRUE);
-      return;
-    }
-
-  g_file_enumerator_next_files_async (enumerator, FILES_PER_QUERY,
-                                     G_PRIORITY_DEFAULT,
-                                     priv->cancellable,
-                                     enumerator_files_callback,
-                                     folder);
-
-  for (f = file_infos; f; f = f->next)
-    {
-      GFileInfo *info;
-      GFile *child_file;
-
-      info = f->data;
-      child_file = g_file_get_child (priv->folder_file, g_file_info_get_name (info));
-      gtk_folder_add_file (folder, child_file, info);
-      files = g_slist_prepend (files, child_file);
-    }
-
-  gdk_threads_enter ();
-  g_signal_emit (folder, folder_signals[FILES_ADDED], 0, files);
-  gdk_threads_leave ();
-
-  g_list_foreach (file_infos, (GFunc) g_object_unref, NULL);
-  g_list_free (file_infos);
-
-  g_slist_foreach (files, (GFunc) g_object_unref, NULL);
-  g_slist_free (files);
-}
-
-static void
-gtk_folder_constructed (GObject *object)
-{
-  GtkFolderPrivate *priv;
-  GError *error = NULL;
-
-  priv = GTK_FOLDER_GET_PRIVATE (object);
-  priv->directory_monitor = g_file_monitor_directory (priv->folder_file, G_FILE_MONITOR_NONE, NULL, &error);
-
-  if (error)
-    g_warning (error->message);
-  else
-    g_signal_connect (priv->directory_monitor, "changed",
-                     G_CALLBACK (directory_monitor_changed), object);
-
-  g_file_enumerator_next_files_async (priv->enumerator,
-                                     FILES_PER_QUERY,
-                                     G_PRIORITY_DEFAULT,
-                                     priv->cancellable,
-                                     enumerator_files_callback,
-                                     object);
-  /* This isn't needed anymore */
-  g_object_unref (priv->enumerator);
-  priv->enumerator = NULL;
-}
-
-static void
-gtk_folder_finalize (GObject *object)
-{
-  GtkFolderPrivate *priv;
-
-  priv = GTK_FOLDER_GET_PRIVATE (object);
-
-  g_hash_table_unref (priv->children);
-
-  if (priv->folder_file)
-    g_object_unref (priv->folder_file);
-
-  if (priv->directory_monitor)
-    g_object_unref (priv->directory_monitor);
-
-  g_cancellable_cancel (priv->cancellable);
-  g_object_unref (priv->cancellable);
-  g_free (priv->attributes);
-
-  G_OBJECT_CLASS (_gtk_folder_parent_class)->finalize (object);
-}
-
-static void
-_gtk_folder_class_init (GtkFolderClass *class)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
-
-  object_class->set_property = gtk_folder_set_property;
-  object_class->get_property = gtk_folder_get_property;
-  object_class->constructed = gtk_folder_constructed;
-  object_class->finalize = gtk_folder_finalize;
-
-  g_object_class_install_property (object_class,
-                                  PROP_FILE,
-                                  g_param_spec_object ("file",
-                                                       "File",
-                                                       "GFile for the folder",
-                                                       G_TYPE_FILE,
-                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-  g_object_class_install_property (object_class,
-                                  PROP_ENUMERATOR,
-                                  g_param_spec_object ("enumerator",
-                                                       "Enumerator",
-                                                       "GFileEnumerator to list files",
-                                                       G_TYPE_FILE_ENUMERATOR,
-                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-  g_object_class_install_property (object_class,
-                                  PROP_ATTRIBUTES,
-                                  g_param_spec_string ("attributes",
-                                                       "Attributes",
-                                                       "Attributes to query for",
-                                                       NULL,
-                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-  folder_signals[FILES_ADDED] =
-    g_signal_new ("files-added",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (GtkFolderClass, files_added),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__POINTER,
-                 G_TYPE_NONE, 1, G_TYPE_POINTER);
-  folder_signals[FILES_REMOVED] =
-    g_signal_new ("files-removed",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (GtkFolderClass, files_removed),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__POINTER,
-                 G_TYPE_NONE, 1, G_TYPE_POINTER);
-  folder_signals[FILES_CHANGED] =
-    g_signal_new ("files-changed",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (GtkFolderClass, files_changed),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__POINTER,
-                 G_TYPE_NONE, 1, G_TYPE_POINTER);
-  folder_signals[FINISHED_LOADING] =
-    g_signal_new ("finished-loading",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (GtkFolderClass, finished_loading),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-  folder_signals[DELETED] =
-    g_signal_new ("deleted",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (GtkFolderClass, deleted),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-
-  g_type_class_add_private (object_class, sizeof (GtkFolderPrivate));
-}
-
-static void
-_gtk_folder_init (GtkFolder *folder)
-{
-  GtkFolderPrivate *priv;
-
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-
-  priv->children = g_hash_table_new_full (g_file_hash,
-                                         (GEqualFunc) g_file_equal,
-                                         (GDestroyNotify) g_object_unref,
-                                         (GDestroyNotify) g_object_unref);
-  priv->cancellable = g_cancellable_new ();
-}
-
-static void
-gtk_folder_set_finished_loading (GtkFolder *folder,
-                                gboolean   finished_loading)
-{
-  GtkFolderPrivate *priv;
-
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-  priv->finished_loading = (finished_loading == TRUE);
-
-  gdk_threads_enter ();
-  g_signal_emit (folder, folder_signals[FINISHED_LOADING], 0);
-  gdk_threads_leave ();
-}
-
-static void
-gtk_folder_add_file (GtkFolder *folder,
-                    GFile     *file,
-                    GFileInfo *info)
-{
-  GtkFolderPrivate *priv;
-
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-
-  g_hash_table_insert (priv->children,
-                      g_object_ref (file),
-                      g_object_ref (info));
-}
-
-GSList *
-_gtk_folder_list_children (GtkFolder *folder)
-{
-  GtkFolderPrivate *priv;
-  GList *files, *elem;
-  GSList *children = NULL;
-
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-  files = g_hash_table_get_keys (priv->children);
-  children = NULL;
-
-  for (elem = files; elem; elem = elem->next)
-    children = g_slist_prepend (children, g_object_ref (elem->data));
-
-  g_list_free (files);
-
-  return children;
-}
-
-GFileInfo *
-_gtk_folder_get_info (GtkFolder  *folder,
-                     GFile      *file)
-{
-  GtkFolderPrivate *priv;
-  GFileInfo *info;
-
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-  info = g_hash_table_lookup (priv->children, file);
-
-  if (!info)
-    return NULL;
-
-  return g_object_ref (info);
-}
-
-gboolean
-_gtk_folder_is_finished_loading (GtkFolder *folder)
-{
-  GtkFolderPrivate *priv;
-
-  priv = GTK_FOLDER_GET_PRIVATE (folder);
-
-  return priv->finished_loading;
-}
-
 /* GtkFileSystemVolume public methods */
 gchar *
 _gtk_file_system_volume_get_display_name (GtkFileSystemVolume *volume)
@@ -1653,7 +1165,7 @@ get_pixbuf_from_gicon (GIcon      *icon,
     return NULL;
 
   pixbuf = gtk_icon_info_load_icon (icon_info, error);
-  gtk_icon_info_free (icon_info);
+  g_object_unref (icon_info);
 
   return pixbuf;
 }
@@ -1688,8 +1200,22 @@ _gtk_file_system_volume_render_icon (GtkFileSystemVolume  *volume,
   return pixbuf;
 }
 
+GtkFileSystemVolume *
+_gtk_file_system_volume_ref (GtkFileSystemVolume *volume)
+{
+  if (IS_ROOT_VOLUME (volume))
+    return volume;
+
+  if (G_IS_MOUNT (volume)  ||
+      G_IS_VOLUME (volume) ||
+      G_IS_DRIVE (volume))
+    g_object_ref (volume);
+
+  return volume;
+}
+
 void
-_gtk_file_system_volume_free (GtkFileSystemVolume *volume)
+_gtk_file_system_volume_unref (GtkFileSystemVolume *volume)
 {
   /* Root volume doesn't need to be freed */
   if (IS_ROOT_VOLUME (volume))
@@ -1724,7 +1250,39 @@ _gtk_file_info_render_icon (GFileInfo *info,
 
       if (icon)
        pixbuf = get_pixbuf_from_gicon (icon, widget, icon_size, NULL);
+
+      if (!pixbuf)
+       {
+          /* Use general fallback for all files without icon */
+         icon = g_themed_icon_new ("text-x-generic");
+         pixbuf = get_pixbuf_from_gicon (icon, widget, icon_size, NULL);
+         g_object_unref (icon);
+       }
     }
 
   return pixbuf;
 }
+
+gboolean
+_gtk_file_info_consider_as_directory (GFileInfo *info)
+{
+  GFileType type = g_file_info_get_file_type (info);
+  
+  return (type == G_FILE_TYPE_DIRECTORY ||
+          type == G_FILE_TYPE_MOUNTABLE ||
+          type == G_FILE_TYPE_SHORTCUT);
+}
+
+gboolean
+_gtk_file_has_native_path (GFile *file)
+{
+  char *local_file_path;
+  gboolean has_native_path;
+
+  /* Don't use g_file_is_native(), as we want to support FUSE paths if available */
+  local_file_path = g_file_get_path (file);
+  has_native_path = (local_file_path != NULL);
+  g_free (local_file_path);
+
+  return has_native_path;
+}