libgnomeui r5494 - in trunk: . file-chooser



Author: carlosg
Date: Mon Jan 14 22:33:03 2008
New Revision: 5494
URL: http://svn.gnome.org/viewvc/libgnomeui?rev=5494&view=rev

Log:
2008-01-14  Carlos Garnacho  <carlos imendio com>

        * file-chooser/gtkfilesystemgio.[ch]: Add Gio GtkFileSystem
        implementation. #509262
        * configure.in, file-chooser/Makefile.am: Add autofoo.


Added:
   trunk/file-chooser/gtkfilesystemgio.c
   trunk/file-chooser/gtkfilesystemgio.h
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/file-chooser/Makefile.am

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Jan 14 22:33:03 2008
@@ -28,6 +28,7 @@
 m4_define([gnomevfs_required_version],       [2.7.3])
 m4_define([libglade_required_version],       [2.0.0])
 m4_define([gnome_keyring_required_version],       [0.4])
+m4_define([gio_required_version],            [2.15.2])
 
 dnl libtool versioning from libgnome
 
@@ -221,11 +222,16 @@
   libglade-2.0 >= libglade_required_version])
 
 dnl File Chooser stuff
-PKG_CHECK_MODULES(FILE_SYSTEM,
+PKG_CHECK_MODULES(GNOME_VFS_FILE_SYSTEM,
  [gtk+-2.0 >= gtk_required_version dnl
   libgnome-2.0 >= libgnome_required_version dnl
   gnome-vfs-2.0 >= gnomevfs_required_version])
 
+PKG_CHECK_MODULES(GIO_FILE_SYSTEM, [
+	gtk+-2.0 >= gtk_required_version
+	gio-2.0  >= gio_required_version
+])
+
 GTK_BINARY_VERSION=`$PKG_CONFIG --variable=gtk_binary_version gtk+-2.0`
 AC_SUBST(GTK_BINARY_VERSION)
 	

Modified: trunk/file-chooser/Makefile.am
==============================================================================
--- trunk/file-chooser/Makefile.am	(original)
+++ trunk/file-chooser/Makefile.am	Mon Jan 14 22:33:03 2008
@@ -1,9 +1,11 @@
+
 NULL =
 
 INCLUDES =					\
 	-I$(top_srcdir)				\
 	-I$(top_builddir)			\
-	$(FILE_SYSTEM_CFLAGS)			\
+	$(GNOME_VFS_FILE_SYSTEM_CFLAGS)		\
+	$(GIO_FILE_SYSTEM_CFLAGS)		\
 	$(WARN_CFLAGS)				\
 	-DGNOMEUILOCALEDIR="\"$(datadir)/locale\""	\
 	-D_FILE_OFFSET_BITS=64			\
@@ -20,13 +22,18 @@
 
 modules_LTLIBRARIES =				\
 	libgnome-vfs.la			\
+	libgio.la			\
 	$(NULL)
 
 libgnome_vfs_la_SOURCES = gtkfilesystemgnomevfs.c gtkfilesystemgnomevfs.h
 libgnome_vfs_la_LDFLAGS = $(module_flags)
-libgnome_vfs_la_LIBADD = $(FILE_SYSTEM_LIBS)	\
+libgnome_vfs_la_LIBADD = $(GNOME_VFS_FILE_SYSTEM_LIBS)	\
 	$(top_builddir)/libgnomeui/libgnomeui-2.la
 
+libgio_la_SOURCES = gtkfilesystemgio.c gtkfilesystemgio.h
+libgio_la_LDFLAGS = $(module_flags)
+libgio_la_LIBADD = $(GIO_FILE_SYSTEM_LIBS)
+
 EXTRA_DIST = \
 	testfilechooser.c
 

Added: trunk/file-chooser/gtkfilesystemgio.c
==============================================================================
--- (empty file)
+++ trunk/file-chooser/gtkfilesystemgio.c	Mon Jan 14 22:33:03 2008
@@ -0,0 +1,1799 @@
+/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
+/* Copyright (C) 2007 Carlos Garnacho
+ *
+ * This program 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,
+ * 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: Carlos Garnacho Parro  <carlos imendio com>
+ */
+
+#include <config.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include "gtkfilesystemgio.h"
+
+#define GTK_FILE_SYSTEM_GIO_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c),   GTK_TYPE_FILE_SYSTEM_GIO, GtkFileSystemGioClass))
+#define GTK_IS_FILE_SYSTEM_GIO_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c),   GTK_TYPE_FILE_SYSTEM_GIO))
+#define GTK_FILE_SYSTEM_GIO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_FILE_SYSTEM_GIO, GtkFileSystemGioClass))
+
+#define GTK_TYPE_FILE_SYSTEM_HANDLE_GIO  (gtk_file_system_handle_gio_get_type ())
+#define GTK_FILE_SYSTEM_HANDLE_GIO(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_FILE_SYSTEM_HANDLE_GIO, GtkFileSystemHandleGio))
+
+#define GTK_TYPE_FILE_FOLDER_GIO         (gtk_file_folder_gio_get_type ())
+#define GTK_FILE_FOLDER_GIO(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_FILE_FOLDER_GIO, GtkFileFolderGio))
+
+/* #define DEBUG_MODE */
+#ifdef DEBUG_MODE
+#define DEBUG(x) g_debug (x);
+#else
+#define DEBUG(x)
+#endif
+
+#define FILES_PER_QUERY 100
+
+#define MODULE_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init)       { \
+  const GInterfaceInfo g_implement_interface_info = { \
+    (GInterfaceInitFunc) iface_init, NULL, NULL \
+  }; \
+  g_type_module_add_interface (type_module, g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \
+}
+
+typedef struct GtkFileSystemGioClass       GtkFileSystemGioClass;
+typedef struct GtkFileSystemHandleGioClass GtkFileSystemHandleGioClass;
+typedef struct GtkFileSystemHandleGio      GtkFileSystemHandleGio;
+typedef struct GtkFileFolderGioClass       GtkFileFolderGioClass;
+typedef struct GtkFileFolderGio            GtkFileFolderGio;
+typedef struct BookmarkEntry               BookmarkEntry;
+
+struct GtkFileSystemGioClass
+{
+  GObjectClass parent_class;
+};
+
+struct GtkFileSystemGio
+{
+  GObject parent_instance;
+
+  GVolumeMonitor *volume_monitor;
+
+  /* This list contains elements that can be of type GDrive, GVolume and GMount */
+  GSList *volumes;
+
+  GCancellable *cancellable;
+};
+
+struct GtkFileSystemHandleGioClass
+{
+  GtkFileSystemHandleClass parent_class;
+};
+
+struct GtkFileSystemHandleGio
+{
+  GtkFileSystemHandle parent_instance;
+
+  GCancellable *cancellable;
+  guint source_id;
+  gpointer callback;
+  gpointer data;
+};
+
+struct GtkFileFolderGioClass
+{
+  GObjectClass parent_class;
+};
+
+struct GtkFileFolderGio
+{
+  GObject parent_instance;
+
+  GtkFileSystemGio *file_system;
+  GFile *parent_file;
+  GHashTable *children;
+  GFileMonitor *directory_monitor;
+  guint finished_loading : 1;
+};
+
+struct BookmarkEntry
+{
+  gchar *uri;
+  gchar *label;
+};
+
+/* GtkFileSystemGio methods */
+static void gtk_file_system_gio_iface_init     (GtkFileSystemIface     *iface);
+static void gtk_file_system_gio_dispose        (GObject                *object);
+
+/* GtkFileSystemHandleGio methods */
+static GType gtk_file_system_handle_gio_get_type (void);
+static void  gtk_file_system_handle_gio_finalize (GObject *object);
+
+/* GtkFileSystem interface methods */
+static GSList *              gtk_file_system_gio_list_volumes     (GtkFileSystem                  *file_system);
+static GtkFileSystemVolume * gtk_file_system_gio_get_volume_for_path (GtkFileSystem               *file_system,
+								      const GtkFilePath           *path);
+static GtkFileSystemHandle * gtk_file_system_gio_get_folder       (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *path,
+								   GtkFileInfoType                 types,
+								   GtkFileSystemGetFolderCallback  callback,
+								   gpointer                        data);
+
+static GtkFileSystemHandle * gtk_file_system_gio_get_info         (GtkFileSystem                     *file_system,
+								   const GtkFilePath                 *path,
+								   GtkFileInfoType                    types,
+								   GtkFileSystemGetInfoCallback       callback,
+								   gpointer                           data);
+static GtkFileSystemHandle * gtk_file_system_gio_create_folder    (GtkFileSystem                     *file_system,
+								   const GtkFilePath                 *path,
+								   GtkFileSystemCreateFolderCallback  callback,
+								   gpointer                           data);
+static void                  gtk_file_system_gio_cancel_operation (GtkFileSystemHandle               *handle);
+
+
+static void                  gtk_file_system_gio_volume_free             (GtkFileSystem             *file_system,
+									  GtkFileSystemVolume       *volume);
+static GtkFilePath *         gtk_file_system_gio_volume_get_base_path    (GtkFileSystem             *file_system,
+									  GtkFileSystemVolume       *volume);
+static gboolean              gtk_file_system_gio_volume_get_is_mounted   (GtkFileSystem             *file_system,
+									  GtkFileSystemVolume       *volume);
+static GtkFileSystemHandle * gtk_file_system_gio_volume_mount            (GtkFileSystem                    *file_system,
+									  GtkFileSystemVolume              *volume,
+									  GtkFileSystemVolumeMountCallback  callback,
+									  gpointer                          data);
+
+static gchar *               gtk_file_system_gio_volume_get_display_name (GtkFileSystem             *file_system,
+									  GtkFileSystemVolume       *volume);
+static gchar *               gtk_file_system_gio_volume_get_icon_name    (GtkFileSystem             *file_system,
+									  GtkFileSystemVolume       *file_system_volume,
+									  GError                   **error);
+
+static gboolean              gtk_file_system_gio_get_parent       (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *path,
+								   GtkFilePath                   **parent,
+								   GError                        **error);
+static GtkFilePath *         gtk_file_system_gio_make_path        (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *base_path,
+								   const gchar                    *display_name,
+								   GError                        **error);
+static gboolean              gtk_file_system_gio_parse            (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *base_path,
+								   const gchar                    *str,
+								   GtkFilePath                   **folder,
+								   gchar                         **file_part,
+								   GError                        **error);
+static gchar *               gtk_file_system_gio_path_to_uri      (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *path);
+static gchar *               gtk_file_system_gio_path_to_filename (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *path);
+static GtkFilePath *         gtk_file_system_gio_uri_to_path      (GtkFileSystem                  *file_system,
+								   const gchar                    *uri);
+static GtkFilePath *         gtk_file_system_gio_filename_to_path (GtkFileSystem                  *file_system,
+								   const gchar                    *filename);
+
+static gboolean              gtk_file_system_gio_insert_bookmark  (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *path,
+								   gint                            position,
+								   GError                        **error);
+static gboolean              gtk_file_system_gio_remove_bookmark  (GtkFileSystem                  *file_system,
+								   const GtkFilePath              *path,
+								   GError                        **error);
+static GSList *              gtk_file_system_gio_list_bookmarks   (GtkFileSystem                  *file_system);
+
+static gchar *               gtk_file_system_gio_get_bookmark_label (GtkFileSystem                *file_system,
+								     const GtkFilePath            *path);
+static void                  gtk_file_system_gio_set_bookmark_label (GtkFileSystem                *file_system,
+								     const GtkFilePath            *path,
+								     const gchar                  *label);
+
+/* GtkFileFolderGio methods */
+static GType gtk_file_folder_gio_get_type       (void);
+static void  gtk_file_folder_gio_iface_init     (GtkFileFolderIface     *iface);
+static void  gtk_file_folder_gio_finalize       (GObject                *object);
+
+/* GtkFileFolder implementation methods */
+static GtkFileInfo *         gtk_file_folder_gio_get_info         (GtkFileFolder                  *folder,
+								   const GtkFilePath              *path,
+								   GError                        **error);
+static gboolean              gtk_file_folder_gio_list_children    (GtkFileFolder                  *folder,
+								   GSList                        **children,
+								   GError                        **error);
+static gboolean              gtk_file_folder_gio_is_finished_loading (GtkFileFolder               *folder);
+
+/* GtkFileSystem module methods */
+void                         fs_module_init     (GTypeModule    *module);
+void                         fs_module_exit     (void);
+GtkFileSystem *              fs_module_create   (void);
+
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GtkFileSystemGio,
+				gtk_file_system_gio,
+				G_TYPE_OBJECT,
+				0,
+				MODULE_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_SYSTEM,
+							    gtk_file_system_gio_iface_init))
+
+G_DEFINE_DYNAMIC_TYPE (GtkFileSystemHandleGio,
+		       gtk_file_system_handle_gio,
+		       GTK_TYPE_FILE_SYSTEM_HANDLE)
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GtkFileFolderGio,
+				gtk_file_folder_gio,
+				G_TYPE_OBJECT,
+				0,
+				MODULE_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_FOLDER,
+							    gtk_file_folder_gio_iface_init))
+
+/* GtkFileSystemGio methods */
+static void
+gtk_file_system_gio_class_init (GtkFileSystemGioClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->dispose = gtk_file_system_gio_dispose;
+}
+
+static void
+gtk_file_system_gio_class_finalize (GtkFileSystemGioClass *class)
+{
+  DEBUG ("class_finalize");
+}
+
+static void
+get_volumes_list (GtkFileSystemGio *file_system)
+{
+  GList *l, *ll;
+  GList *drives;
+  GList *volumes;
+  GList *mounts;
+  GDrive *drive;
+  GVolume *volume;
+  GMount *mount;
+
+  if (file_system->volumes)
+    {
+      g_slist_foreach (file_system->volumes, (GFunc) g_object_unref, NULL);
+      g_slist_free (file_system->volumes);
+      file_system->volumes = NULL;
+    }
+
+  /* first go through all connected drives */
+  drives = g_volume_monitor_get_connected_drives (file_system->volume_monitor);
+  for (l = drives; l != NULL; l = l->next)
+    {
+      drive = l->data;
+
+      volumes = g_drive_get_volumes (drive);
+      if (volumes)
+        {
+          for (ll = volumes; ll != NULL; ll = ll->next)
+            {
+              volume = ll->data;
+              mount = g_volume_get_mount (volume);
+              if (mount)
+                {
+                  /* Show mounted volume */
+                  file_system->volumes = g_slist_prepend (file_system->volumes, g_object_ref (mount));
+                  g_object_unref (mount);
+                }
+              else
+                {
+                  /* Do show the unmounted volumes in the sidebar;
+                   * this is so the user can mount it (in case automounting
+                   * is off).
+                   *
+                   * Also, even if automounting is enabled, this gives a visual
+                   * cue that the user should remember to yank out the media if
+                   * he just unmounted it.
+                   */
+                  file_system->volumes = g_slist_prepend (file_system->volumes, g_object_ref (volume));
+                }
+              g_object_unref (volume);
+            }
+        }
+      else
+        {
+          if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive))
+            {
+              /* If the drive has no mountable volumes and we cannot detect media change.. we
+               * display the drive in the sidebar so the user can manually poll the drive by
+               * right clicking and selecting "Rescan..."
+               *
+               * This is mainly for drives like floppies where media detection doesn't
+               * work.. but it's also for human beings who like to turn off media detection
+               * in the OS to save battery juice.
+               */
+
+              file_system->volumes = g_slist_prepend (file_system->volumes, g_object_ref (drive));
+            }
+        }
+      g_object_unref (drive);
+    }
+  g_list_free (drives);
+
+  /* add all volumes that is not associated with a drive */
+  volumes = g_volume_monitor_get_volumes (file_system->volume_monitor);
+  for (l = volumes; l != NULL; l = l->next)
+    {
+      volume = l->data;
+      drive = g_volume_get_drive (volume);
+      if (drive)
+        {
+          g_object_unref (volume);
+          g_object_unref (drive);
+          continue;
+        }
+      mount = g_volume_get_mount (volume);
+      if (mount)
+        {
+          /* show this mount */
+          file_system->volumes = g_slist_prepend (file_system->volumes, g_object_ref (mount));
+          g_object_unref (mount);
+        }
+      else
+        {
+          /* see comment above in why we add an icon for a volume */
+          file_system->volumes = g_slist_prepend (file_system->volumes, g_object_ref (volume));
+        }
+      g_object_unref (volume);
+    }
+  g_list_free (volumes);
+
+  /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
+  mounts = g_volume_monitor_get_mounts (file_system->volume_monitor);
+  for (l = mounts; l != NULL; l = l->next)
+    {
+      mount = l->data;
+      volume = g_mount_get_volume (mount);
+      if (volume)
+        {
+          g_object_unref (volume);
+          g_object_unref (mount);
+          continue;
+        }
+
+      /* show this mount */
+      file_system->volumes = g_slist_prepend (file_system->volumes, g_object_ref (mount));
+      g_object_unref (mount);
+    }
+  g_list_free (mounts);
+}
+
+static void
+volumes_drives_changed (GVolumeMonitor *volume_monitor,
+			GVolume        *volume,
+			gpointer        user_data)
+{
+  GtkFileSystemGio *impl;
+
+  impl = GTK_FILE_SYSTEM_GIO (user_data);
+  g_signal_emit_by_name (impl, "volumes-changed");
+}
+
+static gchar *
+get_bookmarks_filename (void)
+{
+  return g_build_filename (g_get_home_dir (),
+			   ".gtk-bookmarks",
+			   NULL);
+}
+
+static void
+gtk_file_system_gio_init (GtkFileSystemGio *impl)
+{
+  GFile *bookmarks_file;
+  gchar *path;
+
+  DEBUG ("init");
+
+  impl->volume_monitor = g_volume_monitor_get ();
+
+  path = get_bookmarks_filename ();
+  bookmarks_file = g_file_new_for_path (path);
+  g_object_unref (bookmarks_file);
+  g_free (path);
+
+  g_signal_connect (impl->volume_monitor, "mount-added",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "mount-removed",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "mount-changed",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "volume-added",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "volume-removed",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "volume-changed",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "drive-connected",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "drive-disconnected",
+		    G_CALLBACK (volumes_drives_changed), impl);
+  g_signal_connect (impl->volume_monitor, "drive-changed",
+		    G_CALLBACK (volumes_drives_changed), impl);
+
+  /* This cancellable will be used for cancelling ongoing
+   * enumerator_next_files operations when the filesystem
+   * is being disposed
+   */
+  impl->cancellable = g_cancellable_new ();
+}
+
+static void
+gtk_file_system_gio_dispose (GObject *object)
+{
+  GtkFileSystemGio *impl;
+
+  DEBUG ("dispose");
+
+  impl = GTK_FILE_SYSTEM_GIO (object);
+
+  if (impl->cancellable)
+    {
+      g_cancellable_cancel (impl->cancellable);
+      g_object_unref (impl->cancellable);
+      impl->cancellable = NULL;
+    }
+
+  if (impl->volumes)
+    {
+      g_slist_foreach (impl->volumes, (GFunc) g_object_unref, NULL);
+      g_slist_free (impl->volumes);
+      impl->volumes = NULL;
+    }
+
+  if (impl->volume_monitor)
+    g_object_unref (impl->volume_monitor);
+
+  G_OBJECT_CLASS (gtk_file_system_gio_parent_class)->dispose (object);
+}
+
+/* GtkFileSystemHandleGio methods */
+static void
+gtk_file_system_handle_gio_class_init (GtkFileSystemHandleGioClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = gtk_file_system_handle_gio_finalize;
+}
+
+static void
+gtk_file_system_handle_gio_class_finalize (GtkFileSystemHandleGioClass *class)
+{
+}
+
+static void
+gtk_file_system_handle_gio_init (GtkFileSystemHandleGio *impl)
+{
+}
+
+static void
+gtk_file_system_handle_gio_finalize (GObject *object)
+{
+  GtkFileSystemHandleGio *handle;
+
+  DEBUG ("handle finalize");
+
+  handle = GTK_FILE_SYSTEM_HANDLE_GIO (object);
+
+  if (handle->cancellable)
+    g_object_unref (handle->cancellable);
+
+  G_OBJECT_CLASS (gtk_file_system_handle_gio_parent_class)->finalize (object);
+}
+
+/* GtkFileSystem interface implementation */
+static void
+gtk_file_system_gio_iface_init (GtkFileSystemIface *iface)
+{
+  DEBUG ("iface_init");
+
+  iface->list_volumes = gtk_file_system_gio_list_volumes;
+  iface->get_volume_for_path = gtk_file_system_gio_get_volume_for_path;
+  iface->get_folder = gtk_file_system_gio_get_folder;
+  iface->get_info = gtk_file_system_gio_get_info;
+  iface->create_folder = gtk_file_system_gio_create_folder;
+  iface->cancel_operation = gtk_file_system_gio_cancel_operation;
+  iface->volume_free = gtk_file_system_gio_volume_free;
+  iface->volume_get_base_path = gtk_file_system_gio_volume_get_base_path;
+  iface->volume_get_is_mounted = gtk_file_system_gio_volume_get_is_mounted;
+  iface->volume_mount = gtk_file_system_gio_volume_mount;
+  iface->volume_get_display_name = gtk_file_system_gio_volume_get_display_name;
+  iface->volume_get_icon_name = gtk_file_system_gio_volume_get_icon_name;
+  iface->get_parent = gtk_file_system_gio_get_parent;
+  iface->make_path = gtk_file_system_gio_make_path;
+  iface->parse = gtk_file_system_gio_parse;
+  iface->path_to_uri = gtk_file_system_gio_path_to_uri;
+  iface->path_to_filename = gtk_file_system_gio_path_to_filename;
+  iface->uri_to_path = gtk_file_system_gio_uri_to_path;
+  iface->filename_to_path = gtk_file_system_gio_filename_to_path;
+  iface->insert_bookmark = gtk_file_system_gio_insert_bookmark;
+  iface->remove_bookmark = gtk_file_system_gio_remove_bookmark;
+  iface->list_bookmarks = gtk_file_system_gio_list_bookmarks;
+  iface->get_bookmark_label = gtk_file_system_gio_get_bookmark_label;
+  iface->set_bookmark_label = gtk_file_system_gio_set_bookmark_label;
+}
+
+static GFile *
+get_file_from_path (const GtkFilePath *path)
+{
+  const gchar *uri;
+
+  uri = gtk_file_path_get_string (path);
+  return g_file_new_for_uri (uri);
+}
+
+static GtkFilePath *
+get_path_from_file (GFile *file)
+{
+  gchar *uri;
+
+  uri = g_file_get_uri (file);
+  return gtk_file_path_new_steal (uri);
+}
+
+static GSList *
+gtk_file_system_gio_list_volumes (GtkFileSystem *file_system)
+{
+  GtkFileSystemGio *file_system_gio;
+  GSList *list;
+
+  DEBUG ("list_volumes");
+
+  get_volumes_list (GTK_FILE_SYSTEM_GIO (file_system));
+
+  file_system_gio = GTK_FILE_SYSTEM_GIO (file_system);
+  list = g_slist_copy (file_system_gio->volumes);
+  g_slist_foreach (list, (GFunc) g_object_ref, NULL);
+
+  return list;
+}
+
+static GtkFileSystemVolume *
+gtk_file_system_gio_get_volume_for_path (GtkFileSystem     *file_system,
+					 const GtkFilePath *path)
+{
+  GtkFileSystemGio *file_system_gio;
+  GFile *file;
+  GMount *mount;
+  GSList *list;
+
+  DEBUG ("get_volume_for_path");
+
+  file_system_gio = GTK_FILE_SYSTEM_GIO (file_system);
+  file = get_file_from_path (path);
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  for (list = file_system_gio->volumes; list; list = list->next)
+    {
+      if (g_type_is_a (G_OBJECT_TYPE (list->data), G_TYPE_MOUNT))
+        {
+          GFile *root;
+
+          mount = list->data;
+          root = g_mount_get_root (mount);
+          if (g_file_contains_file (root, file))
+            {
+              mount = list->data;
+              break;
+            }
+          g_object_unref (root);
+
+          mount = NULL;
+        }
+
+    }
+
+  g_object_unref (file);
+
+  if (mount)
+    return (GtkFileSystemVolume *) g_object_ref (mount);
+
+  return NULL;
+}
+
+static void
+enumerator_files_callback (GObject      *source_object,
+			   GAsyncResult *result,
+			   gpointer      user_data)
+{
+  GtkFileSystemGio *file_system;
+  GFileEnumerator *enumerator;
+  GtkFileFolderGio *folder;
+  GError *error = NULL;
+  GSList *added_files = NULL;
+  GList *files, *f;
+
+  folder = GTK_FILE_FOLDER_GIO (user_data);
+  file_system = folder->file_system;
+  enumerator = G_FILE_ENUMERATOR (source_object);
+  files = g_file_enumerator_next_files_finish (enumerator, result, &error);
+
+  if (!files)
+    {
+      /* There's no way to spread the error up to the filechooser, if any */
+      g_file_enumerator_close_async (enumerator,
+				     G_PRIORITY_DEFAULT,
+				     NULL, NULL, NULL);
+
+      folder->finished_loading = TRUE;
+      g_signal_emit_by_name (folder, "finished-loading", 0);
+      g_object_unref (folder);
+      return;
+    }
+
+  for (f = files; f; f = f->next)
+    {
+      GFileInfo *info;
+      GFile *child_file;
+
+      info = f->data;
+      child_file = g_file_resolve_relative_path (folder->parent_file, g_file_info_get_name (info));
+      g_hash_table_insert (folder->children, g_file_get_uri (child_file), info);
+      added_files = g_slist_prepend (added_files, get_path_from_file (child_file));
+
+      g_object_unref (child_file);
+    }
+
+  g_file_enumerator_next_files_async (enumerator, FILES_PER_QUERY,
+				      G_PRIORITY_DEFAULT,
+				      file_system->cancellable,
+				      enumerator_files_callback,
+				      folder);
+
+  g_signal_emit_by_name (folder, "files-added", added_files);
+  g_slist_foreach (added_files, (GFunc) g_free, NULL);
+  g_slist_free (added_files);
+
+  g_list_free (files);
+}
+
+static void
+directory_monitor_changed (GFileMonitor      *monitor,
+			   GFile             *file,
+			   GFile             *other_file,
+			   GFileMonitorEvent  event,
+			   gpointer           data)
+{
+  GtkFileFolder *folder;
+  GSList *files;
+
+  folder = GTK_FILE_FOLDER (data);
+  files = g_slist_prepend (NULL, get_path_from_file (file));
+
+  switch (event)
+    {
+    case G_FILE_MONITOR_EVENT_CREATED:
+      g_signal_emit_by_name (folder, "files-added", files);
+      break;
+    case G_FILE_MONITOR_EVENT_DELETED:
+      g_signal_emit_by_name (folder, "files-removed", files);
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+enumerate_children_callback (GObject      *source_object,
+			     GAsyncResult *result,
+			     gpointer      user_data)
+{
+  GtkFileSystemGio *file_system;
+  GtkFileSystemHandleGio *handle;
+  GtkFileFolderGio *folder = NULL;
+  GFileEnumerator *enumerator;
+  GFile *file;
+  GError *error = NULL;
+
+  file = G_FILE (source_object);
+  handle = GTK_FILE_SYSTEM_HANDLE_GIO (user_data);
+  file_system = GTK_FILE_SYSTEM_GIO (GTK_FILE_SYSTEM_HANDLE (handle)->file_system);
+  enumerator = g_file_enumerate_children_finish (file, result, &error);
+
+  if (enumerator)
+    {
+      folder = g_object_new (GTK_TYPE_FILE_FOLDER_GIO, NULL);
+      folder->file_system = file_system;
+      folder->parent_file = g_object_ref (file);
+      folder->children = g_hash_table_new_full (g_str_hash, g_str_equal,
+						(GDestroyNotify) g_free,
+						(GDestroyNotify) g_object_unref);
+      folder->finished_loading = FALSE;
+
+      folder->directory_monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, &error);
+
+      if (error)
+	g_warning (error->message);
+      else
+	g_signal_connect (folder->directory_monitor, "changed",
+			  G_CALLBACK (directory_monitor_changed), folder);
+
+      g_file_enumerator_next_files_async (enumerator, FILES_PER_QUERY,
+					  G_PRIORITY_DEFAULT,
+					  file_system->cancellable,
+					  enumerator_files_callback,
+					  g_object_ref (folder));
+      g_object_unref (enumerator);
+    }
+
+  ((GtkFileSystemGetFolderCallback) handle->callback) (GTK_FILE_SYSTEM_HANDLE (handle),
+						       GTK_FILE_FOLDER (folder),
+						       error, handle->data);
+}
+
+static GtkFileSystemHandle *
+gtk_file_system_gio_get_folder (GtkFileSystem                  *file_system,
+				const GtkFilePath              *path,
+				GtkFileInfoType                 types,
+				GtkFileSystemGetFolderCallback  callback,
+				gpointer                        data)
+{
+  GtkFileSystemHandleGio *handle;
+  GFile *file;
+
+  DEBUG ("get_folder");
+
+  file = get_file_from_path (path);
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE_GIO, NULL);
+  GTK_FILE_SYSTEM_HANDLE (handle)->file_system = file_system;
+  handle->cancellable = g_cancellable_new ();
+  handle->callback = callback;
+  handle->data = data;
+
+  g_file_enumerate_children_async (file, "standard,time,thumbnail::*", 0, 0,
+				   handle->cancellable,
+				   enumerate_children_callback,
+				   handle);
+  g_object_unref (file);
+
+  return GTK_FILE_SYSTEM_HANDLE (handle);
+}
+
+static gchar *
+get_icon_string (GIcon *icon)
+{
+  gchar *name = NULL;
+
+  if (!icon)
+    return NULL;
+
+  if (G_IS_THEMED_ICON (icon))
+    {
+      const gchar * const *names;
+
+      /* FIXME: choose between names */
+      names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+
+      if (names)
+	name = g_strdup (names [0]);
+    }
+  else if (G_IS_FILE_ICON (icon))
+    {
+      GFile *icon_file;
+
+      icon_file = g_file_icon_get_file (G_FILE_ICON (icon));
+      name = g_file_get_path (icon_file);
+      g_object_unref (icon_file);
+    }
+
+  return name;
+}
+
+static GtkFileInfo *
+translate_file_info (GFileInfo *file_info)
+{
+  GtkFileInfo *info;
+  gboolean is_folder;
+  GTimeVal mtime;
+  const gchar *thumbnail_path;
+
+  info = gtk_file_info_new ();
+  is_folder = (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY);
+  g_file_info_get_modification_time (file_info, &mtime);
+
+  gtk_file_info_set_display_name (info, g_file_info_get_display_name (file_info));
+  gtk_file_info_set_is_folder (info, is_folder);
+  gtk_file_info_set_is_hidden (info, g_file_info_get_is_hidden (file_info));
+  gtk_file_info_set_mime_type (info, g_file_info_get_content_type (file_info));
+  gtk_file_info_set_modification_time (info, mtime.tv_sec);
+  gtk_file_info_set_size (info, g_file_info_get_size (file_info));
+
+  thumbnail_path = g_file_info_get_attribute_byte_string (file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
+
+  if (thumbnail_path)
+    gtk_file_info_set_icon_name (info, thumbnail_path);
+  else
+    {
+      GIcon *icon;
+      gchar *name;
+
+      icon = g_file_info_get_icon (file_info);
+      name = get_icon_string (icon);
+      gtk_file_info_set_icon_name (info, name);
+
+      g_free (name);
+    }
+
+  return info;
+}
+
+static void
+query_info_callback (GObject      *source_object,
+		     GAsyncResult *result,
+		     gpointer      user_data)
+{
+  GtkFileSystemHandleGio *handle;
+  GtkFileInfo *info = NULL;
+  GError *error = NULL;
+  GFileInfo *file_info;
+  GFile *file;
+
+  DEBUG ("query_info_callback");
+
+  file = G_FILE (source_object);
+  handle = GTK_FILE_SYSTEM_HANDLE_GIO (user_data);
+  file_info = g_file_query_info_finish (file, result, &error);
+
+  if (file_info)
+    {
+      info = translate_file_info (file_info);
+      g_object_unref (file_info);
+    }
+
+  ((GtkFileSystemGetInfoCallback) handle->callback) (GTK_FILE_SYSTEM_HANDLE (handle),
+						     info, error, handle->data);
+
+  if (info)
+    gtk_file_info_free (info);
+}
+
+static GtkFileSystemHandle *
+gtk_file_system_gio_get_info (GtkFileSystem                *file_system,
+			      const GtkFilePath            *path,
+			      GtkFileInfoType               types,
+			      GtkFileSystemGetInfoCallback  callback,
+			      gpointer                      data)
+{
+  GtkFileSystemHandleGio *handle;
+  GFile *file;
+
+  DEBUG ("get_info");
+
+  file = get_file_from_path (path);
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE_GIO, NULL);
+  GTK_FILE_SYSTEM_HANDLE (handle)->file_system = file_system;
+  handle->cancellable = g_cancellable_new ();
+  handle->callback = callback;
+  handle->data = data;
+
+  g_file_query_info_async (file, "standard,time,thumbnail::*", 0, 0,
+			   handle->cancellable,
+			   query_info_callback,
+			   handle);
+
+  g_object_unref (file);
+
+  return GTK_FILE_SYSTEM_HANDLE (g_object_ref (handle));
+}
+
+typedef struct
+{
+  GtkFilePath *path;
+  GtkFileSystemHandleGio *handle;
+} CreateFolderData;
+
+static gboolean
+create_folder_callback (gpointer data)
+{
+  GtkFileSystemHandleGio *handle;
+  CreateFolderData *idle_data;
+  GError *error = NULL;
+  GFile *file;
+
+  idle_data = (CreateFolderData *) data;
+  handle = idle_data->handle;
+  file = get_file_from_path (idle_data->path);
+
+  g_file_make_directory (file, handle->cancellable, &error);
+
+  ((GtkFileSystemCreateFolderCallback) handle->callback) (GTK_FILE_SYSTEM_HANDLE (handle),
+							  idle_data->path, error, handle->data);
+  g_object_unref (file);
+  gtk_file_path_free (idle_data->path);
+  g_slice_free (CreateFolderData, idle_data);
+
+  return FALSE;
+}
+
+static GtkFileSystemHandle *
+gtk_file_system_gio_create_folder (GtkFileSystem                     *file_system,
+				   const GtkFilePath                 *path,
+				   GtkFileSystemCreateFolderCallback  callback,
+				   gpointer                           data)
+{
+  GtkFileSystemHandleGio *handle;
+  CreateFolderData *idle_data;
+
+  DEBUG ("create_folder");
+
+  /* FIXME: make_directory() doesn't seem to have async version */
+
+  handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE_GIO, NULL);
+  GTK_FILE_SYSTEM_HANDLE (handle)->file_system = file_system;
+  handle->cancellable = g_cancellable_new ();
+  handle->callback = callback;
+  handle->data = data;
+
+  idle_data = g_slice_new (CreateFolderData);
+  idle_data->path = gtk_file_path_copy (path);
+  idle_data->handle = handle;
+
+  handle->source_id = gdk_threads_add_idle (create_folder_callback, idle_data);
+
+  return GTK_FILE_SYSTEM_HANDLE (handle);
+}
+
+static void
+gtk_file_system_gio_cancel_operation (GtkFileSystemHandle *handle)
+{
+  GtkFileSystemHandleGio *handle_gio;
+
+  DEBUG ("cancel_operation");
+
+  handle_gio = GTK_FILE_SYSTEM_HANDLE_GIO (handle);
+
+  if (handle_gio->cancellable)
+    {
+      g_cancellable_cancel (handle_gio->cancellable);
+      g_object_unref (handle_gio->cancellable);
+      handle_gio->cancellable = NULL;
+    }
+
+  if (handle_gio->source_id)
+    {
+      /* This is only for functions without async option */
+      g_source_remove (handle_gio->source_id);
+      handle_gio->source_id = 0;
+    }
+}
+
+static void
+gtk_file_system_gio_volume_free (GtkFileSystem       *file_system,
+				 GtkFileSystemVolume *volume)
+{
+  DEBUG ("volume_free");
+  g_object_unref (G_OBJECT (volume));
+}
+
+static GtkFilePath *
+gtk_file_system_gio_volume_get_base_path (GtkFileSystem       *file_system,
+					  GtkFileSystemVolume *file_system_volume)
+{
+  GFile *root;
+  GtkFilePath *path;
+
+  DEBUG ("volume_get_base_path");
+
+  path = NULL;
+
+  if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_MOUNT))
+    {
+      GMount *mount = G_MOUNT (file_system_volume);
+
+      root = g_mount_get_root (mount);
+      path = get_path_from_file (root);
+      g_object_unref (root);
+    }
+  else if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_VOLUME))
+    {
+      GMount *mount;
+      GVolume *volume = G_VOLUME (file_system_volume);
+
+      mount = g_volume_get_mount (volume);
+
+      if (mount)
+        {
+          root = g_mount_get_root (mount);
+          path = get_path_from_file (root);
+          g_object_unref (mount);
+        }
+    }
+
+  return path;
+}
+
+static gboolean
+gtk_file_system_gio_volume_get_is_mounted (GtkFileSystem       *file_system,
+					   GtkFileSystemVolume *file_system_volume)
+{
+  gboolean mounted;
+
+  DEBUG ("volume_get_is_mounted");
+
+  mounted = FALSE;
+
+  if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_MOUNT))
+    mounted = TRUE;
+  else if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_VOLUME))
+    {
+      GMount *mount;
+      GVolume *volume = G_VOLUME (file_system_volume);
+
+      mount = g_volume_get_mount (volume);
+
+      if (mount)
+        {
+          mounted = TRUE;
+          g_object_unref (mount);
+        }
+    }
+
+  return mounted;
+}
+
+static void
+volume_mount_cb (GObject *source_object,
+		 GAsyncResult *res,
+		 gpointer user_data)
+{
+  GError *error = NULL;
+  GtkFileSystemHandleGio *handle;
+
+  handle = GTK_FILE_SYSTEM_HANDLE_GIO (user_data);
+
+  g_volume_mount_finish (G_VOLUME (source_object), res, &error);
+
+  ((GtkFileSystemVolumeMountCallback) handle->callback) (GTK_FILE_SYSTEM_HANDLE (handle),
+                                                         (GtkFileSystemVolume *) source_object,
+                                                         error, handle->data);
+  if (error)
+    g_error_free (error);
+}
+
+static void
+drive_poll_for_media_cb (GObject *source_object,
+                         GAsyncResult *res,
+                         gpointer user_data)
+{
+  GError *error = NULL;
+  GtkFileSystemHandleGio *handle;
+
+  handle = GTK_FILE_SYSTEM_HANDLE_GIO (user_data);
+
+  g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error);
+
+  ((GtkFileSystemVolumeMountCallback) handle->callback) (GTK_FILE_SYSTEM_HANDLE (handle),
+                                                         (GtkFileSystemVolume *) source_object,
+                                                         error, handle->data);
+  if (error)
+    g_error_free (error);
+}
+
+GtkFileSystemHandle *
+gtk_file_system_gio_volume_mount (GtkFileSystem                    *file_system,
+				  GtkFileSystemVolume              *file_system_volume,
+				  GtkFileSystemVolumeMountCallback  callback,
+				  gpointer                          data)
+{
+  GtkFileSystemHandleGio *handle;
+
+  DEBUG ("volume_mount");
+
+  handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE_GIO, NULL);
+  GTK_FILE_SYSTEM_HANDLE (handle)->file_system = file_system;
+  handle->cancellable = g_cancellable_new ();
+  handle->callback = callback;
+  handle->data = data;
+
+  if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_DRIVE))
+    {
+      GDrive *drive = G_DRIVE (file_system_volume);
+
+      /* this path happens for drives that are not polled by the OS and where the last media
+       * check indicated that no media was available. So the thing to do here is to
+       * invoke poll_for_media() on the drive
+       */
+      g_drive_poll_for_media (drive, handle->cancellable, drive_poll_for_media_cb, handle);
+    }
+  else
+    {
+      GVolume *volume = G_VOLUME (file_system_volume);
+      GMountOperation *mount_op;
+
+      mount_op = g_mount_operation_new ();
+      g_volume_mount (volume, mount_op, handle->cancellable, volume_mount_cb, handle);
+      g_object_unref (mount_op);
+    }
+
+  return GTK_FILE_SYSTEM_HANDLE (handle);
+}
+
+static gchar *
+gtk_file_system_gio_volume_get_display_name (GtkFileSystem       *file_system,
+					     GtkFileSystemVolume *file_system_volume)
+{
+  gchar *name = NULL;
+
+  DEBUG ("volume_get_display_name");
+
+  if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_DRIVE))
+    {
+      GDrive *drive = G_DRIVE (file_system_volume);
+      name = g_drive_get_name (drive);
+    }
+  else if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_VOLUME))
+    {
+      GVolume *volume = G_VOLUME (file_system_volume);
+      name = g_volume_get_name (volume);
+    }
+  else if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_MOUNT))
+    {
+      GMount *mount = G_MOUNT (file_system_volume);
+      name = g_mount_get_name (mount);
+    }
+
+  return name;
+}
+
+static gchar *
+gtk_file_system_gio_volume_get_icon_name (GtkFileSystem        *file_system,
+					  GtkFileSystemVolume  *file_system_volume,
+					  GError              **error)
+{
+  char *name;
+  GIcon *icon = NULL;
+
+  DEBUG ("volume_get_icon_name");
+
+  if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_DRIVE))
+    {
+      GDrive *drive = G_DRIVE (file_system_volume);
+      icon = g_drive_get_icon (drive);
+    }
+  else if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_VOLUME))
+    {
+      GVolume *volume = G_VOLUME (file_system_volume);
+      icon = g_volume_get_icon (volume);
+    }
+  else if (g_type_is_a (G_OBJECT_TYPE (file_system_volume), G_TYPE_MOUNT))
+    {
+      GMount *mount = G_MOUNT (file_system_volume);
+      icon = g_mount_get_icon (mount);
+    }
+
+  name = get_icon_string (icon);
+
+  return name;
+}
+
+static gboolean
+gtk_file_system_gio_get_parent (GtkFileSystem      *file_system,
+				const GtkFilePath  *path,
+				GtkFilePath       **parent,
+				GError            **error)
+{
+  GFile *file, *parent_file;
+
+  DEBUG ("get_parent");
+  file = get_file_from_path (path);
+  parent_file = g_file_get_parent (file);
+
+  if (parent_file)
+    {
+      *parent = get_path_from_file (parent_file);
+      g_object_unref (parent_file);
+    }
+  else
+    *parent = NULL;
+
+  g_object_unref (file);
+
+  return TRUE;
+}
+
+static GtkFilePath *
+gtk_file_system_gio_make_path (GtkFileSystem      *file_system,
+			       const GtkFilePath  *base_path,
+			       const gchar        *display_name,
+			       GError            **error)
+{
+  GFile *base_path_file, *file;
+  GtkFilePath *path = NULL;
+
+  DEBUG ("make_path");
+
+  /* FIXME: should check for dir separator */
+
+  base_path_file = get_file_from_path (base_path);
+  file = g_file_get_child_for_display_name (base_path_file, display_name, error);
+  g_object_unref (base_path_file);
+
+  if (file)
+    {
+      path = get_path_from_file (file);
+      g_object_unref (file);
+    }
+
+  return path;
+}
+
+static gboolean
+gtk_file_system_gio_parse (GtkFileSystem     *file_system,
+			   const GtkFilePath *base_path,
+			   const gchar       *str,
+			   GtkFilePath      **folder,
+			   gchar            **file_part,
+			   GError           **error)
+{
+  GFile *base_path_file, *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);
+  base_path_file = get_file_from_path (base_path);
+
+  if (str[0] == '~')
+    file = g_file_parse_name (str);
+  else
+    file = g_file_resolve_relative_path (base_path_file, str);
+
+  if (g_file_equal (base_path_file, file))
+    {
+      /* this is when user types '.', could be the
+       * beginning of a hidden file, ./ or ../
+       */
+      *folder = get_path_from_file (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 = get_path_from_file (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_SYSTEM_ERROR,
+		       GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
+		       "Could not get parent file");
+	  *folder = NULL;
+	  *file_part = NULL;
+	}
+      else
+	{
+	  *folder = get_path_from_file (parent_file);
+	  g_object_unref (parent_file);
+
+	  result = TRUE;
+
+	  if (last_slash)
+	    *file_part = g_strdup (last_slash + 1);
+	  else
+	    *file_part = g_strdup (str);
+	}
+    }
+
+  g_object_unref (base_path_file);
+  g_object_unref (file);
+
+  return result;
+}
+
+static gchar *
+gtk_file_system_gio_path_to_uri (GtkFileSystem     *file_system,
+				 const GtkFilePath *path)
+{
+  GFile *file;
+  gchar *uri;
+
+  DEBUG ("path_to_uri");
+
+  file = get_file_from_path (path);
+  uri = g_file_get_uri (file);
+  g_object_unref (file);
+
+  return uri;
+}
+
+static gchar *
+gtk_file_system_gio_path_to_filename (GtkFileSystem     *file_system,
+				      const GtkFilePath *path)
+{
+  GFile *file;
+  gchar *path_str;
+
+  DEBUG ("path_to_filename");
+
+  file = get_file_from_path (path);
+  path_str = g_file_get_path (file);
+  g_object_unref (file);
+
+  return path_str;
+}
+
+static GtkFilePath *
+gtk_file_system_gio_uri_to_path (GtkFileSystem *file_system,
+				 const gchar   *uri)
+{
+  GFile *file;
+  GtkFilePath *path;
+
+  DEBUG ("uri_to_path");
+
+  /* leave to GFile the task of canonicalizing
+   * the uri in order to create the GtkFilePath
+   */
+  file = g_file_new_for_uri (uri);
+  path = get_path_from_file (file);
+  g_object_unref (file);
+
+  return path;
+}
+
+static GtkFilePath *
+gtk_file_system_gio_filename_to_path (GtkFileSystem *file_system,
+				      const gchar   *filename)
+{
+  GFile *file;
+  GtkFilePath *path;
+
+  DEBUG ("filename_to_path");
+  file = g_file_new_for_path (filename);
+  path = get_path_from_file (file);
+  g_object_unref (file);
+
+  return path;
+}
+
+static GList *
+read_bookmarks_file (void)
+{
+  gchar *filename, *contents;
+  gchar **lines, *space;
+  GError *error = NULL;
+  GList *bookmarks = NULL;
+  GFile *file;
+  gint i;
+
+  filename = get_bookmarks_filename ();
+  file = g_file_new_for_path (filename);
+  g_free (filename);
+
+  if (!g_file_load_contents (file, NULL, &contents,
+			     NULL, NULL, &error))
+    {
+      if (error)
+	{
+	  g_critical (error->message);
+	  g_error_free (error);
+	}
+
+      return NULL;
+    }
+
+  lines = g_strsplit (contents, "\n", -1);
+
+  for (i = 0; lines[i]; i++)
+    {
+      BookmarkEntry *entry;
+
+      if (!*lines[i])
+	continue;
+
+      entry = g_slice_new0 (BookmarkEntry);
+
+      if ((space = strchr (lines[i], ' ')) != NULL)
+	{
+	  space[0] = '\0';
+	  entry->label = g_strdup (space + 1);
+	}
+
+      entry->uri = g_strdup (lines[i]);
+      bookmarks = g_list_prepend (bookmarks, entry);
+    }
+
+  g_strfreev (lines);
+  g_free (contents);
+  g_object_unref (file);
+
+  return bookmarks;
+}
+
+static void
+save_bookmarks_file (GList *bookmarks)
+{
+  GError *error = NULL;
+  gchar *filename;
+  GString *contents;
+  GList *elem;
+  GFile *file;
+
+  /* read_bookmarks_file returns the list reversed
+   * in order to just prepend elements in list_bookmarks,
+   * so to keep the same order we have to reverse it here
+   */
+  bookmarks = g_list_reverse (bookmarks);
+
+  filename = get_bookmarks_filename ();
+  file = g_file_new_for_path (filename);
+  g_free (filename);
+
+  contents = g_string_new ("");
+
+  for (elem = bookmarks; elem; elem = elem->next)
+    {
+      BookmarkEntry *entry = elem->data;
+
+      g_string_append (contents, entry->uri);
+
+      if (entry->label)
+	g_string_append_printf (contents, " %s", entry->label);
+
+      g_string_append_c (contents, '\n');
+    }
+
+  if (!g_file_replace_contents (file, contents->str,
+				strlen (contents->str),
+				NULL, FALSE, 0, NULL,
+				NULL, &error))
+    {
+      g_critical (error->message);
+      g_error_free (error);
+    }
+
+  g_object_unref (file);
+  g_string_free (contents, TRUE);
+}
+
+static void
+free_bookmark_entry (BookmarkEntry *entry)
+{
+  g_free (entry->uri);
+  g_free (entry->label);
+  g_slice_free (BookmarkEntry, entry);
+}
+
+static void
+free_bookmarks (GList *bookmarks)
+{
+  g_list_foreach (bookmarks, (GFunc) free_bookmark_entry, NULL);
+  g_list_free (bookmarks);
+}
+
+static gboolean
+gtk_file_system_gio_insert_bookmark (GtkFileSystem      *file_system,
+				     const GtkFilePath  *path,
+				     gint                position,
+				     GError            **error)
+{
+  GList *bookmarks, *elem;
+  BookmarkEntry *entry;
+  gboolean result = TRUE;
+  gchar *uri;
+
+  bookmarks = read_bookmarks_file ();
+  uri = gtk_file_system_gio_path_to_uri (file_system, path);
+
+  for (elem = bookmarks; elem; elem = elem->next)
+    {
+      entry = elem->data;
+
+      if (strcmp (uri, entry->uri) == 0)
+	{
+	  /* uh oh, found the same entry */
+	  result = FALSE;
+	  break;
+	}
+    }
+
+  if (!result)
+    {
+      g_set_error (error,
+		   GTK_FILE_SYSTEM_ERROR,
+		   GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
+		   "%s already exists in the bookmarks list",
+		   uri);
+      g_free (uri);
+      return FALSE;
+    }
+
+  entry = g_slice_new0 (BookmarkEntry);
+  entry->uri = uri;
+
+  bookmarks = g_list_insert (bookmarks, entry, position);
+  save_bookmarks_file (bookmarks);
+  free_bookmarks (bookmarks);
+
+  g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_file_system_gio_remove_bookmark (GtkFileSystem      *file_system,
+				     const GtkFilePath  *path,
+				     GError            **error)
+{
+  GList *bookmarks;
+  gboolean result = FALSE;
+  GList *elem;
+  gchar *uri;
+
+  bookmarks = read_bookmarks_file ();
+
+  if (!bookmarks)
+    return FALSE;
+
+  uri = gtk_file_system_gio_path_to_uri (file_system, path);
+
+  for (elem = bookmarks; elem; elem = elem->next)
+    {
+      BookmarkEntry *entry = (BookmarkEntry *) elem->data;
+
+      if (strcmp (uri, entry->uri) != 0)
+	continue;
+
+      result = TRUE;
+      bookmarks = g_list_remove (bookmarks, entry);
+      free_bookmark_entry (entry);
+    }
+
+  if (!result)
+    {
+      g_set_error (error,
+		   GTK_FILE_SYSTEM_ERROR,
+		   GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
+		   "%s does not exist in the bookmarks list",
+		   uri);
+      return FALSE;
+    }
+
+  save_bookmarks_file (bookmarks);
+  free_bookmarks (bookmarks);
+  g_free (uri);
+
+  g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
+
+  return TRUE;
+}
+
+static GSList *
+gtk_file_system_gio_list_bookmarks (GtkFileSystem *file_system)
+{
+  GList *bookmarks, *elem;
+  GSList *list = NULL;
+
+  DEBUG ("list_bookmarks");
+  bookmarks = read_bookmarks_file ();
+
+  for (elem = bookmarks; elem; elem = elem->next)
+    {
+      BookmarkEntry *entry = elem->data;
+      list = g_slist_prepend (list, g_strdup (entry->uri));
+    }
+
+  free_bookmarks (bookmarks);
+
+  return list;
+}
+
+static gchar *
+gtk_file_system_gio_get_bookmark_label (GtkFileSystem     *file_system,
+					const GtkFilePath *path)
+{
+  GList *bookmarks, *elem;
+  gchar *uri, *label = NULL;
+
+  DEBUG ("get_bookmark_label");
+
+  bookmarks = read_bookmarks_file ();
+  uri = gtk_file_system_gio_path_to_uri (file_system, path);
+
+  for (elem = bookmarks; elem; elem = elem->next)
+    {
+      BookmarkEntry *entry = elem->data;
+
+      if (strcmp (uri, entry->uri) == 0)
+	{
+	  label = g_strdup (entry->label);
+	  break;
+	}
+    }
+
+  free_bookmarks (bookmarks);
+  g_free (uri);
+
+  return label;
+}
+
+static void
+gtk_file_system_gio_set_bookmark_label (GtkFileSystem     *file_system,
+					const GtkFilePath *path,
+					const gchar       *label)
+{
+  GList *bookmarks, *elem;
+  gboolean changed = FALSE;
+  gchar *uri;
+
+  DEBUG ("set_bookmark_label");
+
+  bookmarks = read_bookmarks_file ();
+  uri = gtk_file_system_gio_path_to_uri (file_system, path);
+
+  for (elem = bookmarks; elem; elem = elem->next)
+    {
+      BookmarkEntry *entry = elem->data;
+
+      if (strcmp (uri, entry->uri) == 0)
+	{
+	  g_free (entry->label);
+	  entry->label = g_strdup (label);
+	  changed = TRUE;
+
+	  break;
+	}
+    }
+
+  save_bookmarks_file (bookmarks);
+  free_bookmarks (bookmarks);
+
+  if (changed)
+    g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
+
+  g_free (uri);
+}
+
+/* GtkFileFolder methods */
+static void
+gtk_file_folder_gio_class_init (GtkFileFolderGioClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = gtk_file_folder_gio_finalize;
+}
+
+static void
+gtk_file_folder_gio_iface_init (GtkFileFolderIface *iface)
+{
+  iface->get_info = gtk_file_folder_gio_get_info;
+  iface->list_children = gtk_file_folder_gio_list_children;
+  iface->is_finished_loading = gtk_file_folder_gio_is_finished_loading;
+}
+
+static void
+gtk_file_folder_gio_init (GtkFileFolderGio *impl)
+{
+}
+
+static void
+gtk_file_folder_gio_class_finalize (GtkFileFolderGioClass *class)
+{
+}
+
+static void
+gtk_file_folder_gio_finalize (GObject *object)
+{
+  GtkFileFolderGio *folder = GTK_FILE_FOLDER_GIO (object);
+
+  DEBUG ("folder_finalize");
+
+  g_object_unref (folder->parent_file);
+
+  if (folder->directory_monitor)
+    g_object_unref (folder->directory_monitor);
+
+  g_hash_table_unref (folder->children);
+  G_OBJECT_CLASS (gtk_file_folder_gio_parent_class)->finalize (object);
+}
+
+/* GtkFileFolder implementation methods */
+static GtkFileInfo *
+gtk_file_folder_gio_get_info (GtkFileFolder      *folder,
+			      const GtkFilePath  *path,
+			      GError            **error)
+{
+  GtkFileFolderGio *folder_gio;
+  GFileInfo *file_info;
+
+  DEBUG ("folder_get_info");
+
+  folder_gio = GTK_FILE_FOLDER_GIO (folder);
+  file_info = g_hash_table_lookup (folder_gio->children,
+				   gtk_file_path_get_string (path));
+
+  if (file_info)
+    return translate_file_info (file_info);
+
+  return NULL;
+}
+
+static gboolean
+gtk_file_folder_gio_list_children (GtkFileFolder  *folder,
+				   GSList        **children,
+				   GError        **error)
+{
+  GtkFileFolderGio *folder_gio;
+  GList *list, *elem;
+
+  DEBUG ("list_children");
+
+  folder_gio = GTK_FILE_FOLDER_GIO (folder);
+  list = g_hash_table_get_keys (folder_gio->children);
+
+  for (elem = list; elem; elem = elem->next)
+    *children = g_slist_prepend (*children, gtk_file_path_new_dup (elem->data));
+
+  return TRUE;
+}
+
+static gboolean
+gtk_file_folder_gio_is_finished_loading (GtkFileFolder *folder)
+{
+  GtkFileFolderGio *folder_gio;
+
+  DEBUG ("is_finished_loading");
+  folder_gio = GTK_FILE_FOLDER_GIO (folder);
+
+  return folder_gio->finished_loading;
+}
+
+GtkFileSystem*
+gtk_file_system_gio_new (void)
+{
+  return g_object_new (GTK_TYPE_FILE_SYSTEM_GIO, NULL);
+}
+
+/* GtkFileSystem module methods */
+void
+fs_module_init (GTypeModule *module)
+{
+  /* these are defined by the G_DEFINE_BLAH macros */
+  gtk_file_system_gio_register_type (module);
+  gtk_file_system_handle_gio_register_type (module);
+  gtk_file_folder_gio_register_type (module);
+}
+
+void
+fs_module_exit (void)
+{
+}
+
+GtkFileSystem *
+fs_module_create (void)
+{
+  return gtk_file_system_gio_new ();
+}

Added: trunk/file-chooser/gtkfilesystemgio.h
==============================================================================
--- (empty file)
+++ trunk/file-chooser/gtkfilesystemgio.h	Mon Jan 14 22:33:03 2008
@@ -0,0 +1,45 @@
+/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
+/* Copyright (C) 2007 Carlos Garnacho
+ *
+ * This program 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,
+ * 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: Carlos Garnacho Parro  <carlos imendio com>
+ */
+
+#ifndef __GTK_FILE_SYSTEM_GIO_H__
+#define __GTK_FILE_SYSTEM_GIO_H__
+
+
+#include <glib-object.h>
+#define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
+#include <gtk/gtkfilesystem.h>
+#undef GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
+
+G_BEGIN_DECLS
+
+
+#define GTK_TYPE_FILE_SYSTEM_GIO  (gtk_file_system_gio_get_type ())
+#define GTK_FILE_SYSTEM_GIO(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_FILE_SYSTEM_GIO, GtkFileSystemGio))
+#define GTK_IS_FILE_SYSTEM_GIO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_FILE_SYSTEM_GIO))
+
+typedef struct GtkFileSystemGio GtkFileSystemGio;
+
+GType          gtk_file_system_gio_get_type (void);
+GtkFileSystem *gtk_file_system_gio_new      (void);
+
+
+G_END_DECLS
+
+#endif /* __GTK_FILE_SYSTEM_GIO_H__ */



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