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