summaryrefslogtreecommitdiff
path: root/gtk/gtkfilesystem.c
diff options
context:
space:
mode:
authorCarlos Garnacho <carlos@imendio.com>2008-06-10 00:39:35 +0000
committerCarlos Garnacho <carlosg@src.gnome.org>2008-06-10 00:39:35 +0000
commit640d68778a82ae1c338d1583af49120c7119e3ae (patch)
tree72c424513afd4aeae2885ad037ce2f1cfe203546 /gtk/gtkfilesystem.c
parentd717e77c1dc6a4588154a779062aa385554c8bb9 (diff)
downloadgtk+-640d68778a82ae1c338d1583af49120c7119e3ae.tar.gz
Bug 520874 - Should use gio directly.
2008-06-10 Carlos Garnacho <carlos@imendio.com> Bug 520874 - Should use gio directly. * gtk/gtkfilesystem.[ch]: Turn into a private object, which mostly provides helper functions for asynchronous calls, folder abstraction and uniform handling of volumes/drives/mounts. * gtk/gtkfilesystemwin32.[ch]: * gtk/gtkfilesystemunix.[ch]: Removed, these are no longer required. * gtk/gtkfilechooser.c: * gtk/gtkfilechooserbutton.c: * gtk/gtkfilechooserdefault.c: * gtk/gtkfilechooserentry.[ch]: * gtk/gtkfilechooserprivate.h: * gtk/gtkfilechooserutils.c: * gtk/gtkfilesystemmodel.[ch]: * gtk/gtkpathbar.[ch]: Use GIO internally. Adapt to GtkFileSystem API. Do not load filesystem implementation modules. * gtk/Makefile.am: * gtk/gtk.symbols: the gtkfilesystem.h private header isn't installed anymore, nor the unix/win32 implementations. * README.in: Add blurb about these changes. svn path=/trunk/; revision=20342
Diffstat (limited to 'gtk/gtkfilesystem.c')
-rw-r--r--gtk/gtkfilesystem.c2528
1 files changed, 1447 insertions, 1081 deletions
diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c
index 2f7dff5c0d..095b71229d 100644
--- a/gtk/gtkfilesystem.c
+++ b/gtk/gtkfilesystem.c
@@ -1,48 +1,136 @@
/* GTK - The GIMP Toolkit
- * gtkfilesystem.c: Abstract file system interfaces
+ * gtkfilesystem.c: Filesystem abstraction functions.
* Copyright (C) 2003, Red Hat, Inc.
+ * Copyright (C) 2007-2008 Carlos Garnacho
*
- * 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 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 library is distributed in the hope that it will be useful,
+ * 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
- * Lesser General Public License for more details.
+ * 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 Lesser General Public
- * License along with this library; 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 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 <carlos@imendio.com>
*/
-#include <config.h>
-#include <gmodule.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
#include "gtkfilesystem.h"
-#include "gtkicontheme.h"
-#include "gtkmodules.h"
-#include "gtkintl.h"
-#include "gtkstock.h"
-#include "gtkalias.h"
+#include "gtkprivate.h"
-#include <string.h>
+/* #define DEBUG_MODE */
+#ifdef DEBUG_MODE
+#define DEBUG(x...) g_debug (x);
+#else
+#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
+ * really pointers to GDrive, GVolume or GMount objects. We need an extra
+ * token for the fake "File System" volume. So, we'll return a pointer to
+ * this particular string.
+ */
+static const gchar *root_volume_token = N_("File System");
+#define IS_ROOT_VOLUME(volume) ((gpointer) (volume) == (gpointer) root_volume_token)
+
+enum {
+ PROP_0,
+ PROP_FILE,
+ PROP_ENUMERATOR,
+ PROP_ATTRIBUTES
+};
+
+enum {
+ BOOKMARKS_CHANGED,
+ VOLUMES_CHANGED,
+ FS_LAST_SIGNAL
+};
+
+enum {
+ FILES_ADDED,
+ FILES_REMOVED,
+ FILES_CHANGED,
+ FINISHED_LOADING,
+ DELETED,
+ FOLDER_LAST_SIGNAL
+};
+
+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
+{
+ GVolumeMonitor *volume_monitor;
+
+ /* This list contains elements that can be
+ * of type GDrive, GVolume and GMount
+ */
+ GSList *volumes;
+
+ /* This list contains GtkFileSystemBookmark structs */
+ GSList *bookmarks;
+
+ 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;
+
+ gpointer callback;
+ gpointer data;
+};
-struct _GtkFileInfo
+struct GtkFileSystemBookmark
{
- GtkFileTime modification_time;
- gint64 size;
- gchar *display_name;
- gchar *display_key;
- gchar *mime_type;
- gchar *icon_name;
- guint is_folder : 1;
- guint is_hidden : 1;
+ GFile *file;
+ gchar *label;
};
-static void gtk_file_system_base_init (gpointer g_class);
-static void gtk_file_folder_base_init (gpointer g_class);
+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);
+
GQuark
gtk_file_system_error_quark (void)
@@ -50,1351 +138,1629 @@ gtk_file_system_error_quark (void)
return g_quark_from_static_string ("gtk-file-system-error-quark");
}
-/*****************************************
- * GtkFileInfo *
- *****************************************/
-GType
-gtk_file_info_get_type (void)
+/* GtkFileSystemBookmark methods */
+void
+gtk_file_system_bookmark_free (GtkFileSystemBookmark *bookmark)
{
- static GType our_type = 0;
-
- if (our_type == 0)
- our_type = g_boxed_type_register_static (I_("GtkFileInfo"),
- (GBoxedCopyFunc) gtk_file_info_copy,
- (GBoxedFreeFunc) gtk_file_info_free);
-
- return our_type;
+ g_object_unref (bookmark->file);
+ g_free (bookmark->label);
+ g_slice_free (GtkFileSystemBookmark, bookmark);
}
-GtkFileInfo *
-gtk_file_info_new (void)
+/* GtkFileSystem methods */
+static void
+volumes_changed (GVolumeMonitor *volume_monitor,
+ gpointer volume,
+ gpointer user_data)
{
- GtkFileInfo *info;
-
- info = g_new0 (GtkFileInfo, 1);
+ GtkFileSystem *file_system;
- return info;
-}
+ gdk_threads_enter ();
-GtkFileInfo *
-gtk_file_info_copy (GtkFileInfo *info)
-{
- GtkFileInfo *new_info;
-
- g_return_val_if_fail (info != NULL, NULL);
-
- new_info = g_memdup (info, sizeof (GtkFileInfo));
- if (new_info->display_name)
- new_info->display_name = g_strdup (new_info->display_name);
- if (new_info->display_key)
- new_info->display_key = g_strdup (new_info->display_key);
- if (new_info->mime_type)
- new_info->mime_type = g_strdup (new_info->mime_type);
- if (new_info->icon_name)
- new_info->icon_name = g_strdup (new_info->icon_name);
- if (new_info->display_key)
- new_info->display_key = g_strdup (new_info->display_key);
-
- return new_info;
+ file_system = GTK_FILE_SYSTEM (user_data);
+ g_signal_emit (file_system, fs_signals[VOLUMES_CHANGED], 0, volume);
+ gdk_threads_leave ();
}
-void
-gtk_file_info_free (GtkFileInfo *info)
+static void
+gtk_file_system_dispose (GObject *object)
{
- g_return_if_fail (info != NULL);
+ GtkFileSystemPrivate *priv;
- g_free (info->display_name);
- g_free (info->mime_type);
- g_free (info->display_key);
- g_free (info->icon_name);
-
- g_free (info);
-}
+ DEBUG ("dispose");
-G_CONST_RETURN gchar *
-gtk_file_info_get_display_name (const GtkFileInfo *info)
-{
- g_return_val_if_fail (info != NULL, NULL);
-
- return info->display_name;
-}
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (object);
-/**
- * gtk_file_info_get_display_key:
- * @info: a #GtkFileInfo
- *
- * Returns for the collation key for the display name for @info.
- * This is useful when sorting a bunch of #GtkFileInfo structures
- * since the collate key will be only computed once.
- *
- * Return value: The collate key for the display name, or %NULL
- * if the display name hasn't been set.
- **/
-G_CONST_RETURN gchar *
-gtk_file_info_get_display_key (const GtkFileInfo *info)
-{
- g_return_val_if_fail (info != NULL, NULL);
+ if (priv->volumes)
+ {
+ g_slist_foreach (priv->volumes, (GFunc) g_object_unref, NULL);
+ g_slist_free (priv->volumes);
+ priv->volumes = NULL;
+ }
- if (!info->display_key && info->display_name)
+ if (priv->volume_monitor)
{
- /* Since info->display_key is only a cache, we cast off the const
- */
- ((GtkFileInfo *)info)->display_key = g_utf8_collate_key_for_filename (info->display_name, -1);
+ g_signal_handlers_disconnect_by_func (priv->volume_monitor, volumes_changed, object);
+ g_object_unref (priv->volume_monitor);
+ priv->volume_monitor = NULL;
}
-
- return info->display_key;
+
+ G_OBJECT_CLASS (gtk_file_system_parent_class)->dispose (object);
}
-void
-gtk_file_info_set_display_name (GtkFileInfo *info,
- const gchar *display_name)
+static void
+gtk_file_system_finalize (GObject *object)
{
- g_return_if_fail (info != NULL);
+ GtkFileSystemPrivate *priv;
- if (display_name == info->display_name)
- return;
+ DEBUG ("finalize");
+
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (object);
+
+ if (priv->bookmarks_monitor)
+ g_object_unref (priv->bookmarks_monitor);
- g_free (info->display_name);
- if (info->display_key)
+ if (priv->bookmarks)
{
- g_free (info->display_key);
- info->display_key = NULL;
+ g_slist_foreach (priv->bookmarks, (GFunc) gtk_file_system_bookmark_free, NULL);
+ g_slist_free (priv->bookmarks);
}
- info->display_name = g_strdup (display_name);
+ G_OBJECT_CLASS (gtk_file_system_parent_class)->finalize (object);
}
-gboolean
-gtk_file_info_get_is_folder (const GtkFileInfo *info)
+static void
+gtk_file_system_class_init (GtkFileSystemClass *class)
{
- g_return_val_if_fail (info != NULL, FALSE);
-
- return info->is_folder;
-}
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
-void
-gtk_file_info_set_is_folder (GtkFileInfo *info,
- gboolean is_folder)
-{
- g_return_if_fail (info != NULL);
+ object_class->dispose = gtk_file_system_dispose;
+ object_class->finalize = gtk_file_system_finalize;
- info->is_folder = is_folder != FALSE;
-}
+ fs_signals[BOOKMARKS_CHANGED] =
+ g_signal_new ("bookmarks-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkFileSystemClass, bookmarks_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
-gboolean
-gtk_file_info_get_is_hidden (const GtkFileInfo *info)
-{
- g_return_val_if_fail (info != NULL, FALSE);
-
- return info->is_hidden;
+ fs_signals[VOLUMES_CHANGED] =
+ g_signal_new ("volumes-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkFileSystemClass, volumes_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (object_class, sizeof (GtkFileSystemPrivate));
}
-void
-gtk_file_info_set_is_hidden (GtkFileInfo *info,
- gboolean is_hidden)
+static GFile *
+get_bookmarks_file (void)
{
- g_return_if_fail (info != NULL);
+ GFile *file;
+ gchar *filename;
- info->is_hidden = is_hidden != FALSE;
-}
+ filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
+ file = g_file_new_for_path (filename);
+ g_free (filename);
-G_CONST_RETURN gchar *
-gtk_file_info_get_mime_type (const GtkFileInfo *info)
-{
- g_return_val_if_fail (info != NULL, NULL);
-
- return info->mime_type;
+ return file;
}
-void
-gtk_file_info_set_mime_type (GtkFileInfo *info,
- const gchar *mime_type)
+static GSList *
+read_bookmarks (GFile *file)
{
- g_return_if_fail (info != NULL);
-
- g_free (info->mime_type);
+ gchar *contents;
+ gchar **lines, *space;
+ GSList *bookmarks = NULL;
+ gint i;
- info->mime_type = g_strdup (mime_type);
-}
+ if (!g_file_load_contents (file, NULL, &contents,
+ NULL, NULL, NULL))
+ return NULL;
-GtkFileTime
-gtk_file_info_get_modification_time (const GtkFileInfo *info)
-{
- g_return_val_if_fail (info != NULL, 0);
+ lines = g_strsplit (contents, "\n", -1);
- return info->modification_time;
-}
+ for (i = 0; lines[i]; i++)
+ {
+ GtkFileSystemBookmark *bookmark;
-void
-gtk_file_info_set_modification_time (GtkFileInfo *info,
- GtkFileTime modification_time)
-{
- g_return_if_fail (info != NULL);
-
- info->modification_time = modification_time;
-}
+ if (!*lines[i])
+ continue;
-gint64
-gtk_file_info_get_size (const GtkFileInfo *info)
-{
- g_return_val_if_fail (info != NULL, 0);
-
- return info->size;
-}
+ bookmark = g_slice_new0 (GtkFileSystemBookmark);
-void
-gtk_file_info_set_size (GtkFileInfo *info,
- gint64 size)
-{
- g_return_if_fail (info != NULL);
- g_return_if_fail (size >= 0);
-
- info->size = size;
+ if ((space = strchr (lines[i], ' ')) != NULL)
+ {
+ space[0] = '\0';
+ bookmark->label = g_strdup (space + 1);
+ }
+
+ bookmark->file = g_file_new_for_uri (lines[i]);
+ bookmarks = g_slist_prepend (bookmarks, bookmark);
+ }
+
+ bookmarks = g_slist_reverse (bookmarks);
+ g_strfreev (lines);
+ g_free (contents);
+
+ return bookmarks;
}
-void
-gtk_file_info_set_icon_name (GtkFileInfo *info,
- const gchar *icon_name)
+static void
+save_bookmarks (GFile *bookmarks_file,
+ GSList *bookmarks)
{
- g_return_if_fail (info != NULL);
-
- g_free (info->icon_name);
+ GError *error = NULL;
+ GString *contents;
+
+ contents = g_string_new ("");
+
+ while (bookmarks)
+ {
+ GtkFileSystemBookmark *bookmark;
+ gchar *uri;
+
+ bookmark = bookmarks->data;
+ uri = g_file_get_uri (bookmark->file);
+ g_string_append (contents, uri);
- info->icon_name = g_strdup (icon_name);
+ 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))
+ {
+ g_critical (error->message);
+ g_error_free (error);
+ }
+
+ g_string_free (contents, TRUE);
}
-G_CONST_RETURN gchar *
-gtk_file_info_get_icon_name (const GtkFileInfo *info)
+static void
+bookmarks_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer data)
{
- g_return_val_if_fail (info != NULL, NULL);
-
- return info->icon_name;
+ GtkFileSystemPrivate *priv;
+
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (data);
+
+ switch (event)
+ {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ case G_FILE_MONITOR_EVENT_CREATED:
+ case G_FILE_MONITOR_EVENT_DELETED:
+ g_slist_foreach (priv->bookmarks, (GFunc) gtk_file_system_bookmark_free, NULL);
+ g_slist_free (priv->bookmarks);
+
+ priv->bookmarks = read_bookmarks (file);
+
+ gdk_threads_enter ();
+ g_signal_emit (data, fs_signals[BOOKMARKS_CHANGED], 0);
+ gdk_threads_leave ();
+ break;
+ default:
+ /* ignore at the moment */
+ break;
+ }
}
-GdkPixbuf *
-gtk_file_info_render_icon (const GtkFileInfo *info,
- GtkWidget *widget,
- gint pixel_size,
- GError **error)
+static void
+get_volumes_list (GtkFileSystem *file_system)
{
- GdkPixbuf *pixbuf = NULL;
+ GtkFileSystemPrivate *priv;
+ GList *l, *ll;
+ GList *drives;
+ GList *volumes;
+ GList *mounts;
+ GDrive *drive;
+ GVolume *volume;
+ GMount *mount;
- g_return_val_if_fail (info != NULL, NULL);
- g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
- if (info->icon_name)
+ if (priv->volumes)
{
- if (g_path_is_absolute (info->icon_name))
- pixbuf = gdk_pixbuf_new_from_file_at_size (info->icon_name,
- pixel_size,
- pixel_size,
- NULL);
- else
- {
- GtkIconTheme *icon_theme;
+ g_slist_foreach (priv->volumes, (GFunc) g_object_unref, NULL);
+ g_slist_free (priv->volumes);
+ priv->volumes = NULL;
+ }
+
+ /* first go through all connected drives */
+ drives = g_volume_monitor_get_connected_drives (priv->volume_monitor);
+
+ for (l = drives; l != NULL; l = l->next)
+ {
+ drive = l->data;
+ volumes = g_drive_get_volumes (drive);
- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
- if (gtk_icon_theme_has_icon (icon_theme, info->icon_name))
- pixbuf = gtk_icon_theme_load_icon (icon_theme, info->icon_name,
- pixel_size, 0, NULL);
+ if (volumes)
+ {
+ for (ll = volumes; ll != NULL; ll = ll->next)
+ {
+ volume = ll->data;
+ mount = g_volume_get_mount (volume);
+
+ if (mount)
+ {
+ /* Show mounted volume */
+ priv->volumes = g_slist_prepend (priv->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.
+ */
+ priv->volumes = g_slist_prepend (priv->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.
+ */
+
+ priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (drive));
}
}
- if (!pixbuf)
+ g_list_free (drives);
+
+ /* add all volumes that is not associated with a drive */
+ volumes = g_volume_monitor_get_volumes (priv->volume_monitor);
+
+ for (l = volumes; l != NULL; l = l->next)
{
- /* load a fallback icon */
- pixbuf = gtk_widget_render_icon (widget,
- gtk_file_info_get_is_folder (info)
- ? GTK_STOCK_DIRECTORY : GTK_STOCK_FILE,
- GTK_ICON_SIZE_MENU,
- NULL);
- if (!pixbuf && error)
- g_set_error (error,
- GTK_FILE_SYSTEM_ERROR,
- GTK_FILE_SYSTEM_ERROR_FAILED,
- _("Could not get a stock icon for %s\n"),
- info->icon_name);
+ volume = l->data;
+ drive = g_volume_get_drive (volume);
+
+ if (drive)
+ {
+ g_object_unref (drive);
+ continue;
+ }
+
+ mount = g_volume_get_mount (volume);
+
+ if (mount)
+ {
+ /* show this mount */
+ priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (mount));
+ g_object_unref (mount);
+ }
+ else
+ {
+ /* see comment above in why we add an icon for a volume */
+ priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (volume));
+ }
}
- return pixbuf;
-}
+ g_list_free (volumes);
-/*****************************************
- * GtkFileSystemHandle *
- *****************************************/
+ /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
+ mounts = g_volume_monitor_get_mounts (priv->volume_monitor);
-enum
-{
- PROP_0,
- PROP_CANCELLED
-};
+ for (l = mounts; l != NULL; l = l->next)
+ {
+ mount = l->data;
+ volume = g_mount_get_volume (mount);
+
+ if (volume)
+ {
+ g_object_unref (volume);
+ continue;
+ }
+
+ /* show this mount */
+ priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (mount));
+ }
-G_DEFINE_TYPE (GtkFileSystemHandle, gtk_file_system_handle, G_TYPE_OBJECT)
+ g_list_free (mounts);
+}
static void
-gtk_file_system_handle_init (GtkFileSystemHandle *handle)
+gtk_file_system_init (GtkFileSystem *file_system)
+{
+ GtkFileSystemPrivate *priv;
+ GFile *bookmarks_file;
+ GError *error = NULL;
+
+ DEBUG ("init");
+
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
+
+ /* Volumes */
+ priv->volume_monitor = g_volume_monitor_get ();
+
+ g_signal_connect (priv->volume_monitor, "mount-added",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "mount-removed",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "mount-changed",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "volume-added",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "volume-removed",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "volume-changed",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "drive-connected",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "drive-disconnected",
+ G_CALLBACK (volumes_changed), file_system);
+ g_signal_connect (priv->volume_monitor, "drive-changed",
+ G_CALLBACK (volumes_changed), file_system);
+
+ /* Bookmarks */
+ bookmarks_file = get_bookmarks_file ();
+ priv->bookmarks = read_bookmarks (bookmarks_file);
+ priv->bookmarks_monitor = g_file_monitor_file (bookmarks_file,
+ G_FILE_MONITOR_NONE,
+ NULL, &error);
+ if (error)
+ g_warning (error->message);
+ else
+ g_signal_connect (priv->bookmarks_monitor, "changed",
+ G_CALLBACK (bookmarks_file_changed), file_system);
+
+ g_object_unref (bookmarks_file);
+}
+
+/* GtkFileSystem public methods */
+GtkFileSystem *
+gtk_file_system_new (void)
{
- handle->file_system = NULL;
- handle->cancelled = FALSE;
+ return g_object_new (GTK_TYPE_FILE_SYSTEM, NULL);
}
-static void
-gtk_file_system_handle_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+GSList *
+gtk_file_system_list_volumes (GtkFileSystem *file_system)
{
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ GtkFileSystemPrivate *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));
+
+ list = g_slist_copy (priv->volumes);
+
+ /* Prepend root volume */
+ list = g_slist_prepend (list, (gpointer) root_volume_token);
+
+ return list;
}
-static void
-gtk_file_system_handle_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+GSList *
+gtk_file_system_list_bookmarks (GtkFileSystem *file_system)
{
- GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (object);
+ GtkFileSystemPrivate *priv;
+ GSList *bookmarks, *files = NULL;
- switch (prop_id)
+ DEBUG ("list_bookmarks");
+
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
+ bookmarks = priv->bookmarks;
+
+ while (bookmarks)
{
- case PROP_CANCELLED:
- g_value_set_boolean (value, handle->cancelled);
- break;
+ GtkFileSystemBookmark *bookmark;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ bookmark = bookmarks->data;
+ bookmarks = bookmarks->next;
+
+ files = g_slist_prepend (files, g_object_ref (bookmark->file));
}
-}
-static void
-gtk_file_system_handle_class_init (GtkFileSystemHandleClass *klass)
-{
- GObjectClass *o_class;
-
- o_class = (GObjectClass *)klass;
- o_class->set_property = gtk_file_system_handle_set_property;
- o_class->get_property = gtk_file_system_handle_get_property;
-
- g_object_class_install_property (o_class,
- PROP_CANCELLED,
- g_param_spec_boolean ("cancelled",
- P_("Cancelled"),
- P_("Whether or not the operation has been successfully cancelled"),
- FALSE,
- G_PARAM_READABLE));
+ return g_slist_reverse (files);
}
-/*****************************************
- * GtkFileSystem *
- *****************************************/
-GType
-gtk_file_system_get_type (void)
+gboolean
+gtk_file_system_parse (GtkFileSystem *file_system,
+ GFile *base_file,
+ const gchar *str,
+ GFile **folder,
+ gchar **file_part,
+ GError **error)
{
- static GType file_system_type = 0;
+ 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 (!file_system_type)
+ 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))
{
- const GTypeInfo file_system_info =
- {
- sizeof (GtkFileSystemIface), /* class_size */
- gtk_file_system_base_init, /* base_init */
- NULL, /* base_finalize */
- };
-
- file_system_type = g_type_register_static (G_TYPE_INTERFACE,
- I_("GtkFileSystem"),
- &file_system_info, 0);
-
- g_type_interface_add_prerequisite (file_system_type, G_TYPE_OBJECT);
+ /* 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);
- return file_system_type;
+ 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 = 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
-gtk_file_system_base_init (gpointer g_class)
+free_async_data (AsyncFuncData *async_data)
{
- static gboolean initialized = FALSE;
-
- if (!initialized)
- {
- GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
-
- g_signal_new (I_("volumes-changed"),
- iface_type,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileSystemIface, volumes_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- g_signal_new (I_("bookmarks-changed"),
- iface_type,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileSystemIface, bookmarks_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- initialized = TRUE;
- }
+ g_object_unref (async_data->file_system);
+ 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);
}
-GSList *
-gtk_file_system_list_volumes (GtkFileSystem *file_system)
+static void
+enumerate_children_callback (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ 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);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->list_volumes (file_system);
+ if (error)
+ g_error_free (error);
}
-GtkFileSystemHandle *
+GCancellable *
gtk_file_system_get_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileInfoType types,
+ 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 (path != NULL, NULL);
- g_return_val_if_fail (callback != NULL, NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_folder (file_system, path, types, callback, data);
-}
+ cancellable = g_cancellable_new ();
-GtkFileSystemHandle *
-gtk_file_system_get_info (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileInfoType types,
- GtkFileSystemGetInfoCallback callback,
- gpointer data)
-{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (path != NULL, NULL);
- g_return_val_if_fail (callback != NULL, NULL);
+ 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);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_info (file_system, path, types, callback, data);
+ 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;
}
-GtkFileSystemHandle *
-gtk_file_system_create_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileSystemCreateFolderCallback callback,
- gpointer data)
+static void
+query_info_callback (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (path != NULL, NULL);
- g_return_val_if_fail (callback != NULL, NULL);
+ AsyncFuncData *async_data;
+ GError *error = NULL;
+ GFileInfo *file_info;
+ GFile *file;
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->create_folder (file_system, path, callback, data);
-}
+ DEBUG ("query_info_callback");
-void
-gtk_file_system_cancel_operation (GtkFileSystemHandle *handle)
-{
- g_return_if_fail (GTK_IS_FILE_SYSTEM_HANDLE (handle));
+ file = G_FILE (source_object);
+ async_data = (AsyncFuncData *) user_data;
+ file_info = g_file_query_info_finish (file, result, &error);
- GTK_FILE_SYSTEM_GET_IFACE (handle->file_system)->cancel_operation (handle);
+ if (async_data->callback)
+ {
+ gdk_threads_enter ();
+ ((GtkFileSystemGetInfoCallback) async_data->callback) (async_data->cancellable,
+ file_info, error, async_data->data);
+ gdk_threads_leave ();
+ }
+
+ if (file_info)
+ g_object_unref (file_info);
+
+ if (error)
+ g_error_free (error);
+
+ free_async_data (async_data);
}
-/**
- * gtk_file_system_get_volume_for_path:
- * @file_system: a #GtkFileSystem
- * @path: a #GtkFilePath
- *
- * Queries the file system volume that corresponds to a specific path.
- * There might not be a volume for all paths (consinder for instance remote
- * shared), so this can return NULL.
- *
- * Return value: the #GtkFileSystemVolume that corresponds to the specified
- * @path, or NULL if there is no such volume. You should free this value with
- * gtk_file_system_volume_free().
- **/
-GtkFileSystemVolume *
-gtk_file_system_get_volume_for_path (GtkFileSystem *file_system,
- const GtkFilePath *path)
+GCancellable *
+gtk_file_system_get_info (GtkFileSystem *file_system,
+ GFile *file,
+ const gchar *attributes,
+ GtkFileSystemGetInfoCallback 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 (path != NULL, NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_volume_for_path (file_system, path);
-}
+ cancellable = g_cancellable_new ();
-/**
- * gtk_file_system_volume_free:
- * @file_system: a #GtkFileSystem
- * @volume: a #GtkFileSystemVolume
- *
- * Frees a #GtkFileSystemVolume structure as returned by
- * gtk_file_system_list_volumes().
- **/
-void
-gtk_file_system_volume_free (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume)
-{
- g_return_if_fail (GTK_IS_FILE_SYSTEM (file_system));
- g_return_if_fail (volume != NULL);
+ 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->callback = callback;
+ async_data->data = data;
- GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_free (file_system, volume);
+ g_file_query_info_async (file,
+ attributes,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ query_info_callback,
+ async_data);
+
+ return cancellable;
}
-/**
- * gtk_file_system_volume_get_base_path:
- * @file_system: a #GtkFileSystem
- * @volume: a #GtkFileSystemVolume
- *
- * Queries the base path for a volume. For example, a CD-ROM device may yield a
- * path of "/mnt/cdrom".
- *
- * Return value: a #GtkFilePath with the base mount path of the specified
- * @volume.
- **/
-GtkFilePath *
-gtk_file_system_volume_get_base_path (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume)
+static void
+drive_poll_for_media_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (volume != NULL, NULL);
+ AsyncFuncData *async_data;
+ GError *error = NULL;
+
+ g_drive_poll_for_media_finish (G_DRIVE (source_object), result, &error);
+ async_data = (AsyncFuncData *) user_data;
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_base_path (file_system, volume);
+ gdk_threads_enter ();
+ ((GtkFileSystemVolumeMountCallback) async_data->callback) (async_data->cancellable,
+ (GtkFileSystemVolume *) source_object,
+ error, async_data->data);
+ gdk_threads_leave ();
+
+ if (error)
+ g_error_free (error);
}
-/**
- * gtk_file_system_volume_get_is_mounted:
- * @file_system: a #GtkFileSystem
- * @volume: a #GtkFileSystemVolume
- *
- * Queries whether a #GtkFileSystemVolume is mounted or not. If it is not, it
- * can be mounted with gtk_file_system_volume_mount().
- *
- * Return value: TRUE if the @volume is mounted, FALSE otherwise.
- **/
-gboolean
-gtk_file_system_volume_get_is_mounted (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume)
+static void
+volume_mount_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (volume != NULL, FALSE);
+ AsyncFuncData *async_data;
+ GError *error = NULL;
+
+ g_volume_mount_finish (G_VOLUME (source_object), result, &error);
+ async_data = (AsyncFuncData *) user_data;
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_is_mounted (file_system, volume);
+ gdk_threads_enter ();
+ ((GtkFileSystemVolumeMountCallback) async_data->callback) (async_data->cancellable,
+ (GtkFileSystemVolume *) source_object,
+ error, async_data->data);
+ gdk_threads_leave ();
+
+ if (error)
+ g_error_free (error);
}
-/**
- * gtk_file_system_volume_mount:
- * @file_system: a #GtkFileSystem
- * @volume: a #GtkFileSystemVolume
- * @error: location to store error, or %NULL
- *
- * Tries to mount an unmounted volume. This may cause the "volumes-changed"
- * signal in the @file_system to be emitted.
- *
- * Return value: TRUE if the @volume was mounted successfully, FALSE otherwise.
- **/
-/* FIXME XXX: update documentation above */
-GtkFileSystemHandle *
-gtk_file_system_volume_mount (GtkFileSystem *file_system,
+GCancellable *
+gtk_file_system_mount_volume (GtkFileSystem *file_system,
GtkFileSystemVolume *volume,
+ GMountOperation *mount_operation,
GtkFileSystemVolumeMountCallback callback,
gpointer data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (volume != NULL, NULL);
- g_return_val_if_fail (callback != NULL, NULL);
+ GCancellable *cancellable;
+ AsyncFuncData *async_data;
+ gboolean handled = FALSE;
+
+ DEBUG ("volume_mount");
+
+ cancellable = g_cancellable_new ();
+
+ async_data = g_new0 (AsyncFuncData, 1);
+ async_data->file_system = g_object_ref (file_system);
+ async_data->cancellable = g_object_ref (cancellable);
+
+ async_data->callback = callback;
+ async_data->data = data;
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_mount (file_system, volume, callback, data);
+ if (G_IS_DRIVE (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 (G_DRIVE (volume), cancellable, drive_poll_for_media_cb, async_data);
+ handled = TRUE;
+ }
+ else if (G_IS_VOLUME (volume))
+ {
+ g_volume_mount (G_VOLUME (volume), G_MOUNT_MOUNT_NONE, mount_operation, cancellable, volume_mount_cb, async_data);
+ handled = TRUE;
+ }
+
+ if (!handled)
+ free_async_data (async_data);
+
+ return cancellable;
}
-/**
- * gtk_file_system_volume_get_display_name:
- * @file_system: a #GtkFileSystem
- * @volume: a #GtkFileSystemVolume
- *
- * Queries the human-readable name for a @volume. This string can be displayed
- * in a list of volumes that can be accessed, for example.
- *
- * Return value: A string with the human-readable name for a #GtkFileSystemVolume.
- **/
-char *
-gtk_file_system_volume_get_display_name (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume)
+static void
+enclosing_volume_mount_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (volume != NULL, NULL);
+ GtkFileSystemVolume *volume;
+ AsyncFuncData *async_data;
+ GError *error = NULL;
+
+ async_data = (AsyncFuncData *) user_data;
+ 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));
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_display_name (file_system, volume);
+ gdk_threads_enter ();
+ ((GtkFileSystemVolumeMountCallback) async_data->callback) (async_data->cancellable, volume,
+ error, async_data->data);
+ gdk_threads_leave ();
+
+ if (error)
+ g_error_free (error);
}
-/**
- * gtk_file_system_volume_render_icon:
- * @file_system: a #GtkFileSystem
- * @volume: a #GtkFileSystemVolume
- * @widget: Reference widget to render icons.
- * @pixel_size: Size of the icon.
- * @error: location to store error, or %NULL
- *
- * Renders an icon suitable for a file #GtkFileSystemVolume.
- *
- * Return value: A #GdkPixbuf containing an icon, or NULL if the icon could not
- * be rendered. In the latter case, the @error value will be set as
- * appropriate.
- **/
-GdkPixbuf *
-gtk_file_system_volume_render_icon (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume,
- GtkWidget *widget,
- gint pixel_size,
- GError **error)
+GCancellable *
+gtk_file_system_mount_enclosing_volume (GtkFileSystem *file_system,
+ GFile *file,
+ GMountOperation *mount_operation,
+ GtkFileSystemVolumeMountCallback callback,
+ gpointer data)
{
- gchar *icon_name;
- GdkPixbuf *pixbuf = NULL;
+ GCancellable *cancellable;
+ AsyncFuncData *async_data;
g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (volume != NULL, NULL);
- g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
- g_return_val_if_fail (pixel_size > 0, NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- icon_name = gtk_file_system_volume_get_icon_name (file_system, volume,
- error);
- if (icon_name)
- {
- GtkIconTheme *icon_theme;
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
- if (gtk_icon_theme_has_icon (icon_theme, icon_name))
- pixbuf = gtk_icon_theme_load_icon (icon_theme,
- icon_name, pixel_size, 0, NULL);
- g_free (icon_name);
- }
+ DEBUG ("mount_enclosing_volume");
- if (!pixbuf)
- pixbuf = gtk_widget_render_icon (widget,
- GTK_STOCK_HARDDISK,
- GTK_ICON_SIZE_MENU,
- NULL);
+ cancellable = g_cancellable_new ();
- return pixbuf;
-}
+ 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);
-/**
- * gtk_file_system_volume_get_icon_name:
- * @file_system: a #GtkFileSystem
- * @volume: a #GtkFileSystemVolume
- * @error: location to store error, or %NULL
- *
- * Gets an icon name suitable for a #GtkFileSystemVolume.
- *
- * Return value: An icon name which can be used for rendering an icon for
- * this volume, or %NULL if no icon name could be found. In the latter
- * case, the @error value will be set as appropriate.
- **/
-gchar *
-gtk_file_system_volume_get_icon_name (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume,
- GError **error)
-{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (volume != NULL, NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ async_data->callback = callback;
+ async_data->data = data;
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_icon_name (file_system,
- volume,
- error);
+ g_file_mount_enclosing_volume (file,
+ G_MOUNT_MOUNT_NONE,
+ mount_operation,
+ cancellable,
+ enclosing_volume_mount_cb,
+ async_data);
+ return cancellable;
}
-/**
- * gtk_file_system_get_parent:
- * @file_system: a #GtkFileSystem
- * @path: base path name
- * @parent: location to store parent path name
- * @error: location to store error, or %NULL
- *
- * Gets the name of the parent folder of a path. If the path has no parent, as when
- * you request the parent of a file system root, then @parent will be set to %NULL.
- *
- * Return value: %TRUE if the operation was successful: @parent will be set to
- * the name of the @path's parent, or to %NULL if @path is already a file system
- * root. If the operation fails, this function returns %FALSE, sets @parent to
- * NULL, and sets the @error value if it is specified.
- **/
gboolean
-gtk_file_system_get_parent (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFilePath **parent,
- GError **error)
+gtk_file_system_insert_bookmark (GtkFileSystem *file_system,
+ GFile *file,
+ gint position,
+ GError **error)
{
- gboolean result;
-
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (path != NULL, FALSE);
- g_return_val_if_fail (parent != NULL, FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ GtkFileSystemPrivate *priv;
+ GSList *bookmarks;
+ GtkFileSystemBookmark *bookmark;
+ gboolean result = TRUE;
+ GFile *bookmarks_file;
- *parent = NULL;
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
+ bookmarks = priv->bookmarks;
- result = GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_parent (file_system, path, parent, error);
- g_assert (result || *parent == NULL);
+ while (bookmarks)
+ {
+ bookmark = bookmarks->data;
+ bookmarks = bookmarks->next;
- return result;
-}
+ if (g_file_equal (bookmark->file, file))
+ {
+ /* File is already in bookmarks */
+ result = FALSE;
+ break;
+ }
+ }
-GtkFilePath *
-gtk_file_system_make_path (GtkFileSystem *file_system,
- const GtkFilePath *base_path,
- const gchar *display_name,
- GError **error)
-{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (base_path != NULL, NULL);
- g_return_val_if_fail (display_name != NULL, NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ if (!result)
+ {
+ gchar *uri = g_file_get_uri (file);
+
+ 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;
+ }
+
+ bookmark = g_slice_new0 (GtkFileSystemBookmark);
+ bookmark->file = g_object_ref (file);
+
+ priv->bookmarks = g_slist_insert (priv->bookmarks, bookmark, position);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->make_path (file_system, base_path, display_name, error);
+ bookmarks_file = get_bookmarks_file ();
+ save_bookmarks (bookmarks_file, priv->bookmarks);
+ g_object_unref (bookmarks_file);
+
+ g_signal_emit (file_system, fs_signals[BOOKMARKS_CHANGED], 0);
+
+ return TRUE;
}
-/**
- * gtk_file_system_parse:
- * @file_system: a #GtkFileSystem
- * @base_path: reference folder with respect to which relative
- * paths should be interpreted.
- * @str: the string to parse
- * @folder: location to store folder portion of result, or %NULL
- * @file_part: location to store file portion of result, or %NULL
- * @error: location to store error, or %NULL
- *
- * Given a string entered by a user, parse it (possibly using
- * heuristics) into a folder path and a UTF-8 encoded
- * filename part. (Suitable for passing to gtk_file_system_make_path())
- *
- * Note that the returned filename point may point to a subfolder
- * of the returned folder. Adding a trailing path separator is needed
- * to enforce the interpretation as a folder name.
- *
- * If parsing fails because the syntax of @str is not understood,
- * and error of type GTK_FILE_SYSTEM_ERROR_BAD_FILENAME will
- * be set in @error and %FALSE returned.
- *
- * If parsing fails because a path was encountered that doesn't
- * exist on the filesystem, then an error of type
- * %GTK_FILE_SYSTEM_ERROR_NONEXISTENT will be set in @error
- * and %FALSE returned. (This only applies to parsing relative paths,
- * not to interpretation of @file_part. No check is made as
- * to whether @file_part exists.)
- *
- * Return value: %TRUE if the parsing succeeds, otherwise, %FALSE.
- **/
gboolean
-gtk_file_system_parse (GtkFileSystem *file_system,
- const GtkFilePath *base_path,
- const gchar *str,
- GtkFilePath **folder,
- gchar **file_part,
- GError **error)
+gtk_file_system_remove_bookmark (GtkFileSystem *file_system,
+ GFile *file,
+ GError **error)
{
- GtkFilePath *tmp_folder = NULL;
- gchar *tmp_file_part = NULL;
- gboolean result;
-
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (base_path != NULL, FALSE);
- g_return_val_if_fail (str != NULL, FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- result = GTK_FILE_SYSTEM_GET_IFACE (file_system)->parse (file_system, base_path, str,
- &tmp_folder, &tmp_file_part,
- error);
- g_assert (result || (tmp_folder == NULL && tmp_file_part == NULL));
-
- if (folder)
- *folder = tmp_folder;
- else
- gtk_file_path_free (tmp_folder);
+ GtkFileSystemPrivate *priv;
+ GtkFileSystemBookmark *bookmark;
+ GSList *bookmarks;
+ gboolean result = FALSE;
+ GFile *bookmarks_file;
- if (file_part)
- *file_part = tmp_file_part;
- else
- g_free (tmp_file_part);
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
- return result;
-}
+ if (!priv->bookmarks)
+ return FALSE;
+ bookmarks = priv->bookmarks;
-gchar *
-gtk_file_system_path_to_uri (GtkFileSystem *file_system,
- const GtkFilePath *path)
-{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (path != NULL, NULL);
-
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->path_to_uri (file_system, path);
+ while (bookmarks)
+ {
+ bookmark = bookmarks->data;
+
+ if (g_file_equal (bookmark->file, file))
+ {
+ result = TRUE;
+ priv->bookmarks = g_slist_remove_link (priv->bookmarks, bookmarks);
+ gtk_file_system_bookmark_free (bookmark);
+ g_slist_free_1 (bookmarks);
+ break;
+ }
+
+ bookmarks = bookmarks->next;
+ }
+
+ if (!result)
+ {
+ gchar *uri = g_file_get_uri (file);
+
+ g_set_error (error,
+ GTK_FILE_SYSTEM_ERROR,
+ GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
+ "%s does not exist in the bookmarks list",
+ uri);
+
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ bookmarks_file = get_bookmarks_file ();
+ save_bookmarks (bookmarks_file, priv->bookmarks);
+ g_object_unref (bookmarks_file);
+
+ g_signal_emit (file_system, fs_signals[BOOKMARKS_CHANGED], 0);
+
+ return TRUE;
}
gchar *
-gtk_file_system_path_to_filename (GtkFileSystem *file_system,
- const GtkFilePath *path)
+gtk_file_system_get_bookmark_label (GtkFileSystem *file_system,
+ GFile *file)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (path != NULL, NULL);
-
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->path_to_filename (file_system, path);
-}
+ GtkFileSystemPrivate *priv;
+ GSList *bookmarks;
+ gchar *label = NULL;
-GtkFilePath *
-gtk_file_system_uri_to_path (GtkFileSystem *file_system,
- const gchar *uri)
-{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (uri != NULL, NULL);
-
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->uri_to_path (file_system, uri);
-}
+ DEBUG ("get_bookmark_label");
-GtkFilePath *
-gtk_file_system_filename_to_path (GtkFileSystem *file_system,
- const gchar *filename)
-{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (filename != NULL, NULL);
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
+ bookmarks = priv->bookmarks;
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->filename_to_path (file_system, filename);
-}
+ while (bookmarks)
+ {
+ GtkFileSystemBookmark *bookmark;
-/**
- * gtk_file_system_path_is_local:
- * @filesystem: a #GtkFileSystem
- * @path: A #GtkFilePath from that filesystem
- *
- * Checks whether a #GtkFilePath is local; that is whether
- * gtk_file_system_path_to_filename would return non-%NULL.
- *
- * Return value: %TRUE if the path is loca
- **/
-gboolean
-gtk_file_system_path_is_local (GtkFileSystem *file_system,
- const GtkFilePath *path)
-{
- gchar *filename;
- gboolean result;
-
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (path != NULL, FALSE);
+ bookmark = bookmarks->data;
+ bookmarks = bookmarks->next;
- filename = gtk_file_system_path_to_filename (file_system, path);
- result = filename != NULL;
- g_free (filename);
+ if (g_file_equal (file, bookmark->file))
+ {
+ label = g_strdup (bookmark->label);
+ break;
+ }
+ }
- return result;
+ return label;
}
-/**
- * gtk_file_system_insert_bookmark:
- * @file_system: a #GtkFileSystem
- * @path: path of the bookmark to add
- * @position: index in the bookmarks list at which the @path should be inserted; use 0
- * for the beginning, and -1 or the number of bookmarks itself for the end of the list.
- * @error: location to store error, or %NULL
- *
- * Adds a path for a folder to the user's bookmarks list. If the operation
- * succeeds, the "bookmarks_changed" signal will be emitted. Bookmark paths are
- * unique; if you try to insert a @path that already exists, the operation will
- * fail and the @error will be set to #GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS. To
- * reorder the list of bookmarks, use gtk_file_system_remove_bookmark() to
- * remove the path in question, and call gtk_file_system_insert_bookmark() with
- * the new position for the path.
- *
- * Return value: TRUE if the operation succeeds, FALSE otherwise. In the latter case,
- * the @error value will be set.
- **/
-gboolean
-gtk_file_system_insert_bookmark (GtkFileSystem *file_system,
- const GtkFilePath *path,
- gint position,
- GError **error)
+void
+gtk_file_system_set_bookmark_label (GtkFileSystem *file_system,
+ GFile *file,
+ const gchar *label)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (path != NULL, FALSE);
+ GtkFileSystemPrivate *priv;
+ gboolean changed = FALSE;
+ GFile *bookmarks_file;
+ GSList *bookmarks;
+
+ DEBUG ("set_bookmark_label");
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->insert_bookmark (file_system, path, position, error);
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
+ bookmarks = priv->bookmarks;
+
+ while (bookmarks)
+ {
+ GtkFileSystemBookmark *bookmark;
+
+ bookmark = bookmarks->data;
+ bookmarks = bookmarks->next;
+
+ if (g_file_equal (file, bookmark->file))
+ {
+ g_free (bookmark->file);
+ bookmark->label = g_strdup (label);
+ changed = TRUE;
+ break;
+ }
+ }
+
+ bookmarks_file = get_bookmarks_file ();
+ save_bookmarks (bookmarks_file, priv->bookmarks);
+ g_object_unref (bookmarks_file);
+
+ if (changed)
+ g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
}
-/**
- * gtk_file_system_remove_bookmark:
- * @file_system: a #GtkFileSystem
- * @path: path of the bookmark to remove
- * @error: location to store error, or %NULL
- *
- * Removes a bookmark folder from the user's bookmarks list. If the operation
- * succeeds, the "bookmarks_changed" signal will be emitted. If you try to remove
- * a @path which does not exist in the bookmarks list, the operation will fail
- * and the @error will be set to GTK_FILE_SYSTEM_ERROR_NONEXISTENT.
- *
- * Return value: TRUE if the operation succeeds, FALSE otherwise. In the latter
- * case, the @error value will be set.
- **/
-gboolean
-gtk_file_system_remove_bookmark (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error)
+GtkFileSystemVolume *
+gtk_file_system_get_volume_for_file (GtkFileSystem *file_system,
+ GFile *file)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (path != NULL, FALSE);
+ GtkFileSystemPrivate *priv;
+ GMount *mount;
+
+ DEBUG ("get_volume_for_file");
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->remove_bookmark (file_system, path, error);
+ priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
+ mount = g_file_find_enclosing_mount (file, NULL, NULL);
+
+ if (!mount && g_file_is_native (file))
+ return (GtkFileSystemVolume *) root_volume_token;
+
+ return (GtkFileSystemVolume *) mount;
}
-/**
- * gtk_file_system_list_bookmarks:
- * @file_system: a #GtkFileSystem
- *
- * Queries the list of bookmarks in the file system.
- *
- * Return value: A list of #GtkFilePath, or NULL if there are no configured
- * bookmarks. You should use gtk_file_paths_free() to free this list.
- *
- * See also: gtk_file_system_get_supports_bookmarks()
- **/
-GSList *
-gtk_file_system_list_bookmarks (GtkFileSystem *file_system)
+/* GtkFolder methods */
+static void
+gtk_folder_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ GtkFolderPrivate *priv;
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->list_bookmarks (file_system);
+ 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;
+ }
}
-/**
- * gtk_file_system_get_bookmark_label:
- * @file_system: a #GtkFileSystem
- * @path: path of the bookmark
- *
- * Gets the label to display for a bookmark, or %NULL.
- *
- * Returns: the label for the bookmark @path
- *
- * Since: 2.8
- */
-gchar *
-gtk_file_system_get_bookmark_label (GtkFileSystem *file_system,
- const GtkFilePath *path)
+static void
+gtk_folder_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GtkFileSystemIface *iface;
-
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (path != NULL, NULL);
+ GtkFolderPrivate *priv;
- iface = GTK_FILE_SYSTEM_GET_IFACE (file_system);
- if (iface->get_bookmark_label)
- return iface->get_bookmark_label (file_system, path);
+ priv = GTK_FOLDER_GET_PRIVATE (object);
- return NULL;
+ 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;
+ }
}
-/**
- * gtk_file_system_set_bookmark_label:
- * @file_system: a #GtkFileSystem
- * @path: path of the bookmark
- * @label: the label for the bookmark, or %NULL to display
- * the path itself
- *
- * Sets the label to display for a bookmark.
- *
- * Since: 2.8
- */
-void
-gtk_file_system_set_bookmark_label (GtkFileSystem *file_system,
- const GtkFilePath *path,
- const gchar *label)
+static void
+query_created_file_info_callback (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GtkFileSystemIface *iface;
+ GFile *file = G_FILE (source_object);
+ GError *error = NULL;
+ GFileInfo *info;
+ GtkFolder *folder;
+ GSList *files;
+
+ info = g_file_query_info_finish (file, result, &error);
- g_return_if_fail (GTK_IS_FILE_SYSTEM (file_system));
- g_return_if_fail (path != NULL);
+ if (error)
+ {
+ g_error_free (error);
+ return;
+ }
- iface = GTK_FILE_SYSTEM_GET_IFACE (file_system);
- if (iface->set_bookmark_label)
- iface->set_bookmark_label (file_system, path, label);
+ 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);
}
-/*****************************************
- * GtkFileFolder *
- *****************************************/
-GType
-gtk_file_folder_get_type (void)
+static void
+directory_monitor_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer data)
{
- static GType file_folder_type = 0;
+ GtkFolderPrivate *priv;
+ GtkFolder *folder;
+ GSList *files;
- if (!file_folder_type)
+ folder = GTK_FOLDER (data);
+ priv = GTK_FOLDER_GET_PRIVATE (folder);
+ files = g_slist_prepend (NULL, file);
+
+ gdk_threads_enter ();
+
+ switch (event)
{
- const GTypeInfo file_folder_info =
- {
- sizeof (GtkFileFolderIface), /* class_size */
- gtk_file_folder_base_init, /* base_init */
- NULL, /* base_finalize */
- };
-
- file_folder_type = g_type_register_static (G_TYPE_INTERFACE,
- I_("GtkFileFolder"),
- &file_folder_info, 0);
-
- g_type_interface_add_prerequisite (file_folder_type, G_TYPE_OBJECT);
+ 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;
}
- return file_folder_type;
+ gdk_threads_leave ();
+
+ g_slist_free (files);
}
static void
-gtk_file_folder_base_init (gpointer g_class)
+enumerator_files_callback (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- static gboolean initialized = FALSE;
-
- if (!initialized)
+ 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)
{
- GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
-
- g_signal_new (I_("deleted"),
- iface_type,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileFolderIface, deleted),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- g_signal_new (I_("files-added"),
- iface_type,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileFolderIface, files_added),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
- g_signal_new (I_("files-changed"),
- iface_type,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileFolderIface, files_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
- g_signal_new (I_("files-removed"),
- iface_type,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileFolderIface, files_removed),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
- g_signal_new (I_("finished-loading"),
- iface_type,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileFolderIface, finished_loading),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- initialized = TRUE;
+ 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);
}
-gboolean
-gtk_file_folder_list_children (GtkFileFolder *folder,
- GSList **children,
- GError **error)
+static void
+gtk_folder_constructed (GObject *object)
{
- gboolean result;
- GSList *tmp_children = NULL;
-
- g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ GtkFolderPrivate *priv;
+ GError *error = NULL;
- result = GTK_FILE_FOLDER_GET_IFACE (folder)->list_children (folder, &tmp_children, error);
- g_assert (result || tmp_children == NULL);
+ priv = GTK_FOLDER_GET_PRIVATE (object);
+ priv->directory_monitor = g_file_monitor_directory (priv->folder_file, G_FILE_MONITOR_NONE, NULL, &error);
- if (children)
- *children = tmp_children;
+ if (error)
+ g_warning (error->message);
else
- gtk_file_paths_free (tmp_children);
+ g_signal_connect (priv->directory_monitor, "changed",
+ G_CALLBACK (directory_monitor_changed), object);
- return result;
+ 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;
}
-GtkFileInfo *
-gtk_file_folder_get_info (GtkFileFolder *folder,
- const GtkFilePath *path,
- GError **error)
+static void
+gtk_folder_finalize (GObject *object)
{
- g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ GtkFolderPrivate *priv;
- return GTK_FILE_FOLDER_GET_IFACE (folder)->get_info (folder, path, error);
-}
+ priv = GTK_FOLDER_GET_PRIVATE (object);
-gboolean
-gtk_file_folder_is_finished_loading (GtkFileFolder *folder)
-{
- GtkFileFolderIface *iface;
+ g_hash_table_unref (priv->children);
- g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), TRUE);
+ if (priv->folder_file)
+ g_object_unref (priv->folder_file);
- iface = GTK_FILE_FOLDER_GET_IFACE (folder);
- if (!iface->is_finished_loading)
- return TRUE;
- else
- return iface->is_finished_loading (folder);
-}
+ if (priv->directory_monitor)
+ g_object_unref (priv->directory_monitor);
+ g_cancellable_cancel (priv->cancellable);
+ g_object_unref (priv->cancellable);
+ g_free (priv->attributes);
-/*****************************************
- * GtkFilePath modules *
- *****************************************/
+ G_OBJECT_CLASS (gtk_folder_parent_class)->finalize (object);
+}
-/* We make these real functions in case either copy or free are implemented as macros
- */
-static gpointer
-gtk_file_path_real_copy (gpointer boxed)
-{
- return gtk_file_path_copy ((GtkFilePath *) boxed);
+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_file_path_real_free (gpointer boxed)
+gtk_folder_init (GtkFolder *folder)
{
- gtk_file_path_free (boxed);
+ 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 ();
}
-GType
-gtk_file_path_get_type (void)
+static void
+_gtk_folder_set_finished_loading (GtkFolder *folder,
+ gboolean finished_loading)
{
- static GType our_type = 0;
-
- if (our_type == 0)
- our_type = g_boxed_type_register_static (I_("GtkFilePath"),
- (GBoxedCopyFunc) gtk_file_path_real_copy,
- (GBoxedFreeFunc) gtk_file_path_real_free);
-
- return our_type;
-}
+ GtkFolderPrivate *priv;
+ priv = GTK_FOLDER_GET_PRIVATE (folder);
+ priv->finished_loading = (finished_loading == TRUE);
-GSList *
-gtk_file_paths_sort (GSList *paths)
-{
-#ifndef G_OS_WIN32
- return g_slist_sort (paths, (GCompareFunc)strcmp);
-#else
- return g_slist_sort (paths, (GCompareFunc)_gtk_file_system_win32_path_compare);
-#endif
+ gdk_threads_enter ();
+ g_signal_emit (folder, folder_signals[FINISHED_LOADING], 0);
+ gdk_threads_leave ();
}
-/**
- * gtk_file_paths_copy:
- * @paths: A #GSList of #GtkFilePath structures.
- *
- * Copies a list of #GtkFilePath structures.
- *
- * Return value: A copy of @paths. Since the contents of the list are copied as
- * well, you should use gtk_file_paths_free() to free the result.
- **/
-GSList *
-gtk_file_paths_copy (GSList *paths)
+static void
+_gtk_folder_add_file (GtkFolder *folder,
+ GFile *file,
+ GFileInfo *info)
{
- GSList *head, *tail, *l;
+ GtkFolderPrivate *priv;
- head = tail = NULL;
+ priv = GTK_FOLDER_GET_PRIVATE (folder);
- for (l = paths; l; l = l->next)
- {
- GtkFilePath *path;
- GSList *node;
+ g_hash_table_insert (priv->children,
+ g_object_ref (file),
+ g_object_ref (info));
+}
- path = l->data;
- node = g_slist_alloc ();
+GSList *
+gtk_folder_list_children (GtkFolder *folder)
+{
+ GtkFolderPrivate *priv;
+ GList *files, *elem;
+ GSList *children = NULL;
- if (tail)
- tail->next = node;
- else
- head = node;
+ priv = GTK_FOLDER_GET_PRIVATE (folder);
+ files = g_hash_table_get_keys (priv->children);
+ children = NULL;
- node->data = gtk_file_path_copy (path);
- tail = node;
- }
+ for (elem = files; elem; elem = elem->next)
+ children = g_slist_prepend (children, g_object_ref (elem->data));
+
+ g_list_free (files);
- return head;
+ return children;
}
-void
-gtk_file_paths_free (GSList *paths)
+GFileInfo *
+gtk_folder_get_info (GtkFolder *folder,
+ GFile *file)
{
- GSList *tmp_list;
+ GtkFolderPrivate *priv;
+ GFileInfo *info;
+
+ priv = GTK_FOLDER_GET_PRIVATE (folder);
+ info = g_hash_table_lookup (priv->children, file);
- for (tmp_list = paths; tmp_list; tmp_list = tmp_list->next)
- gtk_file_path_free (tmp_list->data);
+ if (!info)
+ return NULL;
- g_slist_free (paths);
+ return g_object_ref (info);
}
-/*****************************************
- * GtkFileSystem modules *
- *****************************************/
+gboolean
+gtk_folder_is_finished_loading (GtkFolder *folder)
+{
+ GtkFolderPrivate *priv;
-typedef struct _GtkFileSystemModule GtkFileSystemModule;
-typedef struct _GtkFileSystemModuleClass GtkFileSystemModuleClass;
+ priv = GTK_FOLDER_GET_PRIVATE (folder);
+
+ return priv->finished_loading;
+}
-struct _GtkFileSystemModule
+/* GtkFileSystemVolume public methods */
+gchar *
+gtk_file_system_volume_get_display_name (GtkFileSystemVolume *volume)
{
- GTypeModule parent_instance;
-
- GModule *library;
+ DEBUG ("volume_get_display_name");
- void (*init) (GTypeModule *module);
- void (*exit) (void);
- GtkFileSystem * (*create) (void);
+ if (IS_ROOT_VOLUME (volume))
+ return g_strdup (_(root_volume_token));
+ if (G_IS_DRIVE (volume))
+ return g_drive_get_name (G_DRIVE (volume));
+ else if (G_IS_MOUNT (volume))
+ return g_mount_get_name (G_MOUNT (volume));
+ else if (G_IS_VOLUME (volume))
+ return g_volume_get_name (G_VOLUME (volume));
- gchar *path;
-};
+ return NULL;
+}
-struct _GtkFileSystemModuleClass
+gboolean
+gtk_file_system_volume_is_mounted (GtkFileSystemVolume *volume)
{
- GTypeModuleClass parent_class;
-};
+ gboolean mounted;
-G_DEFINE_TYPE (GtkFileSystemModule, _gtk_file_system_module, G_TYPE_TYPE_MODULE)
-#define GTK_TYPE_FILE_SYSTEM_MODULE (_gtk_file_system_module_get_type ())
-#define GTK_FILE_SYSTEM_MODULE(module) (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_FILE_SYSTEM_MODULE, GtkFileSystemModule))
+ DEBUG ("volume_is_mounted");
+ if (IS_ROOT_VOLUME (volume))
+ return TRUE;
-static GSList *loaded_file_systems;
+ mounted = FALSE;
-static gboolean
-gtk_file_system_module_load (GTypeModule *module)
-{
- GtkFileSystemModule *fs_module = GTK_FILE_SYSTEM_MODULE (module);
-
- fs_module->library = g_module_open (fs_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
- if (!fs_module->library)
- {
- g_warning (g_module_error());
- return FALSE;
- }
-
- /* extract symbols from the lib */
- if (!g_module_symbol (fs_module->library, "fs_module_init",
- (gpointer *)&fs_module->init) ||
- !g_module_symbol (fs_module->library, "fs_module_exit",
- (gpointer *)&fs_module->exit) ||
- !g_module_symbol (fs_module->library, "fs_module_create",
- (gpointer *)&fs_module->create))
+ if (G_IS_MOUNT (volume))
+ mounted = TRUE;
+ else if (G_IS_VOLUME (volume))
{
- g_warning (g_module_error());
- g_module_close (fs_module->library);
-
- return FALSE;
+ GMount *mount;
+
+ mount = g_volume_get_mount (G_VOLUME (volume));
+
+ if (mount)
+ {
+ mounted = TRUE;
+ g_object_unref (mount);
+ }
}
-
- /* call the filesystems's init function to let it */
- /* setup anything it needs to set up. */
- fs_module->init (module);
- return TRUE;
+ return mounted;
}
-static void
-gtk_file_system_module_unload (GTypeModule *module)
+GFile *
+gtk_file_system_volume_get_root (GtkFileSystemVolume *volume)
{
- GtkFileSystemModule *fs_module = GTK_FILE_SYSTEM_MODULE (module);
-
- fs_module->exit();
+ GFile *file = NULL;
- g_module_close (fs_module->library);
- fs_module->library = NULL;
+ DEBUG ("volume_get_base");
- fs_module->init = NULL;
- fs_module->exit = NULL;
- fs_module->create = NULL;
-}
+ if (IS_ROOT_VOLUME (volume))
+ return g_file_new_for_uri ("file:///");
-/* This only will ever be called if an error occurs during
- * initialization
- */
-static void
-gtk_file_system_module_finalize (GObject *object)
-{
- GtkFileSystemModule *module = GTK_FILE_SYSTEM_MODULE (object);
+ if (G_IS_MOUNT (volume))
+ file = g_mount_get_root (G_MOUNT (volume));
+ else if (G_IS_VOLUME (volume))
+ {
+ GMount *mount;
- g_free (module->path);
+ mount = g_volume_get_mount (G_VOLUME (volume));
- G_OBJECT_CLASS (_gtk_file_system_module_parent_class)->finalize (object);
+ if (mount)
+ {
+ file = g_mount_get_root (mount);
+ g_object_unref (mount);
+ }
+ }
+
+ return file;
}
-static void
-_gtk_file_system_module_class_init (GtkFileSystemModuleClass *class)
+static GdkPixbuf *
+get_pixbuf_from_gicon (GIcon *icon,
+ GtkWidget *widget,
+ gint icon_size,
+ GError **error)
{
- GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
- GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-
- module_class->load = gtk_file_system_module_load;
- module_class->unload = gtk_file_system_module_unload;
+ GdkScreen *screen;
+ GtkIconTheme *icon_theme;
+ GtkIconInfo *icon_info;
+ GdkPixbuf *pixbuf;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (widget));
+ icon_theme = gtk_icon_theme_get_for_screen (screen);
+
+ icon_info = gtk_icon_theme_lookup_by_gicon (icon_theme,
+ icon,
+ icon_size,
+ 0);
+
+ if (!icon_info)
+ return NULL;
+
+ pixbuf = gtk_icon_info_load_icon (icon_info, error);
+ gtk_icon_info_free (icon_info);
- gobject_class->finalize = gtk_file_system_module_finalize;
+ return pixbuf;
}
-static void
-_gtk_file_system_module_init (GtkFileSystemModule *fs_module)
+static GIcon *
+get_icon_for_special_directory (GFile *file)
{
-}
+ const gchar *special_dir;
+ GFile *special_file;
+ special_dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
+ special_file = g_file_new_for_path (special_dir);
-static GtkFileSystem *
-_gtk_file_system_module_create (GtkFileSystemModule *fs_module)
-{
- GtkFileSystem *fs;
-
- if (g_type_module_use (G_TYPE_MODULE (fs_module)))
+ if (g_file_equal (file, special_file))
+ {
+ g_object_unref (special_file);
+ return g_themed_icon_new ("gnome-fs-desktop");
+ }
+
+ g_object_unref (special_file);
+ special_dir = g_get_home_dir ();
+ special_file = g_file_new_for_path (special_dir);
+
+ if (g_file_equal (file, special_file))
{
- fs = fs_module->create ();
- g_type_module_unuse (G_TYPE_MODULE (fs_module));
- return fs;
+ g_object_unref (special_file);
+ return g_themed_icon_new ("gnome-fs-home");
}
+
+ g_object_unref (special_file);
+
return NULL;
}
-
-GtkFileSystem *
-gtk_file_system_create (const char *file_system_name)
+GdkPixbuf *
+gtk_file_system_volume_render_icon (GtkFileSystemVolume *volume,
+ GtkWidget *widget,
+ gint icon_size,
+ GError **error)
{
- GSList *l;
- char *module_path;
- GtkFileSystemModule *fs_module;
- GtkFileSystem *fs;
+ GIcon *icon = NULL;
- for (l = loaded_file_systems; l != NULL; l = l->next)
+ DEBUG ("volume_get_icon_name");
+
+ if (IS_ROOT_VOLUME (volume))
+ icon = g_themed_icon_new ("gnome-dev-harddisk");
+ else if (G_IS_DRIVE (volume))
+ icon = g_drive_get_icon (G_DRIVE (volume));
+ else if (G_IS_VOLUME (volume))
+ icon = g_volume_get_icon (G_VOLUME (volume));
+ else if (G_IS_MOUNT (volume))
{
- fs_module = l->data;
-
- if (strcmp (G_TYPE_MODULE (fs_module)->name, file_system_name) == 0)
- return _gtk_file_system_module_create (fs_module);
+ GMount *mount = G_MOUNT (volume);
+ GFile *file;
+
+ file = g_mount_get_root (mount);
+ icon = get_icon_for_special_directory (file);
+
+ if (!icon)
+ icon = g_mount_get_icon (mount);
}
- fs = NULL;
- if (g_module_supported ())
- {
- module_path = _gtk_find_module (file_system_name, "filesystems");
+ if (!icon)
+ return NULL;
- if (module_path)
- {
- fs_module = g_object_new (GTK_TYPE_FILE_SYSTEM_MODULE, NULL);
+ return get_pixbuf_from_gicon (icon, widget, icon_size, error);
+}
- g_type_module_set_name (G_TYPE_MODULE (fs_module), file_system_name);
- fs_module->path = g_strdup (module_path);
+void
+gtk_file_system_volume_free (GtkFileSystemVolume *volume)
+{
+ /* Root volume doesn't need to be freed */
+ if (IS_ROOT_VOLUME (volume))
+ return;
- loaded_file_systems = g_slist_prepend (loaded_file_systems,
- fs_module);
+ if (G_IS_MOUNT (volume) ||
+ G_IS_VOLUME (volume) ||
+ G_IS_DRIVE (volume))
+ g_object_unref (volume);
+}
- fs = _gtk_file_system_module_create (fs_module);
- }
-
- g_free (module_path);
+/* GFileInfo helper functions */
+GdkPixbuf *
+gtk_file_info_render_icon (GFileInfo *info,
+ GtkWidget *widget,
+ gint icon_size)
+{
+ GIcon *icon;
+ GdkPixbuf *pixbuf = NULL;
+ gchar *thumbnail_path;
+
+ thumbnail_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
+
+ if (thumbnail_path)
+ pixbuf = gdk_pixbuf_new_from_file_at_size (thumbnail_path,
+ icon_size, icon_size,
+ NULL);
+
+ if (!pixbuf)
+ {
+ icon = g_file_info_get_icon (info);
+
+ if (icon)
+ pixbuf = get_pixbuf_from_gicon (icon, widget, icon_size, NULL);
}
-
- return fs;
-}
-#define __GTK_FILE_SYSTEM_C__
-#include "gtkaliasdef.c"
+ return pixbuf;
+}