diff options
Diffstat (limited to 'libnautilus-private/nautilus-directory-async.c')
-rw-r--r-- | libnautilus-private/nautilus-directory-async.c | 2317 |
1 files changed, 1467 insertions, 850 deletions
diff --git a/libnautilus-private/nautilus-directory-async.c b/libnautilus-private/nautilus-directory-async.c index 49757cf59..5877b321d 100644 --- a/libnautilus-private/nautilus-directory-async.c +++ b/libnautilus-private/nautilus-directory-async.c @@ -30,6 +30,7 @@ #include "nautilus-file-attributes.h" #include "nautilus-file-private.h" #include "nautilus-file-utilities.h" +#include "nautilus-signaller.h" #include "nautilus-global-preferences.h" #include "nautilus-link.h" #include "nautilus-marshal.h" @@ -37,10 +38,6 @@ #include <eel/eel-glib-extensions.h> #include <eel/eel-string.h> #include <gtk/gtkmain.h> -#include <libgnomevfs/gnome-vfs-ops.h> -#include <libgnomevfs/gnome-vfs-utils.h> -#include <libgnomevfs/gnome-vfs-mime-monitor.h> -#include <libgnomevfs/gnome-vfs-volume-monitor.h> #include <libxml/parser.h> #include <stdio.h> #include <stdlib.h> @@ -60,23 +57,76 @@ #define DEBUG_START_STOP #endif - #define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100 /* Keep async. jobs down to this number for all directories. */ #define MAX_ASYNC_JOBS 10 struct TopLeftTextReadState { - gboolean large; + NautilusDirectory *directory; NautilusFile *file; - EelReadFileHandle *handle; + gboolean large; + GCancellable *cancellable; }; struct LinkInfoReadState { + NautilusDirectory *directory; + GCancellable *cancellable; + NautilusFile *file; +}; + +struct ThumbnailState { + NautilusDirectory *directory; + GCancellable *cancellable; NautilusFile *file; - EelReadFileHandle *handle; + gboolean trying_original; + gboolean tried_original; +}; + +struct DirectoryLoadState { + NautilusDirectory *directory; + GCancellable *cancellable; + GFileEnumerator *enumerator; + GHashTable *load_mime_list_hash; + NautilusFile *load_directory_file; + int load_file_count; +}; + +struct MimeListState { + NautilusDirectory *directory; + GCancellable *cancellable; + GFileEnumerator *enumerator; + GHashTable *mime_list_hash; +}; + +struct GetInfoState { + NautilusDirectory *directory; + GCancellable *cancellable; +}; + +struct NewFilesState { + NautilusDirectory *directory; + GCancellable *cancellable; + int count; }; +struct DirectoryCountState { + NautilusDirectory *directory; + GCancellable *cancellable; + GFileEnumerator *enumerator; + int file_count; +}; + +struct DeepCountState { + NautilusDirectory *directory; + GCancellable *cancellable; + GFileEnumerator *enumerator; + GFile *deep_count_location; + GList *deep_count_subdirectories; +}; + + + typedef struct { NautilusFile *file; /* Which file, NULL means all. */ union { @@ -121,25 +171,23 @@ static GHashTable *async_jobs; static char *kde_trash_dir_name = NULL; /* Forward declarations for functions that need them. */ -static void deep_count_load (NautilusDirectory *directory, - const char *uri); -static gboolean request_is_satisfied (NautilusDirectory *directory, - NautilusFile *file, - Request *request); -static void cancel_loading_attributes (NautilusDirectory *directory, - NautilusFileAttributes file_attributes); -static void add_all_files_to_work_queue (NautilusDirectory *directory); -static void link_info_done (NautilusDirectory *directory, - NautilusFile *file, - const char *uri, - const char *name, - const char *icon, - gulong drive_id, - gulong volume_id); -static void move_file_to_low_priority_queue (NautilusDirectory *directory, - NautilusFile *file); -static void move_file_to_extension_queue (NautilusDirectory *directory, - NautilusFile *file); +static void deep_count_load (DeepCountState *state, + GFile *location); +static gboolean request_is_satisfied (NautilusDirectory *directory, + NautilusFile *file, + Request *request); +static void cancel_loading_attributes (NautilusDirectory *directory, + NautilusFileAttributes file_attributes); +static void add_all_files_to_work_queue (NautilusDirectory *directory); +static void link_info_done (NautilusDirectory *directory, + NautilusFile *file, + const char *uri, + const char *name, + const char *icon); +static void move_file_to_low_priority_queue (NautilusDirectory *directory, + NautilusFile *file); +static void move_file_to_extension_queue (NautilusDirectory *directory, + NautilusFile *file); static void nautilus_directory_invalidate_file_attributes (NautilusDirectory *directory, NautilusFileAttributes file_attributes); @@ -227,7 +275,7 @@ async_job_start (NautilusDirectory *directory, #endif #ifdef DEBUG_START_STOP - g_message ("starting %s in %s", job, directory->details->uri); + g_message ("starting %s in %p", job, directory->details->location); #endif g_assert (async_job_count >= 0); @@ -248,18 +296,22 @@ async_job_start (NautilusDirectory *directory, } #ifdef DEBUG_ASYNC_JOBS - if (async_jobs == NULL) { - async_jobs = eel_g_hash_table_new_free_at_exit - (g_str_hash, g_str_equal, - "nautilus-directory-async.c: async_jobs"); - } - key = g_strconcat (directory->details->uri, ": ", job, NULL); - if (g_hash_table_lookup (async_jobs, key) != NULL) { - g_warning ("same job twice: %s in %s", - job, - directory->details->uri); - } - g_hash_table_insert (async_jobs, key, directory); + { + char *uri; + if (async_jobs == NULL) { + async_jobs = eel_g_hash_table_new_free_at_exit + (g_str_hash, g_str_equal, + "nautilus-directory-async.c: async_jobs"); + } + uri = = nautilus_directory_get_uri (directory); + key = g_strconcat (uri, ": ", job, NULL); + if (g_hash_table_lookup (async_jobs, key) != NULL) { + g_warning ("same job twice: %s in %s", + job, uri); + } + g_free (uri); + g_hash_table_insert (async_jobs, key, directory); + } #endif async_job_count += 1; @@ -277,23 +329,27 @@ async_job_end (NautilusDirectory *directory, #endif #ifdef DEBUG_START_STOP - g_message ("stopping %s in %s", job, directory->details->uri); + g_message ("stopping %s in %p", job, directory->details->location); #endif g_assert (async_job_count > 0); #ifdef DEBUG_ASYNC_JOBS - g_assert (async_jobs != NULL); - key = g_strconcat (directory->details->uri, ": ", job, NULL); - if (!g_hash_table_lookup_extended (async_jobs, key, &table_key, &value)) { - g_warning ("ending job we didn't start: %s in %s", - job, - directory->details->uri); - } else { - g_hash_table_remove (async_jobs, key); - g_free (table_key); + { + char *uri; + uri = nautilus_directory_get_uri (directory); + g_assert (async_jobs != NULL); + key = g_strconcat (uri, ": ", job, NULL); + if (!g_hash_table_lookup_extended (async_jobs, key, &table_key, &value)) { + g_warning ("ending job we didn't start: %s in %s", + job, uri); + } else { + g_hash_table_remove (async_jobs, key); + g_free (table_key); + } + g_free (uri); + g_free (key); } - g_free (key); #endif async_job_count -= 1; @@ -355,9 +411,11 @@ static void directory_count_cancel (NautilusDirectory *directory) { if (directory->details->count_in_progress != NULL) { - gnome_vfs_async_cancel (directory->details->count_in_progress); - directory->details->count_file = NULL; + g_cancellable_cancel (directory->details->count_in_progress->cancellable); + directory->details->count_in_progress->directory = NULL; directory->details->count_in_progress = NULL; + directory->details->count_file = NULL; + async_job_end (directory, "directory count"); } @@ -368,17 +426,14 @@ deep_count_cancel (NautilusDirectory *directory) { if (directory->details->deep_count_in_progress != NULL) { g_assert (NAUTILUS_IS_FILE (directory->details->deep_count_file)); - - gnome_vfs_async_cancel (directory->details->deep_count_in_progress); + + g_cancellable_cancel (directory->details->deep_count_in_progress->cancellable); directory->details->deep_count_file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED; - directory->details->deep_count_file = NULL; + directory->details->deep_count_in_progress->directory = NULL; directory->details->deep_count_in_progress = NULL; - g_free (directory->details->deep_count_uri); - directory->details->deep_count_uri = NULL; - eel_g_list_free_deep (directory->details->deep_count_subdirectories); - directory->details->deep_count_subdirectories = NULL; + directory->details->deep_count_file = NULL; async_job_end (directory, "deep count"); } @@ -390,12 +445,11 @@ mime_list_cancel (NautilusDirectory *directory) if (directory->details->mime_list_in_progress != NULL) { g_assert (NAUTILUS_IS_FILE (directory->details->mime_list_file)); - gnome_vfs_async_cancel (directory->details->mime_list_in_progress); - istr_set_destroy (directory->details->mime_list_hash); - - directory->details->mime_list_file = NULL; + g_cancellable_cancel (directory->details->mime_list_in_progress->cancellable); + + directory->details->mime_list_in_progress->directory = NULL; directory->details->mime_list_in_progress = NULL; - directory->details->mime_list_hash = NULL; + directory->details->mime_list_file = NULL; async_job_end (directory, "MIME list"); } @@ -405,10 +459,10 @@ static void top_left_cancel (NautilusDirectory *directory) { if (directory->details->top_left_read_state != NULL) { - eel_read_file_cancel (directory->details->top_left_read_state->handle); - g_free (directory->details->top_left_read_state); + g_cancellable_cancel (directory->details->top_left_read_state->cancellable); + directory->details->top_left_read_state->directory = NULL; directory->details->top_left_read_state = NULL; - + async_job_end (directory, "top left"); } } @@ -417,20 +471,32 @@ static void link_info_cancel (NautilusDirectory *directory) { if (directory->details->link_info_read_state != NULL) { - eel_read_file_cancel (directory->details->link_info_read_state->handle); - g_free (directory->details->link_info_read_state); + g_cancellable_cancel (directory->details->link_info_read_state->cancellable); + directory->details->link_info_read_state->directory = NULL; directory->details->link_info_read_state = NULL; async_job_end (directory, "link info"); } } static void +thumbnail_cancel (NautilusDirectory *directory) +{ + if (directory->details->thumbnail_state != NULL) { + g_cancellable_cancel (directory->details->thumbnail_state->cancellable); + directory->details->thumbnail_state->directory = NULL; + directory->details->thumbnail_state = NULL; + async_job_end (directory, "thumbnail"); + } +} + +static void file_info_cancel (NautilusDirectory *directory) { if (directory->details->get_info_in_progress != NULL) { - gnome_vfs_async_cancel (directory->details->get_info_in_progress); - directory->details->get_info_file = NULL; + g_cancellable_cancel (directory->details->get_info_in_progress->cancellable); + directory->details->get_info_in_progress->directory = NULL; directory->details->get_info_in_progress = NULL; + directory->details->get_info_file = NULL; async_job_end (directory, "file info"); } @@ -439,11 +505,17 @@ file_info_cancel (NautilusDirectory *directory) static void new_files_cancel (NautilusDirectory *directory) { - if (directory->details->get_file_infos_in_progress != NULL) { - g_list_foreach (directory->details->get_file_infos_in_progress, - (GFunc)gnome_vfs_async_cancel, NULL); - g_list_free (directory->details->get_file_infos_in_progress); - directory->details->get_file_infos_in_progress = NULL; + GList *l; + NewFilesState *state; + + if (directory->details->new_files_in_progress != NULL) { + for (l = directory->details->new_files_in_progress; l != NULL; l = l->next) { + state = l->data; + g_cancellable_cancel (state->cancellable); + state->directory = NULL; + } + g_list_free (directory->details->new_files_in_progress); + directory->details->new_files_in_progress = NULL; } } @@ -515,18 +587,18 @@ nautilus_directory_set_up_request (Request *request, { memset (request, 0, sizeof (*request)); - request->directory_count = (file_attributes & - NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT) != FALSE; - request->deep_count = (file_attributes & - NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS) != FALSE; - request->mime_list = (file_attributes & - NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES) != FALSE; - request->file_info = (file_attributes & - (NAUTILUS_FILE_ATTRIBUTE_MIME_TYPE | - NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE | - NAUTILUS_FILE_ATTRIBUTE_IS_DIRECTORY | - NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES | - NAUTILUS_FILE_ATTRIBUTE_FILE_TYPE)) != FALSE; + request->directory_count = + (file_attributes & NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT) != 0; + request->deep_count = + (file_attributes & NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS) != 0; + request->mime_list = + (file_attributes & NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES) != 0; + request->file_info = (file_attributes & NAUTILUS_FILE_ATTRIBUTE_INFO) != 0; + + if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_LINK_INFO) { + request->file_info = TRUE; + request->link_info = TRUE; + } if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT) { request->top_left_text = TRUE; @@ -537,61 +609,27 @@ nautilus_directory_set_up_request (Request *request, request->large_top_left_text = TRUE; request->file_info = TRUE; } - - if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI) { - request->file_info = TRUE; - request->link_info = TRUE; - } - - if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_VOLUMES) { - request->link_info = TRUE; - } - if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME) { - request->file_info = TRUE; - request->link_info = TRUE; - } + request->metafile |= (file_attributes & NAUTILUS_FILE_ATTRIBUTE_METADATA) != 0; + request->extension_info = (file_attributes & NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO) != 0; - /* FIXME bugzilla.gnome.org 42435: - * Some file attributes are really pieces of metadata. - * This is a confusing/broken design, since other metadata - * pieces are handled separately from file attributes. There - * are many ways this could be changed, ranging from making - * all metadata pieces have corresponding file attributes, to - * making a single file attribute that means "get all metadata", - * to making metadata keys be acceptable as file attributes - * directly (would need some funky char trick to prevent - * namespace collisions). - */ - if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_CUSTOM_ICON) { - request->metafile = TRUE; + if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL) { + request->thumbnail = TRUE; request->file_info = TRUE; - request->link_info = TRUE; } - - request->metafile |= (file_attributes & - NAUTILUS_FILE_ATTRIBUTE_METADATA) != FALSE; - - request->slow_mime_type = (file_attributes & NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE) != FALSE; - - request->extension_info = (file_attributes & NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO) != FALSE; } static void -mime_db_changed_callback (GnomeVFSMIMEMonitor *ignore, NautilusDirectory *dir) +mime_db_changed_callback (GObject *ignore, NautilusDirectory *dir) { NautilusFileAttributes attrs; g_return_if_fail (dir != NULL); g_return_if_fail (dir->details != NULL); - attrs = NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI | - NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES | - NAUTILUS_FILE_ATTRIBUTE_CUSTOM_ICON | - NAUTILUS_FILE_ATTRIBUTE_MIME_TYPE | - NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE | + attrs = NAUTILUS_FILE_ATTRIBUTE_INFO | + NAUTILUS_FILE_ATTRIBUTE_LINK_INFO | NAUTILUS_FILE_ATTRIBUTE_METADATA | - NAUTILUS_FILE_ATTRIBUTE_FILE_TYPE | NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES; nautilus_directory_force_reload_internal (dir, attrs); @@ -609,7 +647,7 @@ nautilus_directory_monitor_add_internal (NautilusDirectory *directory, { Monitor *monitor; GList *file_list; - + g_assert (NAUTILUS_IS_DIRECTORY (directory)); /* Replace any current monitor for this client/file pair. */ @@ -639,7 +677,7 @@ nautilus_directory_monitor_add_internal (NautilusDirectory *directory, * it allows us to avoid one file monitor per file in a directory. */ if (directory->details->monitor == NULL) { - directory->details->monitor = nautilus_monitor_directory (directory->details->uri); + directory->details->monitor = nautilus_monitor_directory (directory->details->location); } /* We could just call update_metadata_monitors here, but we can be smarter @@ -650,10 +688,10 @@ nautilus_directory_monitor_add_internal (NautilusDirectory *directory, } if (monitor->request.file_info && directory->details->mime_db_monitor == 0) { - directory->details->mime_db_monitor = g_signal_connect_object ( - gnome_vfs_mime_monitor_get (), - "data_changed", - G_CALLBACK (mime_db_changed_callback), directory, 0); + directory->details->mime_db_monitor = + g_signal_connect_object (nautilus_signaller_get_current (), + "mime_data_changed", + G_CALLBACK (mime_db_changed_callback), directory, 0); } /* Put the monitor file or all the files on the work queue. */ @@ -704,25 +742,7 @@ show_backup_files_changed_callback (gpointer callback_data) } static gboolean -is_dot_or_dot_dot (const char *name) -{ - if (name[0] != '.') { - return FALSE; - } - if (name[1] == '\0') { - return TRUE; - } - if (name[1] != '.') { - return FALSE; - } - if (name[2] == '\0') { - return TRUE; - } - return FALSE; -} - -static gboolean -should_skip_file (NautilusDirectory *directory, GnomeVFSFileInfo *info) +should_skip_file (NautilusDirectory *directory, GFileInfo *info) { static gboolean show_hidden_files_changed_callback_installed = FALSE; static gboolean show_backup_files_changed_callback_installed = FALSE; @@ -749,56 +769,21 @@ should_skip_file (NautilusDirectory *directory, GnomeVFSFileInfo *info) show_backup_files_changed_callback (NULL); } - if (info == NULL || info->name == NULL) { - return TRUE; - } - - if (is_dot_or_dot_dot (info->name)) { - return TRUE; - } - - if (!show_hidden_files && (nautilus_file_name_matches_hidden_pattern (info->name) || - (directory != NULL && - g_hash_table_lookup (directory->details->hidden_file_hash, info->name) != NULL))) { + if (!show_hidden_files && + (g_file_info_get_is_hidden (info) || + (directory != NULL && directory->details->hidden_file_hash != NULL && + g_hash_table_lookup (directory->details->hidden_file_hash, + g_file_info_get_name (info)) != NULL))) { return TRUE; } - if (!show_backup_files && nautilus_file_name_matches_backup_pattern (info->name)) { + + if (!show_backup_files && g_file_info_get_is_backup (info)) { return TRUE; } return FALSE; } -static void -load_directory_state_destroy (NautilusDirectory *directory) -{ - NautilusFile *file; - - if (directory->details->load_mime_list_hash != NULL) { - istr_set_destroy (directory->details->load_mime_list_hash); - directory->details->load_mime_list_hash = NULL; - } - - file = directory->details->load_directory_file; - if (file != NULL) { - directory->details->load_directory_file = NULL; - - file->details->loading_directory = FALSE; - if (file->details->directory != directory) { - nautilus_directory_async_state_changed (file->details->directory); - } - - nautilus_file_unref (file); - } -} - -static void -load_directory_done (NautilusDirectory *directory) -{ - load_directory_state_destroy (directory); - nautilus_directory_async_state_changed (directory); -} - static gboolean dequeue_pending_idle_callback (gpointer callback_data) { @@ -807,7 +792,9 @@ dequeue_pending_idle_callback (gpointer callback_data) GList *node, *next; NautilusFile *file; GList *changed_files, *added_files; - GnomeVFSFileInfo *file_info; + GFileInfo *file_info; + const char *mimetype, *name; + DirectoryLoadState *dir_load_state; directory = NAUTILUS_DIRECTORY (callback_data); @@ -821,17 +808,21 @@ dequeue_pending_idle_callback (gpointer callback_data) /* If we are no longer monitoring, then throw away these. */ if (!nautilus_directory_is_file_list_monitored (directory)) { - load_directory_done (directory); + nautilus_directory_async_state_changed (directory); goto drain; } added_files = NULL; changed_files = NULL; + dir_load_state = directory->details->directory_load_in_progress; + /* Build a list of NautilusFile objects. */ for (node = pending_file_info; node != NULL; node = node->next) { file_info = node->data; + name = g_file_info_get_name (file_info); + /* Update the file count. */ /* FIXME bugzilla.gnome.org 45063: This could count a * file twice if we get it from both load_directory @@ -839,32 +830,33 @@ dequeue_pending_idle_callback (gpointer callback_data) * moving this into the actual callback instead of * waiting for the idle function. */ - if (!should_skip_file (directory, file_info)) { - directory->details->load_file_count += 1; + if (dir_load_state && + !should_skip_file (directory, file_info)) { + dir_load_state->load_file_count += 1; /* Add the MIME type to the set. */ - if ((file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) != 0 - && directory->details->load_mime_list_hash != NULL) { - istr_set_insert (directory->details->load_mime_list_hash, - file_info->mime_type); + mimetype = g_file_info_get_content_type (file_info); + if (mimetype != NULL) { + istr_set_insert (dir_load_state->load_mime_list_hash, + mimetype); } } /* check if the file already exists */ - file = nautilus_directory_find_file_by_name (directory, file_info->name); + file = nautilus_directory_find_file_by_name (directory, name); if (file != NULL) { /* file already exists in dir, check if we still need to * emit file_added or if it changed */ set_file_unconfirmed (file, FALSE); if (!file->details->is_added) { /* We consider this newly added even if its in the list. - * This can happen if someone called nautilus_file_get() + * This can happen if someone called nautilus_file_get_by_uri() * on a file in the folder before the add signal was * emitted */ nautilus_file_ref (file); file->details->is_added = TRUE; added_files = g_list_prepend (added_files, file); - } else if (nautilus_file_update_info (file, file_info, FALSE)) { + } else if (nautilus_file_update_info (file, file_info)) { /* File changed, notify about the change. */ nautilus_file_ref (file); changed_files = g_list_prepend (changed_files, file); @@ -902,33 +894,34 @@ dequeue_pending_idle_callback (gpointer callback_data) nautilus_directory_emit_files_added (directory, added_files); nautilus_file_list_free (added_files); - if (directory->details->directory_loaded - && !directory->details->directory_loaded_sent_notification) { + if (directory->details->directory_loaded && + !directory->details->directory_loaded_sent_notification) { /* Send the done_loading signal. */ nautilus_directory_emit_done_loading (directory); - file = directory->details->load_directory_file; - - if (file != NULL) { + if (dir_load_state) { + file = dir_load_state->load_directory_file; + + file->details->directory_count = dir_load_state->load_file_count; file->details->directory_count_is_up_to_date = TRUE; file->details->got_directory_count = TRUE; - file->details->directory_count = directory->details->load_file_count; file->details->got_mime_list = TRUE; file->details->mime_list_is_up_to_date = TRUE; + eel_g_list_free_deep (file->details->mime_list); file->details->mime_list = istr_set_get_as_list - (directory->details->load_mime_list_hash); + (dir_load_state->load_mime_list_hash); nautilus_file_changed (file); } - load_directory_done (directory); + nautilus_directory_async_state_changed (directory); directory->details->directory_loaded_sent_notification = TRUE; } drain: - gnome_vfs_file_info_list_free (pending_file_info); + eel_g_object_list_free (pending_file_info); /* Get the state machine running again. */ nautilus_directory_async_state_changed (directory); @@ -948,15 +941,14 @@ nautilus_directory_schedule_dequeue_pending (NautilusDirectory *directory) static void directory_load_one (NautilusDirectory *directory, - GnomeVFSFileInfo *info) + GFileInfo *info) { - if (info == NULL || info->name == NULL || - is_dot_or_dot_dot (info->name)) { + if (info == NULL) { return; } /* Arrange for the "loading" part of the work. */ - gnome_vfs_file_info_ref (info); + g_object_ref (info); directory->details->pending_file_info = g_list_prepend (directory->details->pending_file_info, info); nautilus_directory_schedule_dequeue_pending (directory); @@ -965,8 +957,19 @@ directory_load_one (NautilusDirectory *directory, static void directory_load_cancel (NautilusDirectory *directory) { - if (directory->details->directory_load_in_progress != NULL) { - gnome_vfs_async_cancel (directory->details->directory_load_in_progress); + NautilusFile *file; + DirectoryLoadState *state; + + state = directory->details->directory_load_in_progress; + if (state != NULL) { + file = state->load_directory_file; + file->details->loading_directory = FALSE; + if (file->details->directory != directory) { + nautilus_directory_async_state_changed (file->details->directory); + } + + g_cancellable_cancel (state->cancellable); + state->directory = NULL; directory->details->directory_load_in_progress = NULL; async_job_end (directory, "file list"); } @@ -989,30 +992,25 @@ file_list_cancel (NautilusDirectory *directory) } if (directory->details->pending_file_info != NULL) { - gnome_vfs_file_info_list_free (directory->details->pending_file_info); + eel_g_object_list_free (directory->details->pending_file_info); directory->details->pending_file_info = NULL; } - g_hash_table_foreach_remove (directory->details->hidden_file_hash, remove_callback, NULL); - - load_directory_state_destroy (directory); + if (directory->details->hidden_file_hash) { + g_hash_table_foreach_remove (directory->details->hidden_file_hash, remove_callback, NULL); + } } static void directory_load_done (NautilusDirectory *directory, - GnomeVFSResult result) + GError *error) { GList *node; - directory_load_cancel (directory); directory->details->directory_loaded = TRUE; directory->details->directory_loaded_sent_notification = FALSE; - /* Note that GNOME_VFS_OK can make it this far when the file-list - * length limit has been reached. In that case, don't treat it as - * an error. - */ - if (result != GNOME_VFS_ERROR_EOF && result != GNOME_VFS_OK) { + if (error != NULL) { /* The load did not complete successfully. This means * we don't know the status of the files in this directory. * We clear the unconfirmed bit on each file here so that @@ -1024,8 +1022,7 @@ directory_load_done (NautilusDirectory *directory, set_file_unconfirmed (NAUTILUS_FILE (node->data), FALSE); } - nautilus_directory_emit_load_error (directory, - result, NULL); + nautilus_directory_emit_load_error (directory, error); } /* Call the idle function right away. */ @@ -1033,35 +1030,8 @@ directory_load_done (NautilusDirectory *directory, g_source_remove (directory->details->dequeue_pending_idle_id); } dequeue_pending_idle_callback (directory); -} - -static void -directory_load_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - GList *list, - guint entries_read, - gpointer callback_data) -{ - NautilusDirectory *directory; - GList *element; - - directory = NAUTILUS_DIRECTORY (callback_data); - - g_assert (directory->details->directory_load_in_progress != NULL); - g_assert (directory->details->directory_load_in_progress == handle); - nautilus_directory_ref (directory); - - for (element = list; element != NULL; element = element->next) { - directory_load_one (directory, element->data); - } - - if (nautilus_directory_file_list_length_reached (directory) - || result != GNOME_VFS_OK) { - directory_load_done (directory, result); - } - - nautilus_directory_unref (directory); + directory_load_cancel (directory); } /* This checks if there's a request for the metafile contents. */ @@ -1415,116 +1385,87 @@ nautilus_directory_cancel_callback_internal (NautilusDirectory *directory, } while (node != NULL); } -static guint -count_non_skipped_files (GList *list) +static void +new_files_state_unref (NewFilesState *state) { - guint count; - GList *node; + state->count--; - count = 0; - for (node = list; node != NULL; node = node->next) { - if (!should_skip_file (NULL, node->data)) { - count += 1; + if (state->count == 0) { + if (state->directory) { + state->directory->details->new_files_in_progress = + g_list_remove (state->directory->details->new_files_in_progress, + state); } + + g_object_unref (state->cancellable); + g_free (state); } - return count; } static void -directory_count_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - GList *list, - guint entries_read, - gpointer callback_data) +new_files_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { NautilusDirectory *directory; - NautilusFile *count_file; - - directory = NAUTILUS_DIRECTORY (callback_data); + GFileInfo *info; + NewFilesState *state; - g_assert (directory->details->count_in_progress == handle); - count_file = directory->details->count_file; - g_assert (NAUTILUS_IS_FILE (count_file)); + state = user_data; - if (result == GNOME_VFS_OK) { + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + new_files_state_unref (state); return; } - - nautilus_directory_ref (directory); - - count_file->details->directory_count_is_up_to_date = TRUE; - - /* Record either a failure or success. */ - if (result != GNOME_VFS_ERROR_EOF) { - count_file->details->directory_count_failed = TRUE; - count_file->details->got_directory_count = FALSE; - count_file->details->directory_count = 0; - } else { - count_file->details->directory_count_failed = FALSE; - count_file->details->got_directory_count = TRUE; - count_file->details->directory_count = count_non_skipped_files (list); - } - directory->details->count_file = NULL; - directory->details->count_in_progress = NULL; - - /* Send file-changed even if count failed, so interested parties can - * distinguish between unknowable and not-yet-known cases. - */ - nautilus_file_changed (count_file); - - /* Start up the next one. */ - async_job_end (directory, "directory count"); - nautilus_directory_async_state_changed (directory); - - nautilus_directory_unref (directory); -} - -static void -new_files_callback (GnomeVFSAsyncHandle *handle, - GList *results, - gpointer callback_data) -{ - GList **handles, *node; - NautilusDirectory *directory; - GnomeVFSGetFileInfoResult *result; - - directory = NAUTILUS_DIRECTORY (callback_data); - handles = &directory->details->get_file_infos_in_progress; - g_assert (handle == NULL || g_list_find (*handles, handle) != NULL); - - nautilus_directory_ref (directory); - /* Note that this call is done. */ - *handles = g_list_remove (*handles, handle); - - /* Queue up the new files. */ - for (node = results; node != NULL; node = node->next) { - result = node->data; - - if (result->result == GNOME_VFS_OK) { - directory_load_one (directory, result->file_info); - } + directory = nautilus_directory_ref (state->directory); + + /* Queue up the new file. */ + info = g_file_query_info_finish (G_FILE (source_object), res, NULL); + if (info != NULL) { + directory_load_one (directory, info); + g_object_unref (info); } + new_files_state_unref (state); + nautilus_directory_unref (directory); } void nautilus_directory_get_info_for_new_files (NautilusDirectory *directory, - GList *vfs_uri_list) + GList *location_list) { - GnomeVFSAsyncHandle *handle; - gnome_vfs_async_get_file_info - (&handle, - vfs_uri_list, - NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS, - GNOME_VFS_PRIORITY_DEFAULT, - new_files_callback, - directory); + NewFilesState *state; + GFile *location; + GList *l; - directory->details->get_file_infos_in_progress - = g_list_prepend (directory->details->get_file_infos_in_progress, - handle); + if (location_list == NULL) { + return; + } + + state = g_new (NewFilesState, 1); + state->directory = directory; + state->cancellable = g_cancellable_new (); + state->count = 0; + + for (l = location_list; l != NULL; l = l->next) { + location = l->data; + + state->count++; + + g_file_query_info_async (location, + NAUTILUS_FILE_DEFAULT_ATTRIBUTES, + 0, + G_PRIORITY_DEFAULT, + state->cancellable, + new_files_callback, state); + } + + directory->details->new_files_in_progress + = g_list_prepend (directory->details->new_files_in_progress, + state); } void @@ -1596,8 +1537,8 @@ nautilus_async_destroying_file (NautilusFile *file) directory->details->top_left_read_state->file = NULL; changed = TRUE; } - if (directory->details->link_info_read_state != NULL - && directory->details->link_info_read_state->file == file) { + if (directory->details->link_info_read_state != NULL && + directory->details->link_info_read_state->file == file) { directory->details->link_info_read_state->file = NULL; changed = TRUE; } @@ -1606,6 +1547,12 @@ nautilus_async_destroying_file (NautilusFile *file) changed = TRUE; } + if (directory->details->thumbnail_state != NULL && + directory->details->thumbnail_state->file == file) { + directory->details->thumbnail_state->file = NULL; + changed = TRUE; + } + /* Let the directory take care of the rest. */ if (changed) { nautilus_directory_async_state_changed (directory); @@ -1675,27 +1622,6 @@ wants_info (const Request *request) } static gboolean -always_lacks (NautilusFile *file) -{ - return TRUE; -} - -static gboolean -lacks_slow_mime_type (NautilusFile *file) -{ - return !file->details->got_slow_mime_type - && !file->details->is_gone && - !file->details->get_info_failed; -} - -static gboolean -wants_slow_mime_type (const Request *request) -{ - return request->slow_mime_type; -} - - -static gboolean lacks_deep_count (NautilusFile *file) { return file->details->deep_counts_status != NAUTILUS_REQUEST_DONE; @@ -1733,7 +1659,7 @@ lacks_link_info (NautilusFile *file) if (nautilus_file_is_nautilus_link (file)) { return TRUE; } else { - link_info_done (file->details->directory, file, NULL, NULL, NULL, 0, 0); + link_info_done (file->details->directory, file, NULL, NULL, NULL); return FALSE; } } else { @@ -1760,6 +1686,20 @@ wants_extension_info (const Request *request) } static gboolean +lacks_thumbnail (NautilusFile *file) +{ + return nautilus_file_should_show_thumbnail (file) && + file->details->thumbnail_path != NULL && + !file->details->thumbnail_is_up_to_date; +} + +static gboolean +wants_thumbnail (const Request *request) +{ + return request->thumbnail; +} + +static gboolean has_problem (NautilusDirectory *directory, NautilusFile *file, FileCheck problem) { GList *node; @@ -1803,12 +1743,6 @@ request_is_satisfied (NautilusDirectory *directory, } } - if (request->slow_mime_type) { - if (has_problem (directory, file, lacks_slow_mime_type)) { - return FALSE; - } - } - if (request->top_left_text) { if (has_problem (directory, file, lacks_top_left)) { return FALSE; @@ -1977,64 +1911,50 @@ mark_all_files_unconfirmed (NautilusDirectory *directory) static void read_dot_hidden_file (NautilusDirectory *directory) { - char *dot_hidden_uri; - GnomeVFSURI *dot_hidden_vfs_uri; - GnomeVFSResult result; - int i, file_size; + gsize file_size; char *file_contents; - GnomeVFSFileInfo *file_info; - gboolean file_ok; + GFile *child; + GFileInfo *info; + GFileType type; + int i; /* FIXME: We only support .hidden on file: uri's for the moment. * Need to figure out if we should do this async or sync to extend * it to all types of uris. */ - if (directory->details->vfs_uri == NULL || - (eel_strcasecmp (directory->details->vfs_uri->method_string, "file") != 0)) { + if (directory->details->location == NULL || + !g_file_is_native (directory->details->location)) { return; } - /* FIXME: what we really need is a uri_append_file_name call - * that works on strings, so we can avoid the VFS parsing step. - */ - dot_hidden_vfs_uri = gnome_vfs_uri_append_file_name (directory->details->vfs_uri, ".hidden"); + child = g_file_get_child (directory->details->location, ".hidden"); - file_info = gnome_vfs_file_info_new (); - if (!file_info) { - gnome_vfs_uri_unref (dot_hidden_vfs_uri); - return; + type = G_FILE_TYPE_UNKNOWN; + + info = g_file_query_info (child, G_FILE_ATTRIBUTE_STD_TYPE, 0, NULL, NULL); + if (info != NULL) { + type = g_file_info_get_file_type (info); + g_object_unref (info); } - if (gnome_vfs_get_file_info_uri ( - dot_hidden_vfs_uri, - file_info, - GNOME_VFS_FILE_INFO_FOLLOW_LINKS) != GNOME_VFS_OK) { - gnome_vfs_uri_unref (dot_hidden_vfs_uri); - gnome_vfs_file_info_unref (file_info); + if (type != G_FILE_TYPE_REGULAR) { + g_object_unref (child); return; } - file_ok = (file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) && - (file_info->type == GNOME_VFS_FILE_TYPE_REGULAR); - - gnome_vfs_file_info_unref (file_info); - - if (!file_ok) { - gnome_vfs_uri_unref (dot_hidden_vfs_uri); + if (!g_file_load_contents (child, NULL, &file_contents, &file_size, NULL, NULL)) { + g_object_unref (child); return; } - - dot_hidden_uri = gnome_vfs_uri_to_string (dot_hidden_vfs_uri, GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (dot_hidden_vfs_uri); - - result = eel_read_entire_file (dot_hidden_uri, &file_size, &file_contents); - g_free (dot_hidden_uri); - if (result != GNOME_VFS_OK) { - return; - } + g_object_unref (child); + if (directory->details->hidden_file_hash == NULL) { + directory->details->hidden_file_hash = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + } + /* Now parse the data */ i = 0; while (i < file_size) { @@ -2046,14 +1966,11 @@ read_dot_hidden_file (NautilusDirectory *directory) } if (i > start) { - char *tmp, *tmp2; + char *hidden_filename; - tmp = g_strndup (file_contents + start, i - start); - tmp2 = gnome_vfs_escape_string (tmp); - g_free (tmp); - + hidden_filename = g_strndup (file_contents + start, i - start); g_hash_table_insert (directory->details->hidden_file_hash, - tmp2, tmp2); + hidden_filename, hidden_filename); } i++; @@ -2063,18 +1980,133 @@ read_dot_hidden_file (NautilusDirectory *directory) g_free (file_contents); } +static void +directory_load_state_free (DirectoryLoadState *state) +{ + if (state->enumerator) { + if (!g_file_enumerator_is_closed (state->enumerator)) { + g_file_enumerator_close_async (state->enumerator, + 0, NULL, NULL, NULL); + } + g_object_unref (state->enumerator); + } + + if (state->load_mime_list_hash != NULL) { + istr_set_destroy (state->load_mime_list_hash); + } + nautilus_file_unref (state->load_directory_file); + g_object_unref (state->cancellable); + g_free (state); +} + +static void +more_files_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + DirectoryLoadState *state; + NautilusDirectory *directory; + GError *error; + GList *files, *l; + GFileInfo *info; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + directory_load_state_free (state); + return; + } + + directory = nautilus_directory_ref (state->directory); + + g_assert (directory->details->directory_load_in_progress != NULL); + g_assert (directory->details->directory_load_in_progress == state); + + error = NULL; + files = g_file_enumerator_next_files_finish (state->enumerator, + res, &error); + + for (l = files; l != NULL; l = l->next) { + info = l->data; + directory_load_one (directory, info); + g_object_unref (info); + } + + if (nautilus_directory_file_list_length_reached (directory) || + files == NULL) { + directory_load_done (directory, error); + directory_load_state_free (state); + } else { + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_DEFAULT, + state->cancellable, + more_files_callback, + state); + } + + nautilus_directory_unref (directory); + + if (error) { + g_error_free (error); + } + + g_list_free (files); +} + +static void +enumerate_children_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + DirectoryLoadState *state; + GFileEnumerator *enumerator; + GError *error; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + directory_load_state_free (state); + return; + } + + error = NULL; + enumerator = g_file_enumerate_children_finish (G_FILE (source_object), + res, &error); + + if (enumerator == NULL) { + directory_load_done (state->directory, error); + g_error_free (error); + directory_load_state_free (state); + return; + } else { + state->enumerator = enumerator; + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_DEFAULT, + state->cancellable, + more_files_callback, + state); + } +} + + /* Start monitoring the file list if it isn't already. */ static void start_monitoring_file_list (NautilusDirectory *directory) { + DirectoryLoadState *state; + if (!directory->details->file_list_monitored) { - g_assert (directory->details->directory_load_in_progress == NULL); + g_assert (!directory->details->directory_load_in_progress); directory->details->file_list_monitored = TRUE; nautilus_file_list_ref (directory->details->file_list); } - if (directory->details->directory_loaded - || directory->details->directory_load_in_progress != NULL) { + if (directory->details->directory_loaded || + directory->details->directory_load_in_progress != NULL) { return; } @@ -2084,36 +2116,47 @@ start_monitoring_file_list (NautilusDirectory *directory) mark_all_files_unconfirmed (directory); - g_assert (directory->details->uri != NULL); - directory->details->load_directory_file = + state = g_new0 (DirectoryLoadState, 1); + state->directory = directory; + state->cancellable = g_cancellable_new (); + state->load_mime_list_hash = istr_set_new (); + state->load_file_count = 0; + + g_assert (directory->details->location != NULL); + state->load_directory_file = nautilus_directory_get_corresponding_file (directory); - - directory->details->load_directory_file->details->loading_directory = TRUE; - directory->details->load_file_count = 0; - directory->details->load_mime_list_hash = istr_set_new (); + state->load_directory_file->details->loading_directory = TRUE; read_dot_hidden_file (directory); /* Hack to work around kde trash dir */ if (kde_trash_dir_name != NULL && nautilus_directory_is_desktop_directory (directory)) { - char *escaped; - escaped = gnome_vfs_escape_string (kde_trash_dir_name); + char *fn; + + if (directory->details->hidden_file_hash == NULL) { + directory->details->hidden_file_hash = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + } + + fn = g_strdup (kde_trash_dir_name); g_hash_table_insert (directory->details->hidden_file_hash, - escaped, escaped); + fn, fn); } #ifdef DEBUG_LOAD_DIRECTORY - g_message ("load_directory called to monitor file list of %s", directory->details->uri); + g_message ("load_directory called to monitor file list of %p", directory->details->location); #endif - gnome_vfs_async_load_directory - (&directory->details->directory_load_in_progress, /* handle */ - directory->details->uri, /* uri */ - NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS, - DIRECTORY_LOAD_ITEMS_PER_CALLBACK, /* items_per_notification */ - GNOME_VFS_PRIORITY_DEFAULT, - directory_load_callback, /* callback */ - directory); + + directory->details->directory_load_in_progress = state; + + g_file_enumerate_children_async (directory->details->location, + NAUTILUS_FILE_DEFAULT_ATTRIBUTES, + 0, /* flags */ + G_PRIORITY_DEFAULT, /* prio */ + state->cancellable, + enumerate_children_callback, + state); } /* Stop monitoring the file list if it is being monitored. */ @@ -2290,12 +2333,171 @@ directory_count_stop (NautilusDirectory *directory) } } +static guint +count_non_skipped_files (GList *list) +{ + guint count; + GList *node; + GFileInfo *info; + + count = 0; + for (node = list; node != NULL; node = node->next) { + info = node->data; + if (!should_skip_file (NULL, info)) { + count += 1; + } + } + return count; +} + +static void +count_children_done (NautilusDirectory *directory, + gboolean succeeded, + int count) +{ + NautilusFile *count_file; + + count_file = directory->details->count_file; + + g_assert (NAUTILUS_IS_FILE (count_file)); + + nautilus_directory_ref (directory); + + count_file->details->directory_count_is_up_to_date = TRUE; + + /* Record either a failure or success. */ + if (!succeeded) { + count_file->details->directory_count_failed = TRUE; + count_file->details->got_directory_count = FALSE; + count_file->details->directory_count = 0; + } else { + count_file->details->directory_count_failed = FALSE; + count_file->details->got_directory_count = TRUE; + count_file->details->directory_count = count; + } + directory->details->count_file = NULL; + directory->details->count_in_progress = NULL; + + /* Send file-changed even if count failed, so interested parties can + * distinguish between unknowable and not-yet-known cases. + */ + nautilus_file_changed (count_file); + + /* Start up the next one. */ + async_job_end (directory, "directory count"); + nautilus_directory_async_state_changed (directory); + + nautilus_directory_unref (directory); +} + +static void +directory_count_state_free (DirectoryCountState *state) +{ + if (state->enumerator) { + if (!g_file_enumerator_is_closed (state->enumerator)) { + g_file_enumerator_close_async (state->enumerator, + 0, NULL, NULL, NULL); + } + g_object_unref (state->enumerator); + } + g_object_unref (state->cancellable); + g_free (state); +} + +static void +count_more_files_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + DirectoryCountState *state; + NautilusDirectory *directory; + GError *error; + GList *files; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + directory_count_state_free (state); + return; + } + + directory = nautilus_directory_ref (state->directory); + + g_assert (directory->details->count_in_progress != NULL); + g_assert (directory->details->count_in_progress == state); + + error = NULL; + files = g_file_enumerator_next_files_finish (state->enumerator, + res, &error); + + state->file_count += count_non_skipped_files (files); + + if (files == NULL) { + count_children_done (directory, TRUE, state->file_count); + directory_count_state_free (state); + } else { + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_DEFAULT, + state->cancellable, + count_more_files_callback, + state); + } + + eel_g_object_list_free (files); + + nautilus_directory_unref (directory); + + if (error) { + g_error_free (error); + } +} + +static void +count_children_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + DirectoryCountState *state; + GFileEnumerator *enumerator; + GError *error; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + directory_count_state_free (state); + return; + } + + error = NULL; + enumerator = g_file_enumerate_children_finish (G_FILE (source_object), + res, &error); + + if (enumerator == NULL) { + count_children_done (state->directory, FALSE, 0); + g_error_free (error); + directory_count_state_free (state); + return; + } else { + state->enumerator = enumerator; + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_DEFAULT, + state->cancellable, + count_more_files_callback, + state); + } +} + static void directory_count_start (NautilusDirectory *directory, NautilusFile *file, gboolean *doing_io) { - char *uri; + DirectoryCountState *state; + GFile *location; if (directory->details->count_in_progress != NULL) { *doing_io = TRUE; @@ -2324,103 +2526,110 @@ directory_count_start (NautilusDirectory *directory, /* Start counting. */ directory->details->count_file = file; - uri = nautilus_file_get_uri (file); + + state = g_new0 (DirectoryCountState, 1); + state->directory = directory; + state->cancellable = g_cancellable_new (); + + directory->details->count_in_progress = state; + #ifdef DEBUG_LOAD_DIRECTORY g_message ("load_directory called to get shallow file count for %s", uri); -#endif - gnome_vfs_async_load_directory - (&directory->details->count_in_progress, - uri, - GNOME_VFS_FILE_INFO_NAME_ONLY, - G_MAXINT, - GNOME_VFS_PRIORITY_DEFAULT, - directory_count_callback, - directory); - g_free (uri); +#endif + location = nautilus_file_get_location (file); + + g_file_enumerate_children_async (location, + "std:name,std:is_hidden,std:is_backup", + 0, /* flags */ + G_PRIORITY_DEFAULT, /* prio */ + state->cancellable, + count_children_callback, + state); + g_object_unref (location); } static void -deep_count_one (NautilusDirectory *directory, - GnomeVFSFileInfo *info) +deep_count_one (DeepCountState *state, + GFileInfo *info) { NautilusFile *file; - char *escaped_name, *uri; - - if (should_skip_file (NULL, info)) + GFile *subdir; + + if (should_skip_file (NULL, info)) { return; + } - file = directory->details->deep_count_file; + file = state->directory->details->deep_count_file; - if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) != 0 - && info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) { + if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { /* Count the directory. */ file->details->deep_directory_count += 1; /* Record the fact that we have to descend into this directory. */ - escaped_name = gnome_vfs_escape_string (info->name); - uri = g_build_filename (directory->details->deep_count_uri, escaped_name, NULL); - g_free (escaped_name); - directory->details->deep_count_subdirectories = g_list_prepend - (directory->details->deep_count_subdirectories, uri); + + subdir = g_file_get_child (state->deep_count_location, g_file_info_get_name (info)); + state->deep_count_subdirectories = g_list_prepend + (state->deep_count_subdirectories, subdir); } else { /* Even non-regular files count as files. */ file->details->deep_file_count += 1; } /* Count the size. */ - if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0) { - file->details->deep_size += info->size; + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STD_SIZE)) { + file->details->deep_size += g_file_info_get_size (info); } } static void -deep_count_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - GList *list, - guint entries_read, - gpointer callback_data) +deep_count_state_free (DeepCountState *state) { - NautilusDirectory *directory; + if (state->enumerator) { + if (!g_file_enumerator_is_closed (state->enumerator)) { + g_file_enumerator_close_async (state->enumerator, + 0, NULL, NULL, NULL); + } + g_object_unref (state->enumerator); + } + g_object_unref (state->cancellable); + if (state->deep_count_location) { + g_object_unref (state->deep_count_location); + } + eel_g_object_list_free (state->deep_count_subdirectories); + g_free (state); +} + +static void +deep_count_next_dir (DeepCountState *state) +{ + GFile *location; NautilusFile *file; - GList *element; - char *uri; + NautilusDirectory *directory; gboolean done; - directory = NAUTILUS_DIRECTORY (callback_data); - g_assert (directory->details->deep_count_in_progress == handle); - file = directory->details->deep_count_file; - g_assert (NAUTILUS_IS_FILE (file)); - - nautilus_directory_ref (directory); - - for (element = list; element != NULL; element = element->next) { - deep_count_one (directory, element->data); - } + directory = state->directory; + + g_object_unref (state->deep_count_location); + state->deep_count_location = NULL; done = FALSE; - if (result != GNOME_VFS_OK) { - if (result != GNOME_VFS_ERROR_EOF) { - file->details->deep_unreadable_count += 1; - } - + file = directory->details->deep_count_file; + + if (state->deep_count_subdirectories != NULL) { + /* Work on a new directory. */ + location = state->deep_count_subdirectories->data; + state->deep_count_subdirectories = g_list_remove + (state->deep_count_subdirectories, location); + deep_count_load (state, location); + g_object_unref (location); + } else { + file->details->deep_counts_status = NAUTILUS_REQUEST_DONE; + directory->details->deep_count_file = NULL; directory->details->deep_count_in_progress = NULL; - g_free (directory->details->deep_count_uri); - directory->details->deep_count_uri = NULL; - - if (directory->details->deep_count_subdirectories != NULL) { - /* Work on a new directory. */ - uri = directory->details->deep_count_subdirectories->data; - directory->details->deep_count_subdirectories = g_list_remove - (directory->details->deep_count_subdirectories, uri); - deep_count_load (directory, uri); - g_free (uri); - } else { - file->details->deep_counts_status = NAUTILUS_REQUEST_DONE; - directory->details->deep_count_file = NULL; - done = TRUE; - } + deep_count_state_free (state); + done = TRUE; } - + nautilus_file_updated_deep_count_in_progress (file); if (done) { @@ -2428,26 +2637,115 @@ deep_count_callback (GnomeVFSAsyncHandle *handle, async_job_end (directory, "deep count"); nautilus_directory_async_state_changed (directory); } +} + +static void +deep_count_more_files_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + DeepCountState *state; + NautilusDirectory *directory; + GList *files, *l; + GFileInfo *info; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + deep_count_state_free (state); + return; + } + + directory = nautilus_directory_ref (state->directory); + + g_assert (directory->details->deep_count_in_progress != NULL); + g_assert (directory->details->deep_count_in_progress == state); + + files = g_file_enumerator_next_files_finish (state->enumerator, + res, NULL); + + for (l = files; l != NULL; l = l->next) { + info = l->data; + deep_count_one (state, info); + g_object_unref (info); + } + + if (files == NULL) { + g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL); + g_object_unref (state->enumerator); + state->enumerator = NULL; + + deep_count_next_dir (state); + } else { + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_LOW, + state->cancellable, + deep_count_more_files_callback, + state); + } + + g_list_free (files); nautilus_directory_unref (directory); } static void -deep_count_load (NautilusDirectory *directory, const char *uri) +deep_count_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + DeepCountState *state; + GFileEnumerator *enumerator; + NautilusFile *file; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + deep_count_state_free (state); + return; + } + + file = state->directory->details->deep_count_file; + + enumerator = g_file_enumerate_children_finish (G_FILE (source_object), res, NULL); + + if (enumerator == NULL) { + file->details->deep_unreadable_count += 1; + + deep_count_next_dir (state); + } else { + state->enumerator = enumerator; + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_LOW, + state->cancellable, + deep_count_more_files_callback, + state); + } +} + + +static void +deep_count_load (DeepCountState *state, GFile *location) { - g_assert (directory->details->deep_count_uri == NULL); - directory->details->deep_count_uri = g_strdup (uri); + NautilusDirectory *directory; + + directory = state->directory; + state->deep_count_location = g_object_ref (location); + #ifdef DEBUG_LOAD_DIRECTORY - g_message ("load_directory called to get deep file count for %s", uri); + g_message ("load_directory called to get deep file count for %p", location); #endif - gnome_vfs_async_load_directory - (&directory->details->deep_count_in_progress, - uri, - GNOME_VFS_FILE_INFO_DEFAULT, - G_MAXINT, - GNOME_VFS_PRIORITY_DEFAULT, - deep_count_callback, - directory); + g_file_enumerate_children_async (state->deep_count_location, + "std:name,std:is_hidden,std:is_backup,std:type,std:size", + 0, /* flags */ + G_PRIORITY_LOW, /* prio */ + state->cancellable, + deep_count_callback, + state); } static void @@ -2477,8 +2775,9 @@ deep_count_start (NautilusDirectory *directory, NautilusFile *file, gboolean *doing_io) { - char *uri; - + GFile *location; + DeepCountState *state; + if (directory->details->deep_count_in_progress != NULL) { *doing_io = TRUE; return; @@ -2509,67 +2808,78 @@ deep_count_start (NautilusDirectory *directory, file->details->deep_unreadable_count = 0; file->details->deep_size = 0; directory->details->deep_count_file = file; - uri = nautilus_file_get_uri (file); - deep_count_load (directory, uri); - g_free (uri); -} -static void -mime_list_one (NautilusDirectory *directory, - GnomeVFSFileInfo *info) -{ - if (should_skip_file (NULL, info)) { - return; - } + state = g_new0 (DeepCountState, 1); + state->directory = directory; + state->cancellable = g_cancellable_new (); - if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) != 0) { - istr_set_insert (directory->details->mime_list_hash, info->mime_type); - } + directory->details->deep_count_in_progress = state; + + location = nautilus_file_get_location (file); + deep_count_load (state, location); + g_object_unref (location); } static void -mime_list_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - GList *list, - guint entries_read, - gpointer callback_data) +mime_list_stop (NautilusDirectory *directory) { - NautilusDirectory *directory; NautilusFile *file; - GList *element; - directory = NAUTILUS_DIRECTORY (callback_data); - g_assert (directory->details->mime_list_in_progress == handle); - file = directory->details->mime_list_file; - g_assert (NAUTILUS_IS_FILE (file)); + if (directory->details->mime_list_in_progress != NULL) { + file = directory->details->mime_list_file; + if (file != NULL) { + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (file->details->directory == directory); + if (is_needy (file, + should_get_mime_list, + wants_mime_list)) { + return; + } + } - for (element = list; element != NULL; element = element->next) { - mime_list_one (directory, element->data); + /* The count is not wanted, so stop it. */ + mime_list_cancel (directory); } +} - if (result == GNOME_VFS_OK) { - return; +static void +mime_list_state_free (MimeListState *state) +{ + if (state->enumerator) { + if (!g_file_enumerator_is_closed (state->enumerator)) { + g_file_enumerator_close_async (state->enumerator, + 0, NULL, NULL, NULL); + } + g_object_unref (state->enumerator); } + g_object_unref (state->cancellable); + istr_set_destroy (state->mime_list_hash); + g_free (state); +} - nautilus_directory_ref (directory); - file->details->mime_list_is_up_to_date = TRUE; +static void +mime_list_done (MimeListState *state, gboolean success) +{ + NautilusFile *file; + NautilusDirectory *directory; - /* Record either a failure or success. */ + directory = state->directory; + g_assert (directory != NULL); + + file = directory->details->mime_list_file; + + file->details->mime_list_is_up_to_date = TRUE; eel_g_list_free_deep (file->details->mime_list); - if (result != GNOME_VFS_ERROR_EOF) { + if (success) { file->details->mime_list_failed = TRUE; file->details->mime_list = NULL; } else { file->details->got_mime_list = TRUE; - file->details->mime_list = istr_set_get_as_list - (directory->details->mime_list_hash); + file->details->mime_list = istr_set_get_as_list (state->mime_list_hash); } - istr_set_destroy (directory->details->mime_list_hash); - directory->details->mime_list_in_progress = NULL; directory->details->mime_list_file = NULL; - directory->details->mime_list_hash = NULL; /* Send file-changed even if getting the item type list * failed, so interested parties can distinguish between @@ -2580,46 +2890,115 @@ mime_list_callback (GnomeVFSAsyncHandle *handle, /* Start up the next one. */ async_job_end (directory, "MIME list"); nautilus_directory_async_state_changed (directory); + +} - nautilus_directory_unref (directory); +static void +mime_list_one (MimeListState *state, + GFileInfo *info) +{ + const char *mime_type; + + if (should_skip_file (NULL, info)) { + g_object_unref (info); + return; + } + + mime_type = g_file_info_get_content_type (info); + if (mime_type != NULL) { + istr_set_insert (state->mime_list_hash, mime_type); + } } static void -mime_list_load (NautilusDirectory *directory, const char *uri) +mime_list_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { - directory->details->mime_list_hash = istr_set_new (); -#ifdef DEBUG_LOAD_DIRECTORY - g_message ("load_directory called to get MIME list of %s", uri); -#endif - gnome_vfs_async_load_directory - (&directory->details->mime_list_in_progress, - uri, - GNOME_VFS_FILE_INFO_GET_MIME_TYPE, - DIRECTORY_LOAD_ITEMS_PER_CALLBACK, - GNOME_VFS_PRIORITY_DEFAULT, - mime_list_callback, - directory); + MimeListState *state; + NautilusDirectory *directory; + GError *error; + GList *files, *l; + GFileInfo *info; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + mime_list_state_free (state); + return; + } + + directory = nautilus_directory_ref (state->directory); + + g_assert (directory->details->mime_list_in_progress != NULL); + g_assert (directory->details->mime_list_in_progress == state); + + error = NULL; + files = g_file_enumerator_next_files_finish (state->enumerator, + res, &error); + + for (l = files; l != NULL; l = l->next) { + info = l->data; + mime_list_one (state, info); + g_object_unref (info); + } + + if (files == NULL) { + mime_list_done (state, error != NULL); + mime_list_state_free (state); + } else { + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_DEFAULT, + state->cancellable, + mime_list_callback, + state); + } + + g_list_free (files); + + nautilus_directory_unref (directory); + + if (error) { + g_error_free (error); + } } static void -mime_list_stop (NautilusDirectory *directory) +list_mime_enum_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { - NautilusFile *file; + MimeListState *state; + GFileEnumerator *enumerator; + GError *error; - if (directory->details->mime_list_in_progress != NULL) { - file = directory->details->mime_list_file; - if (file != NULL) { - g_assert (NAUTILUS_IS_FILE (file)); - g_assert (file->details->directory == directory); - if (is_needy (file, - should_get_mime_list, - wants_mime_list)) { - return; - } - } + state = user_data; - /* The count is not wanted, so stop it. */ - mime_list_cancel (directory); + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + mime_list_state_free (state); + return; + } + + error = NULL; + enumerator = g_file_enumerate_children_finish (G_FILE (source_object), + res, &error); + + if (enumerator == NULL) { + mime_list_done (state, FALSE); + g_error_free (error); + mime_list_state_free (state); + return; + } else { + state->enumerator = enumerator; + g_file_enumerator_next_files_async (state->enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_DEFAULT, + state->cancellable, + mime_list_callback, + state); } } @@ -2628,7 +3007,8 @@ mime_list_start (NautilusDirectory *directory, NautilusFile *file, gboolean *doing_io) { - char *uri; + MimeListState *state; + GFile *location; mime_list_stop (directory); @@ -2659,114 +3039,142 @@ mime_list_start (NautilusDirectory *directory, return; } + + state = g_new0 (MimeListState, 1); + state->directory = directory; + state->cancellable = g_cancellable_new (); + state->mime_list_hash = istr_set_new (); + directory->details->mime_list_file = file; - uri = nautilus_file_get_uri (file); - mime_list_load (directory, uri); - g_free (uri); + directory->details->mime_list_in_progress = state; + +#ifdef DEBUG_LOAD_DIRECTORY + g_message ("load_directory called to get MIME list of %s", uri); +#endif + + location = nautilus_file_get_location (file); + g_file_enumerate_children_async (location, + G_FILE_ATTRIBUTE_STD_CONTENT_TYPE, + 0, /* flags */ + G_PRIORITY_LOW, /* prio */ + state->cancellable, + list_mime_enum_callback, + state); + g_object_unref (location); } -static int -count_lines (const char *text, int length) +static void +top_left_stop (NautilusDirectory *directory) { - int count, i; + NautilusFile *file; - count = 0; - for (i = 0; i < length; i++) { - count += *text++ == '\n'; + if (directory->details->top_left_read_state != NULL) { + file = directory->details->top_left_read_state->file; + if (file != NULL) { + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (file->details->directory == directory); + if (is_needy (file, + lacks_top_left, + wants_top_left) || + is_needy (file, + lacks_large_top_left, + wants_large_top_left)) { + return; + } + } + + /* The top left is not wanted, so stop it. */ + top_left_cancel (directory); } - return count; } static void -top_left_read_done (NautilusDirectory *directory) +top_left_read_state_free (TopLeftTextReadState *state) { - g_assert (directory->details->top_left_read_state->handle == NULL); - g_assert (NAUTILUS_IS_FILE (directory->details->top_left_read_state->file)); - - g_free (directory->details->top_left_read_state); - directory->details->top_left_read_state = NULL; - - async_job_end (directory, "top left"); - nautilus_directory_async_state_changed (directory); + g_object_unref (state->cancellable); + g_free (state); } static void -top_left_read_callback (GnomeVFSResult result, - GnomeVFSFileSize bytes_read, - char *file_contents, +top_left_read_callback (GObject *source_object, + GAsyncResult *res, gpointer callback_data) { + TopLeftTextReadState *state; NautilusDirectory *directory; NautilusFileDetails *file_details; + gsize file_size; + char *file_contents; - directory = NAUTILUS_DIRECTORY (callback_data); - - directory->details->top_left_read_state->handle = NULL; + state = callback_data; - file_details = directory->details->top_left_read_state->file->details; + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + top_left_read_state_free (state); + return; + } + + directory = nautilus_directory_ref (state->directory); + + file_details = state->file->details; file_details->top_left_text_is_up_to_date = TRUE; g_free (file_details->top_left_text); - if (result == GNOME_VFS_OK) { - file_details->top_left_text = nautilus_extract_top_left_text (file_contents, directory->details->top_left_read_state->large, bytes_read); + + if (g_file_load_partial_contents_finish (G_FILE (source_object), + res, + &file_contents, &file_size, + NULL, NULL)) { + file_details->top_left_text = nautilus_extract_top_left_text (file_contents, state->large, file_size); file_details->got_top_left_text = TRUE; - file_details->got_large_top_left_text = directory->details->top_left_read_state->large; + file_details->got_large_top_left_text = state->large; + g_free (file_contents); } else { file_details->top_left_text = NULL; file_details->got_top_left_text = FALSE; file_details->got_large_top_left_text = FALSE; } - g_free (file_contents); + nautilus_file_changed (state->file); - nautilus_file_changed (directory->details->top_left_read_state->file); + directory->details->top_left_read_state = NULL; + async_job_end (directory, "top left"); - top_left_read_done (directory); + top_left_read_state_free (state); + + nautilus_directory_async_state_changed (directory); + + nautilus_directory_unref (directory); } -static gboolean -top_left_read_more_callback (GnomeVFSFileSize bytes_read, - const char *file_contents, - gpointer callback_data) +static int +count_lines (const char *text, int length) { - NautilusDirectory *directory; - - directory = NAUTILUS_DIRECTORY (callback_data); - + int count, i; - /* Stop reading when we have enough. */ - if (directory->details->top_left_read_state->large) { - return bytes_read < NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_BYTES - && count_lines (file_contents, bytes_read) <= NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_LINES; - } else { - return bytes_read < NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_BYTES - && count_lines (file_contents, bytes_read) <= NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_LINES; + count = 0; + for (i = 0; i < length; i++) { + count += *text++ == '\n'; } - + return count; } -static void -top_left_stop (NautilusDirectory *directory) +static gboolean +top_left_read_more_callback (const char *file_contents, + goffset bytes_read, + gpointer callback_data) { - NautilusFile *file; + TopLeftTextReadState *state; - if (directory->details->top_left_read_state != NULL) { - file = directory->details->top_left_read_state->file; - if (file != NULL) { - g_assert (NAUTILUS_IS_FILE (file)); - g_assert (file->details->directory == directory); - if (is_needy (file, - lacks_top_left, - wants_top_left) || - is_needy (file, - lacks_large_top_left, - wants_large_top_left)) { - return; - } - } + state = callback_data; - /* The top left is not wanted, so stop it. */ - top_left_cancel (directory); + /* Stop reading when we have enough. */ + if (state->large) { + return bytes_read < NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_BYTES && + count_lines (file_contents, bytes_read) <= NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_LINES; + } else { + return bytes_read < NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_BYTES && + count_lines (file_contents, bytes_read) <= NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_LINES; } } @@ -2775,8 +3183,9 @@ top_left_start (NautilusDirectory *directory, NautilusFile *file, gboolean *doing_io) { - char *uri; + GFile *location; gboolean needs_large; + TopLeftTextReadState *state; if (directory->details->top_left_read_state != NULL) { *doing_io = TRUE; @@ -2816,42 +3225,56 @@ top_left_start (NautilusDirectory *directory, } /* Start reading. */ - directory->details->top_left_read_state = g_new0 (TopLeftTextReadState, 1); - directory->details->top_left_read_state->large = needs_large; - directory->details->top_left_read_state->file = file; - uri = nautilus_file_get_uri (file); - directory->details->top_left_read_state->handle = eel_read_file_async - (uri, - GNOME_VFS_PRIORITY_DEFAULT, - top_left_read_callback, - top_left_read_more_callback, - directory); - g_free (uri); + state = g_new0 (TopLeftTextReadState, 1); + state->directory = directory; + state->cancellable = g_cancellable_new (); + state->large = needs_large; + state->file = file; + + directory->details->top_left_read_state = state; + + location = nautilus_file_get_location (file); + g_file_load_partial_contents_async (location, + state->cancellable, + top_left_read_more_callback, + top_left_read_callback, + state); + g_object_unref (location); } static void -get_info_callback (GnomeVFSAsyncHandle *handle, - GList *results, - gpointer callback_data) +get_info_state_free (GetInfoState *state) +{ + g_object_unref (state->cancellable); + g_free (state); +} + +static void +query_info_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { NautilusDirectory *directory; NautilusFile *get_info_file; - GnomeVFSGetFileInfoResult *result; - gboolean has_slow_mime_type; + GFileInfo *info; + GetInfoState *state; + GError *error; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + get_info_state_free (state); + return; + } + + directory = nautilus_directory_ref (state->directory); - directory = NAUTILUS_DIRECTORY (callback_data); - g_assert (handle == NULL || handle == directory->details->get_info_in_progress); - g_assert (eel_g_list_exactly_one_item (results)); get_info_file = directory->details->get_info_file; g_assert (NAUTILUS_IS_FILE (get_info_file)); - nautilus_directory_ref (directory); - - has_slow_mime_type = directory->details->get_info_has_slow_mime_type; - directory->details->get_info_file = NULL; directory->details->get_info_in_progress = NULL; - directory->details->get_info_has_slow_mime_type = FALSE; /* ref here because we might be removing the last ref when we * mark the file gone below, but we need to keep a ref at @@ -2859,22 +3282,21 @@ get_info_callback (GnomeVFSAsyncHandle *handle, */ nautilus_file_ref (get_info_file); - result = results->data; - - if (result->result != GNOME_VFS_OK) { - if (result->result == GNOME_VFS_ERROR_NOT_FOUND) { + error = NULL; + info = g_file_query_info_finish (G_FILE (source_object), res, &error); + + if (info == NULL) { + if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND) { /* mark file as gone */ nautilus_file_mark_gone (get_info_file); } get_info_file->details->file_info_is_up_to_date = TRUE; - if (get_info_file->details->info != NULL) { - gnome_vfs_file_info_unref (get_info_file->details->info); - get_info_file->details->info = NULL; - } + nautilus_file_clear_info (get_info_file); get_info_file->details->get_info_failed = TRUE; - get_info_file->details->get_info_error = result->result; + get_info_file->details->get_info_error = error; } else { - nautilus_file_update_info (get_info_file, result->file_info, has_slow_mime_type); + nautilus_file_update_info (get_info_file, info); + g_object_unref (info); } nautilus_file_changed (get_info_file); @@ -2884,6 +3306,8 @@ get_info_callback (GnomeVFSAsyncHandle *handle, nautilus_directory_async_state_changed (directory); nautilus_directory_unref (directory); + + get_info_state_free (state); } static void @@ -2896,8 +3320,7 @@ file_info_stop (NautilusDirectory *directory) if (file != NULL) { g_assert (NAUTILUS_IS_FILE (file)); g_assert (file->details->directory == directory); - if (is_needy (file, lacks_info, wants_info) || - is_needy (file, lacks_slow_mime_type, wants_slow_mime_type)) { + if (is_needy (file, lacks_info, wants_info)) { return; } } @@ -2912,11 +3335,8 @@ file_info_start (NautilusDirectory *directory, NautilusFile *file, gboolean *doing_io) { - char *uri; - GnomeVFSURI *vfs_uri; - GList fake_list; - gboolean need_slow_mime; - GnomeVFSFileInfoOptions options; + GFile *location; + GetInfoState *state; file_info_stop (directory); @@ -2925,53 +3345,35 @@ file_info_start (NautilusDirectory *directory, return; } - if (!is_needy (file, lacks_info, wants_info) && - !is_needy (file, lacks_slow_mime_type, wants_slow_mime_type)) { + if (!is_needy (file, lacks_info, wants_info)) { return; } *doing_io = TRUE; - need_slow_mime = is_needy (file, always_lacks, wants_slow_mime_type); - - uri = nautilus_file_get_uri (file); - vfs_uri = gnome_vfs_uri_new (uri); - g_free (uri); - - /* If we can't even get info, fill in the info and go on. - */ - - if (vfs_uri == NULL) { - file->details->file_info_is_up_to_date = TRUE; - file->details->get_info_failed = TRUE; - file->details->get_info_error = GNOME_VFS_ERROR_INVALID_URI; - file->details->got_slow_mime_type = need_slow_mime; - - nautilus_directory_async_state_changed (directory); - return; - } - if (!async_job_start (directory, "file info")) { return; } + directory->details->get_info_file = file; file->details->get_info_failed = FALSE; - fake_list.data = vfs_uri; - fake_list.prev = NULL; - fake_list.next = NULL; - - options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS; - if (need_slow_mime) { - options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE; + if (file->details->get_info_error) { + g_error_free (file->details->get_info_error); + file->details->get_info_error = NULL; } - directory->details->get_info_has_slow_mime_type = need_slow_mime; - gnome_vfs_async_get_file_info - (&directory->details->get_info_in_progress, - &fake_list, - options, - GNOME_VFS_PRIORITY_DEFAULT, - get_info_callback, - directory); - gnome_vfs_uri_unref (vfs_uri); + + state = g_new (GetInfoState, 1); + state->directory = directory; + state->cancellable = g_cancellable_new (); + + directory->details->get_info_in_progress = state; + + location = nautilus_file_get_location (file); + g_file_query_info_async (location, + NAUTILUS_FILE_DEFAULT_ATTRIBUTES, + 0, + G_PRIORITY_DEFAULT, + state->cancellable, query_info_callback, state); + g_object_unref (location); } static void @@ -2979,40 +3381,23 @@ link_info_done (NautilusDirectory *directory, NautilusFile *file, const char *uri, const char *name, - const char *icon, - gulong drive_id, - gulong volume_id) + const char *icon) { - GnomeVFSVolumeMonitor *monitor; - GnomeVFSVolume *volume; - GnomeVFSDrive *drive; - file->details->link_info_is_up_to_date = TRUE; + nautilus_file_set_display_name (file, name, name, TRUE); + file->details->got_link_info = TRUE; - g_free (file->details->activation_uri); - g_free (file->details->display_name); g_free (file->details->custom_icon); - file->details->activation_uri = g_strdup (uri); - file->details->display_name = g_strdup (name); - file->details->custom_icon = g_strdup (icon); - nautilus_file_clear_cached_display_name (file); - - volume = NULL; - if (volume_id != 0) { - monitor = gnome_vfs_get_volume_monitor (); - volume = gnome_vfs_volume_monitor_get_volume_by_id (monitor, volume_id); - } - nautilus_file_set_volume (file, volume); - gnome_vfs_volume_unref (volume); - - drive = NULL; - if (drive_id != 0) { - monitor = gnome_vfs_get_volume_monitor (); - drive = gnome_vfs_volume_monitor_get_drive_by_id (monitor, drive_id); + if (uri) { + if (file->details->activation_location) { + g_object_unref (file->details->activation_location); + file->details->activation_location = NULL; + } + file->details->got_custom_activation_location = TRUE; + file->details->activation_location = g_file_new_for_uri (uri); } - nautilus_file_set_drive (file, drive); - gnome_vfs_drive_unref (drive); + file->details->custom_icon = g_strdup (icon); nautilus_directory_async_state_changed (directory); } @@ -3020,68 +3405,64 @@ link_info_done (NautilusDirectory *directory, static gboolean should_read_link_info_sync (NautilusFile *file) { - return (nautilus_file_is_local (file) && - !nautilus_file_is_directory (file)); +#ifdef READ_LOCAL_LINKS_SYNC + return (nautilus_file_is_local (file) && !nautilus_file_is_directory (file)); +#else + return FALSE; +#endif } static void -link_info_read_done (NautilusDirectory *directory, - const char *uri, - const char *name, - const char *icon, - gulong drive_id, - gulong volume_id) +link_info_stop (NautilusDirectory *directory) { NautilusFile *file; - file = directory->details->link_info_read_state->file; - g_free (directory->details->link_info_read_state); - directory->details->link_info_read_state = NULL; + if (directory->details->link_info_read_state != NULL) { + file = directory->details->link_info_read_state->file; - nautilus_file_ref (file); - link_info_done (directory, file, uri, name, icon, drive_id, volume_id); - nautilus_file_changed (file); + if (file != NULL) { + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (file->details->directory == directory); + if (is_needy (file, + lacks_link_info, + wants_link_info)) { + return; + } + } - if (!should_read_link_info_sync (file)) { - async_job_end (directory, "link info"); + /* The link info is not wanted, so stop it. */ + link_info_cancel (directory); } - - nautilus_file_unref (file); } - static void -link_info_nautilus_link_read_callback (GnomeVFSResult result, - GnomeVFSFileSize bytes_read, - char *file_contents, - gpointer callback_data) +link_info_got_data (NautilusDirectory *directory, + NautilusFile *file, + gboolean result, + goffset bytes_read, + char *file_contents) { - NautilusDirectory *directory; - char *buffer, *uri, *name, *icon; - gulong drive_id, volume_id; - - directory = NAUTILUS_DIRECTORY (callback_data); + char *uri, *name, *icon; nautilus_directory_ref (directory); + uri = NULL; + name = NULL; + icon = NULL; + /* Handle the case where we read the Nautilus link. */ - if (result != GNOME_VFS_OK) { - /* FIXME bugzilla.gnome.org 42433: We should report this error to the user. */ - g_free (file_contents); - uri = NULL; - name = NULL; - icon = NULL; - volume_id = drive_id = 0; + if (result) { + nautilus_link_get_link_info_given_file_contents (file_contents, bytes_read, + &uri, &name, &icon); } else { - /* The libxml parser requires a zero-terminated array. */ - buffer = g_realloc (file_contents, bytes_read + 1); - buffer[bytes_read] = '\0'; - nautilus_link_get_link_info_given_file_contents (buffer, bytes_read, - &uri, &name, &icon, &drive_id, &volume_id); - g_free (buffer); + /* FIXME bugzilla.gnome.org 42433: We should report this error to the user. */ } - link_info_read_done (directory, uri, name, icon, drive_id, volume_id); + nautilus_file_ref (file); + link_info_done (directory, file, uri, name, icon); + nautilus_file_changed (file); + nautilus_file_unref (file); + g_free (uri); g_free (name); g_free (icon); @@ -3090,39 +3471,61 @@ link_info_nautilus_link_read_callback (GnomeVFSResult result, } static void -link_info_stop (NautilusDirectory *directory) +link_info_read_state_free (LinkInfoReadState *state) { - NautilusFile *file; + g_object_unref (state->cancellable); + g_free (state); +} - if (directory->details->link_info_read_state != NULL) { - file = directory->details->link_info_read_state->file; +static void +link_info_nautilus_link_read_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + LinkInfoReadState *state; + gsize file_size; + char *file_contents; + gboolean result; + NautilusDirectory *directory; - if (file != NULL) { - g_assert (NAUTILUS_IS_FILE (file)); - g_assert (file->details->directory == directory); - if (is_needy (file, - lacks_link_info, - wants_link_info)) { - return; - } - } + state = user_data; - /* The link info is not wanted, so stop it. */ - link_info_cancel (directory); + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + link_info_read_state_free (state); + return; } -} + directory = nautilus_directory_ref (state->directory); + + result = g_file_load_contents_finish (G_FILE (source_object), + res, + &file_contents, &file_size, + NULL, NULL); + + state->directory->details->link_info_read_state = NULL; + async_job_end (state->directory, "link info"); + + link_info_got_data (state->directory, state->file, result, file_size, file_contents); + + g_free (file_contents); + + link_info_read_state_free (state); + + nautilus_directory_unref (directory); +} static void link_info_start (NautilusDirectory *directory, NautilusFile *file, gboolean *doing_io) { - char *uri; + GFile *location; gboolean nautilus_style_link; - int file_size; + gsize file_size; char *file_contents; - GnomeVFSResult result; + gboolean result; + LinkInfoReadState *state; if (directory->details->link_info_read_state != NULL) { *doing_io = TRUE; @@ -3138,39 +3541,246 @@ link_info_start (NautilusDirectory *directory, /* Figure out if it is a link. */ nautilus_style_link = nautilus_file_is_nautilus_link (file); - uri = nautilus_file_get_uri (file); + location = nautilus_file_get_location (file); /* If it's not a link we are done. If it is, we need to read it. */ if (!nautilus_style_link) { - link_info_done (directory, file, NULL, NULL, NULL, 0, 0); + link_info_done (directory, file, NULL, NULL, NULL); } else if (should_read_link_info_sync (file)) { - directory->details->link_info_read_state = g_new0 (LinkInfoReadState, 1); - directory->details->link_info_read_state->file = file; - - result = eel_read_entire_file (uri, &file_size, &file_contents); - link_info_nautilus_link_read_callback (result, file_size, file_contents, directory); - - /* We don't have to free file_contents here - * because it's done in the callback function - */ + result = g_file_load_contents (location, NULL, &file_contents, &file_size, NULL, NULL); + link_info_got_data (directory, file, result, file_size, file_contents); + g_free (file_contents); } else { if (!async_job_start (directory, "link info")) { - g_free (uri); + g_object_unref (location); return; } - directory->details->link_info_read_state = g_new0 (LinkInfoReadState, 1); - directory->details->link_info_read_state->file = file; - directory->details->link_info_read_state->handle = eel_read_entire_file_async - (uri, - GNOME_VFS_PRIORITY_DEFAULT, - link_info_nautilus_link_read_callback, - directory); + state = g_new0 (LinkInfoReadState, 1); + state->directory = directory; + state->file = file; + state->cancellable = g_cancellable_new (); + + directory->details->link_info_read_state = state; + + g_file_load_contents_async (location, + state->cancellable, + link_info_nautilus_link_read_callback, + state); } - g_free (uri); + g_object_unref (location); +} + +static void +thumbnail_done (NautilusDirectory *directory, + NautilusFile *file, + GdkPixbuf *pixbuf, + gboolean tried_original) +{ + file->details->thumbnail_is_up_to_date = TRUE; + file->details->thumbnail_tried_original = tried_original; + if (file->details->thumbnail) { + g_object_unref (file->details->thumbnail); + file->details->thumbnail = NULL; + } + file->details->thumbnail_size = 0; + if (pixbuf) { + file->details->thumbnail = g_object_ref (pixbuf); + } + + nautilus_directory_async_state_changed (directory); +} + +static void +thumbnail_stop (NautilusDirectory *directory) +{ + NautilusFile *file; + + if (directory->details->thumbnail_state != NULL) { + file = directory->details->thumbnail_state->file; + + if (file != NULL) { + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (file->details->directory == directory); + if (is_needy (file, + lacks_thumbnail, + wants_thumbnail)) { + return; + } + } + + /* The link info is not wanted, so stop it. */ + thumbnail_cancel (directory); + } +} + +static void +thumbnail_got_pixbuf (NautilusDirectory *directory, + NautilusFile *file, + GdkPixbuf *pixbuf, + gboolean tried_original) +{ + nautilus_directory_ref (directory); + + nautilus_file_ref (file); + thumbnail_done (directory, file, pixbuf, tried_original); + nautilus_file_changed (file); + nautilus_file_unref (file); + + if (pixbuf) { + g_object_unref (pixbuf); + } + + nautilus_directory_unref (directory); } static void +thumbnail_state_free (ThumbnailState *state) +{ + g_object_unref (state->cancellable); + g_free (state); +} + +static GdkPixbuf * +get_pixbuf_for_content (goffset file_len, + char *file_contents) +{ + gboolean res; + GdkPixbuf *pixbuf, *pixbuf2; + GdkPixbufLoader *loader; + gsize chunk_len; + pixbuf = NULL; + + loader = gdk_pixbuf_loader_new (); + + /* For some reason we have to write in chunks, or gdk-pixbuf fails */ + res = TRUE; + while (res && file_len > 0) { + chunk_len = MIN (32*1024, file_len); + res = gdk_pixbuf_loader_write (loader, file_contents, chunk_len, NULL); + file_contents += chunk_len; + file_len -= chunk_len; + } + if (res) { + res = gdk_pixbuf_loader_close (loader, NULL); + } + if (res) { + pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader)); + } + g_object_unref (G_OBJECT (loader)); + + if (pixbuf) { + pixbuf2 = gdk_pixbuf_apply_embedded_orientation (pixbuf); + g_object_unref (pixbuf); + pixbuf = pixbuf2; + } + return pixbuf; +} + + +static void +thumbnail_read_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + ThumbnailState *state; + gsize file_size; + char *file_contents; + gboolean result; + NautilusDirectory *directory; + GdkPixbuf *pixbuf; + GFile *location; + + state = user_data; + + if (state->directory == NULL) { + /* Operation was cancelled. Bail out */ + thumbnail_state_free (state); + return; + } + + directory = nautilus_directory_ref (state->directory); + + result = g_file_load_contents_finish (G_FILE (source_object), + res, + &file_contents, &file_size, + NULL, NULL); + + pixbuf = NULL; + if (result) { + pixbuf = get_pixbuf_for_content (file_size, file_contents); + g_free (file_contents); + } + + if (pixbuf == NULL && state->trying_original) { + state->trying_original = FALSE; + + location = g_file_new_for_path (state->file->details->thumbnail_path); + g_file_load_contents_async (location, + state->cancellable, + thumbnail_read_callback, + state); + g_object_unref (location); + } else { + state->directory->details->thumbnail_state = NULL; + async_job_end (state->directory, "thumbnail"); + + thumbnail_got_pixbuf (state->directory, state->file, pixbuf, state->tried_original); + + thumbnail_state_free (state); + } + + nautilus_directory_unref (directory); +} + +static void +thumbnail_start (NautilusDirectory *directory, + NautilusFile *file, + gboolean *doing_io) +{ + GFile *location; + ThumbnailState *state; + + if (directory->details->thumbnail_state != NULL) { + *doing_io = TRUE; + return; + } + + if (!is_needy (file, + lacks_thumbnail, + wants_thumbnail)) { + return; + } + *doing_io = TRUE; + + if (!async_job_start (directory, "thumbnail")) { + return; + } + + state = g_new0 (ThumbnailState, 1); + state->directory = directory; + state->file = file; + state->cancellable = g_cancellable_new (); + + if (file->details->thumbnail_size > 128) { + state->tried_original = TRUE; + state->trying_original = TRUE; + location = nautilus_file_get_location (file); + } else { + location = g_file_new_for_path (file->details->thumbnail_path); + } + + directory->details->thumbnail_state = state; + + g_file_load_contents_async (location, + state->cancellable, + thumbnail_read_callback, + state); + g_object_unref (location); +} + + +static void extension_info_cancel (NautilusDirectory *directory) { if (directory->details->extension_info_in_progress != NULL) { @@ -3346,6 +3956,7 @@ start_or_stop_io (NautilusDirectory *directory) top_left_stop (directory); link_info_stop (directory); extension_info_stop (directory); + thumbnail_stop (directory); doing_io = FALSE; /* Take files that are all done off the queue. */ @@ -3372,6 +3983,7 @@ start_or_stop_io (NautilusDirectory *directory) deep_count_start (directory, file, &doing_io); mime_list_start (directory, file, &doing_io); top_left_start (directory, file, &doing_io); + thumbnail_start (directory, file, &doing_io); if (doing_io) { return; @@ -3441,6 +4053,7 @@ nautilus_directory_cancel (NautilusDirectory *directory) new_files_cancel (directory); top_left_cancel (directory); extension_info_cancel (directory); + thumbnail_cancel (directory); /* We aren't waiting for anything any more. */ if (waiting_directories != NULL) { @@ -3499,7 +4112,7 @@ cancel_file_info_for_file (NautilusDirectory *directory, static void cancel_link_info_for_file (NautilusDirectory *directory, - NautilusFile *file) + NautilusFile *file) { if (directory->details->link_info_read_state != NULL && directory->details->link_info_read_state->file == file) { @@ -3540,6 +4153,10 @@ cancel_loading_attributes (NautilusDirectory *directory, extension_info_cancel (directory); } + if (request.thumbnail) { + thumbnail_cancel (directory); + } + /* FIXME bugzilla.gnome.org 45064: implement cancelling metadata when we implement invalidating metadata */ |