summaryrefslogtreecommitdiff
path: root/libnautilus-extensions/nautilus-directory-async.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnautilus-extensions/nautilus-directory-async.c')
-rw-r--r--libnautilus-extensions/nautilus-directory-async.c3078
1 files changed, 0 insertions, 3078 deletions
diff --git a/libnautilus-extensions/nautilus-directory-async.c b/libnautilus-extensions/nautilus-directory-async.c
deleted file mode 100644
index 5d76ca8f3..000000000
--- a/libnautilus-extensions/nautilus-directory-async.c
+++ /dev/null
@@ -1,3078 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
-
- nautilus-directory-async.c: Nautilus directory model state machine.
-
- Copyright (C) 1999, 2000, 2001 Eazel, Inc.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-
- Author: Darin Adler <darin@eazel.com>
-*/
-
-#include <config.h>
-
-#include "nautilus-metafile.h"
-#include "nautilus-directory-metafile.h"
-#include "nautilus-directory-notify.h"
-#include "nautilus-directory-private.h"
-#include "nautilus-file-attributes.h"
-#include "nautilus-file-private.h"
-#include <eel/eel-glib-extensions.h>
-#include "nautilus-global-preferences.h"
-#include "nautilus-link.h"
-#include "nautilus-search-uri.h"
-#include <eel/eel-string.h>
-#include <ctype.h>
-#include <gnome-xml/parser.h>
-#include <gnome-xml/xmlmemory.h>
-#include <gtk/gtkmain.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-/* turn this on to see messages about each load_directory call: */
-#if 0
-#define DEBUG_LOAD_DIRECTORY
-#endif
-
-/* turn this on to check if async. job calls are balanced */
-#if 0
-#define DEBUG_ASYNC_JOBS
-#endif
-
-/* turn this on to log things starting and stopping */
-#if 0
-#define DEBUG_START_STOP
-#endif
-
-
-#define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 32
-
-/* Keep async. jobs down to this number for all directories. */
-#define MAX_ASYNC_JOBS 10
-
-struct TopLeftTextReadState {
- NautilusFile *file;
- EelReadFileHandle *handle;
-};
-
-struct ActivationURIReadState {
- NautilusFile *file;
- EelReadFileHandle *handle;
-};
-
-typedef struct {
- NautilusFile *file; /* Which file, NULL means all. */
- union {
- NautilusDirectoryCallback directory;
- NautilusFileCallback file;
- } callback;
- gpointer callback_data;
- Request request;
-} ReadyCallback;
-
-typedef struct {
- NautilusFile *file; /* Which file, NULL means all. */
- gboolean monitor_hidden_files; /* defines whether "all" includes hidden files */
- gboolean monitor_backup_files; /* defines whether "all" includes backup files */
- gconstpointer client;
- Request request;
-} Monitor;
-
-typedef gboolean (* RequestCheck) (const Request *);
-typedef gboolean (* FileCheck) (NautilusFile *);
-
-/* Current number of async. jobs. */
-static int async_job_count;
-static GHashTable *waiting_directories;
-#ifdef DEBUG_ASYNC_JOBS
-static GHashTable *async_jobs;
-#endif
-
-/* 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,
- GList *file_attributes);
-
-/* Some helpers for case-insensitive strings.
- * Move to nautilus-glib-extensions?
- */
-
-static gboolean
-istr_equal (gconstpointer v, gconstpointer v2)
-{
- return g_strcasecmp (v, v2) == 0;
-}
-
-static guint
-istr_hash (gconstpointer key)
-{
- const char *p;
- guint h;
-
- h = 0;
- for (p = key; *p != '\0'; p++) {
- h = (h << 5) - h + tolower ((guchar) *p);
- }
-
- return h;
-}
-
-static GHashTable *
-istr_set_new (void)
-{
- return g_hash_table_new (istr_hash, istr_equal);
-}
-
-static void
-istr_set_insert (GHashTable *table, const char *istr)
-{
- char *key;
-
- if (g_hash_table_lookup (table, istr) == NULL) {
- key = g_strdup (istr);
- g_hash_table_insert (table, key, key);
- }
-}
-
-static void
-add_istr_to_list (gpointer key, gpointer value, gpointer callback_data)
-{
- GList **list;
-
- list = callback_data;
- *list = g_list_prepend (*list, g_strdup (key));
-}
-
-static GList *
-istr_set_get_as_list (GHashTable *table)
-{
- GList *list;
-
- list = NULL;
- g_hash_table_foreach (table, add_istr_to_list, &list);
- return list;
-}
-
-static void
-istr_set_destroy (GHashTable *table)
-{
- eel_g_hash_table_destroy_deep (table);
-}
-
-/* Start a job. This is really just a way of limiting the number of
- * async. requests that we issue at any given time. Without this, the
- * number of requests is unbounded.
- */
-static gboolean
-async_job_start (NautilusDirectory *directory,
- const char *job)
-{
-#ifdef DEBUG_ASYNC_JOBS
- char *key;
-#endif
-
-#ifdef DEBUG_START_STOP
- g_message ("starting %s in %s", job, directory->details->uri);
-#endif
-
- g_assert (async_job_count >= 0);
- g_assert (async_job_count <= MAX_ASYNC_JOBS);
-
- if (async_job_count >= MAX_ASYNC_JOBS) {
- if (waiting_directories == NULL) {
- waiting_directories = eel_g_hash_table_new_free_at_exit
- (NULL, NULL,
- "nautilus-directory-async.c: waiting_directories");
- }
-
- g_hash_table_insert (waiting_directories,
- directory,
- directory);
-
- return FALSE;
- }
-
-#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);
-#endif
-
- async_job_count += 1;
- return TRUE;
-}
-
-/* End a job. */
-static void
-async_job_end (NautilusDirectory *directory,
- const char *job)
-{
-#ifdef DEBUG_ASYNC_JOBS
- char *key;
- gpointer table_key, value;
-#endif
-
-#ifdef DEBUG_START_STOP
- g_message ("stopping %s in %s", job, directory->details->uri);
-#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);
- }
- g_free (key);
-#endif
-
- async_job_count -= 1;
-}
-
-/* Helper to get one value from a hash table. */
-static void
-get_one_value_callback (gpointer key, gpointer value, gpointer callback_data)
-{
- gpointer *returned_value;
-
- returned_value = callback_data;
- *returned_value = value;
-}
-
-/* return a single value from a hash table. */
-static gpointer
-get_one_value (GHashTable *table)
-{
- gpointer value;
-
- value = NULL;
- if (table != NULL) {
- g_hash_table_foreach (table, get_one_value_callback, &value);
- }
- return value;
-}
-
-/* Wake up directories that are "blocked" as long as there are job
- * slots available.
- */
-static void
-async_job_wake_up (void)
-{
- static gboolean already_waking_up = FALSE;
- gpointer value;
-
- g_assert (async_job_count >= 0);
- g_assert (async_job_count <= MAX_ASYNC_JOBS);
-
- if (already_waking_up) {
- return;
- }
-
- already_waking_up = TRUE;
- while (async_job_count < MAX_ASYNC_JOBS) {
- value = get_one_value (waiting_directories);
- if (value == NULL) {
- break;
- }
- g_hash_table_remove (waiting_directories, value);
- nautilus_directory_async_state_changed
- (NAUTILUS_DIRECTORY (value));
- }
- already_waking_up = FALSE;
-}
-
-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;
- directory->details->count_in_progress = NULL;
-
- async_job_end (directory, "directory count");
- }
-}
-
-static void
-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);
-
- 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 = 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;
-
- async_job_end (directory, "deep count");
- }
-}
-
-static void
-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;
- directory->details->mime_list_in_progress = NULL;
- directory->details->mime_list_hash = NULL;
-
- async_job_end (directory, "MIME list");
- }
-}
-
-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);
- directory->details->top_left_read_state = NULL;
-
- async_job_end (directory, "top left");
- }
-}
-
-static void
-activation_uri_cancel (NautilusDirectory *directory)
-{
- if (directory->details->activation_uri_read_state != NULL) {
- eel_read_file_cancel (directory->details->activation_uri_read_state->handle);
- g_free (directory->details->activation_uri_read_state);
- directory->details->activation_uri_read_state = NULL;
-
- async_job_end (directory, "activation URI");
- }
-}
-
-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;
- directory->details->get_info_in_progress = NULL;
-
- async_job_end (directory, "file info");
- }
-}
-
-static int
-monitor_key_compare (gconstpointer a,
- gconstpointer data)
-{
- const Monitor *monitor;
- const Monitor *compare_monitor;
-
- monitor = a;
- compare_monitor = data;
-
- if (monitor->client < compare_monitor->client) {
- return -1;
- }
- if (monitor->client > compare_monitor->client) {
- return +1;
- }
-
- if (monitor->file < compare_monitor->file) {
- return -1;
- }
- if (monitor->file > compare_monitor->file) {
- return +1;
- }
-
- return 0;
-}
-
-static GList *
-find_monitor (NautilusDirectory *directory,
- NautilusFile *file,
- gconstpointer client)
-{
- Monitor monitor;
-
- monitor.client = client;
- monitor.file = file;
-
- return g_list_find_custom (directory->details->monitor_list,
- &monitor,
- monitor_key_compare);
-}
-
-static int
-monitor_file_compare (gconstpointer a,
- gconstpointer data)
-{
- const Monitor *monitor;
- NautilusFile *file;
-
- monitor = a;
- file = (NautilusFile *) data;
-
- if (monitor->file < file) {
- return -1;
- }
- if (monitor->file > file) {
- return +1;
- }
-
- return 0;
-}
-
-static gboolean
-find_any_monitor (NautilusDirectory *directory,
- NautilusFile *file)
-{
- return g_list_find_custom (directory->details->monitor_list,
- file,
- monitor_file_compare) != NULL;
-}
-
-static void
-remove_monitor_link (NautilusDirectory *directory,
- GList *link)
-{
- if (link != NULL) {
- directory->details->monitor_list =
- g_list_remove_link (directory->details->monitor_list, link);
- g_free (link->data);
- g_list_free_1 (link);
- }
-}
-
-static void
-remove_monitor (NautilusDirectory *directory,
- NautilusFile *file,
- gconstpointer client)
-{
- remove_monitor_link (directory, find_monitor (directory, file, client));
-}
-
-void
-nautilus_directory_set_up_request (Request *request,
- GList *file_attributes)
-{
- memset (request, 0, sizeof (*request));
-
- request->directory_count = g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT,
- eel_strcmp_compare_func) != NULL;
- request->deep_count = g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS,
- eel_strcmp_compare_func) != NULL;
- request->mime_list = g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES,
- eel_strcmp_compare_func) != NULL;
- request->file_info = g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_MIME_TYPE,
- eel_strcmp_compare_func) != NULL;
- request->file_info |= g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_IS_DIRECTORY,
- eel_strcmp_compare_func) != NULL;
- request->file_info |= g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES,
- eel_strcmp_compare_func) != NULL;
- request->file_info |= g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_FILE_TYPE,
- eel_strcmp_compare_func) != NULL;
-
- if (g_list_find_custom (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT,
- eel_strcmp_compare_func) != NULL) {
- request->top_left_text = TRUE;
- request->file_info = TRUE;
- }
-
- if (g_list_find_custom (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI,
- eel_strcmp_compare_func) != NULL) {
- request->file_info = TRUE;
- request->activation_uri = TRUE;
- }
-
- request->metafile |= g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_METADATA,
- eel_strcmp_compare_func) != NULL;
-
- /* FIXME bugzilla.eazel.com 2435:
- * 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).
- */
- request->metafile |= g_list_find_custom
- (file_attributes,
- NAUTILUS_FILE_ATTRIBUTE_CUSTOM_ICON,
- eel_strcmp_compare_func) != NULL;
-}
-
-static gboolean
-is_tentative (gpointer data, gpointer callback_data)
-{
- NautilusFile *file;
-
- g_assert (callback_data == NULL);
-
- file = NAUTILUS_FILE (data);
- return file->details->info == NULL;
-}
-
-static GList *
-get_non_tentative_file_list (NautilusDirectory *directory)
-{
- GList *tentative_files, *non_tentative_files;
-
- tentative_files = eel_g_list_partition
- (g_list_copy (directory->details->file_list),
- is_tentative, NULL, &non_tentative_files);
- g_list_free (tentative_files);
-
- nautilus_file_list_ref (non_tentative_files);
- return non_tentative_files;
-}
-
-void
-nautilus_directory_monitor_add_internal (NautilusDirectory *directory,
- NautilusFile *file,
- gconstpointer client,
- gboolean monitor_hidden_files,
- gboolean monitor_backup_files,
- GList *file_attributes)
-{
- Monitor *monitor;
- GList *file_list;
- char *file_uri;
-
- g_assert (NAUTILUS_IS_DIRECTORY (directory));
-
- /* Replace any current monitor for this client/file pair. */
- remove_monitor (directory, file, client);
-
- /* Add the new monitor. */
- monitor = g_new (Monitor, 1);
- monitor->file = file;
- monitor->monitor_hidden_files = monitor_hidden_files;
- monitor->monitor_backup_files = monitor_backup_files;
- monitor->client = client;
- nautilus_directory_set_up_request (&monitor->request, file_attributes);
-
- monitor->request.file_list = file == NULL;
- directory->details->monitor_list =
- g_list_prepend (directory->details->monitor_list, monitor);
-
- /* Re-send the "files_added" signal for this set of files.
- * Old monitorers already know about them, but it's harmless
- * to hear about the same files again.
- */
- if (file == NULL) {
- file_list = get_non_tentative_file_list (directory);
- if (file_list != NULL) {
- nautilus_directory_emit_files_added
- (directory, file_list);
- nautilus_file_list_free (file_list);
- }
- }
-
- /* Start the "real" monitoring (FAM or whatever). */
- if (file == NULL) {
- if (directory->details->monitor == NULL) {
- directory->details->monitor = nautilus_monitor_directory (directory->details->uri);
- }
- } else {
- if (file->details->monitor == NULL) {
- file_uri = nautilus_file_get_uri (file);
- file->details->monitor = nautilus_monitor_file (file_uri);
- g_free (file_uri);
- }
- }
-
- /* We could just call update_metadata_monitors here, but we can be smarter
- * since we know what monitor was just added.
- */
- if (monitor->request.metafile && directory->details->metafile_monitor == NULL) {
- nautilus_directory_register_metadata_monitor (directory);
- }
-
- /* Kick off I/O. */
- nautilus_directory_async_state_changed (directory);
-}
-
-static void
-set_file_unconfirmed (NautilusFile *file, gboolean unconfirmed)
-{
- NautilusDirectory *directory;
-
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (unconfirmed == FALSE || unconfirmed == TRUE);
-
- if (file->details->unconfirmed == unconfirmed) {
- return;
- }
- file->details->unconfirmed = unconfirmed;
-
- directory = file->details->directory;
- if (unconfirmed) {
- directory->details->confirmed_file_count--;
- } else {
- directory->details->confirmed_file_count++;
- }
-}
-
-static gboolean show_hidden_files = TRUE;
-static gboolean show_backup_files = TRUE;
-
-static void
-show_hidden_files_changed_callback (gpointer callback_data)
-{
- show_hidden_files = nautilus_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES);
-}
-
-static void
-show_backup_files_changed_callback (gpointer callback_data)
-{
- show_backup_files = nautilus_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_BACKUP_FILES);
-}
-
-static GnomeVFSDirectoryFilterOptions
-get_filter_options_for_directory_count (void)
-{
- static gboolean show_hidden_files_changed_callback_installed = FALSE;
- static gboolean show_backup_files_changed_callback_installed = FALSE;
- GnomeVFSDirectoryFilterOptions filter_options;
-
- filter_options = GNOME_VFS_DIRECTORY_FILTER_NOSELFDIR
- | GNOME_VFS_DIRECTORY_FILTER_NOPARENTDIR;
-
- /* Add the callback once for the life of our process */
- if (!show_hidden_files_changed_callback_installed) {
- nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES,
- show_hidden_files_changed_callback,
- NULL);
- show_hidden_files_changed_callback_installed = TRUE;
-
- /* Peek for the first time */
- show_hidden_files_changed_callback (NULL);
- }
-
- /* Add the callback once for the life of our process */
- if (!show_backup_files_changed_callback_installed) {
- nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_BACKUP_FILES,
- show_backup_files_changed_callback,
- NULL);
- show_backup_files_changed_callback_installed = TRUE;
-
- /* Peek for the first time */
- show_backup_files_changed_callback (NULL);
- }
-
- if (!show_hidden_files) {
- filter_options |= GNOME_VFS_DIRECTORY_FILTER_NODOTFILES;
- }
- if (!show_backup_files) {
- filter_options |= GNOME_VFS_DIRECTORY_FILTER_NOBACKUPFILES;
- }
-
- return filter_options;
-}
-
-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);
- }
-
- gnome_vfs_directory_filter_destroy (directory->details->load_file_count_filter);
- directory->details->load_file_count_filter = NULL;
-}
-
-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)
-{
- NautilusDirectory *directory;
- GList *pending_file_info;
- GList *node, *next;
- NautilusFile *file;
- GList *changed_files, *added_files;
- GnomeVFSFileInfo *file_info;
-
- directory = NAUTILUS_DIRECTORY (callback_data);
-
- nautilus_directory_ref (directory);
-
- directory->details->dequeue_pending_idle_id = 0;
-
- /* Handle the files in the order we saw them. */
- pending_file_info = g_list_reverse (directory->details->pending_file_info);
- directory->details->pending_file_info = NULL;
-
- /* If we are no longer monitoring, then throw away these. */
- if (!nautilus_directory_is_file_list_monitored (directory)) {
- load_directory_done (directory);
- goto drain;
- }
-
- added_files = NULL;
- changed_files = NULL;
-
- /* Build a list of NautilusFile objects. */
- for (node = pending_file_info; node != NULL; node = node->next) {
- file_info = node->data;
-
- /* Update the file count. */
- /* FIXME bugzilla.eazel.com 5063: This could count a file twice if we get it
- * from both load_directory and from
- * new_files_callback. Not too hard to fix by moving
- * this into the actual callback instead of waiting
- * for the idle function.
- */
- if (gnome_vfs_directory_filter_apply (directory->details->load_file_count_filter,
- file_info)) {
- directory->details->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);
- }
-
- /* check if the file already exists */
- file = nautilus_directory_find_file_by_name (directory, file_info->name);
- if (file != NULL) {
- /* file already exists, check if it changed */
- set_file_unconfirmed (file, FALSE);
- 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);
- }
- nautilus_file_ref (file);
- } else {
- /* new file, create a nautilus file object and add it to the list */
- file = nautilus_file_new_from_info (directory, file_info);
- nautilus_directory_add_file (directory, file);
- }
- added_files = g_list_prepend (added_files, file);
- }
-
- /* If we are done loading, then we assume that any unconfirmed
- * files are gone.
- */
- if (directory->details->directory_loaded) {
- for (node = directory->details->file_list;
- node != NULL; node = next) {
- file = NAUTILUS_FILE (node->data);
- next = node->next;
-
- if (file->details->unconfirmed) {
- nautilus_file_ref (file);
- changed_files = g_list_prepend (changed_files, file);
-
- file->details->is_gone = TRUE;
- nautilus_directory_remove_file (directory, file);
- }
- }
- }
-
- /* Send the changed and added signals. */
- nautilus_directory_emit_change_signals (directory, changed_files);
- nautilus_file_list_free (changed_files);
- 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) {
- /* Send the done_loading signal. */
- nautilus_directory_emit_done_loading (directory);
-
- file = directory->details->load_directory_file;
-
- if (file != NULL) {
- 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;
- file->details->mime_list = istr_set_get_as_list
- (directory->details->load_mime_list_hash);
-
- nautilus_file_changed (file);
- }
-
- load_directory_done (directory);
-
- directory->details->directory_loaded_sent_notification = TRUE;
- }
-
- drain:
- gnome_vfs_file_info_list_free (pending_file_info);
-
- /* Get the state machine running again. */
- nautilus_directory_async_state_changed (directory);
-
- nautilus_directory_unref (directory);
- return FALSE;
-}
-
-void
-nautilus_directory_schedule_dequeue_pending (NautilusDirectory *directory)
-{
- if (directory->details->dequeue_pending_idle_id == 0) {
- directory->details->dequeue_pending_idle_id
- = gtk_idle_add (dequeue_pending_idle_callback, directory);
- }
-}
-
-static void
-directory_load_one (NautilusDirectory *directory,
- GnomeVFSFileInfo *info)
-{
- if (info == NULL) {
- return;
- }
-
- /* Arrange for the "loading" part of the work. */
- gnome_vfs_file_info_ref (info);
- directory->details->pending_file_info
- = g_list_prepend (directory->details->pending_file_info, info);
- nautilus_directory_schedule_dequeue_pending (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);
- directory->details->directory_load_in_progress = NULL;
- async_job_end (directory, "file list");
- }
-}
-
-static void
-file_list_cancel (NautilusDirectory *directory)
-{
- directory_load_cancel (directory);
-
- if (directory->details->dequeue_pending_idle_id != 0) {
- gtk_idle_remove (directory->details->dequeue_pending_idle_id);
- directory->details->dequeue_pending_idle_id = 0;
- }
-
- if (directory->details->pending_file_info != NULL) {
- gnome_vfs_file_info_list_free (directory->details->pending_file_info);
- directory->details->pending_file_info = NULL;
- }
-
- load_directory_state_destroy (directory);
-}
-
-static void
-directory_load_done (NautilusDirectory *directory,
- GnomeVFSResult result)
-{
- 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) {
- /* 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
- * they won't be marked "gone" later -- we don't know enough
- * about them to know whether they are really gone.
- */
- for (node = directory->details->file_list;
- node != NULL; node = node->next) {
- set_file_unconfirmed (NAUTILUS_FILE (node->data), FALSE);
- }
-
- nautilus_directory_emit_load_error (directory,
- result);
- }
-
- /* Call the idle function right away. */
- if (directory->details->dequeue_pending_idle_id != 0) {
- gtk_idle_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);
-}
-
-/* This checks if there's a request for the metafile contents. */
-static gboolean
-is_anyone_waiting_for_metafile (NautilusDirectory *directory)
-{
- GList *node;
- ReadyCallback *callback;
- Monitor *monitor;
-
- for (node = directory->details->call_when_ready_list; node != NULL; node = node->next) {
- callback = node->data;
- if (callback->request.metafile) {
- return TRUE;
- }
- }
-
- for (node = directory->details->monitor_list; node != NULL; node = node->next) {
- monitor = node->data;
- if (monitor->request.metafile) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static void
-update_metadata_monitors (NautilusDirectory *directory)
-{
- gboolean is_metadata_monitored;
-
- is_metadata_monitored = is_anyone_waiting_for_metafile (directory);
-
- if (directory->details->metafile_monitor == NULL) {
- if (is_metadata_monitored) {
- nautilus_directory_register_metadata_monitor (directory);
- }
- } else {
- if (!is_metadata_monitored) {
- nautilus_directory_unregister_metadata_monitor (directory);
- }
- }
-}
-
-void
-nautilus_directory_monitor_remove_internal (NautilusDirectory *directory,
- NautilusFile *file,
- gconstpointer client)
-{
- g_assert (NAUTILUS_IS_DIRECTORY (directory));
- g_assert (file == NULL || NAUTILUS_IS_FILE (file));
- g_assert (client != NULL);
-
- remove_monitor (directory, file, client);
-
- if (file == NULL) {
- if (directory->details->monitor != NULL
- && !find_any_monitor (directory, NULL)) {
- nautilus_monitor_cancel (directory->details->monitor);
- directory->details->monitor = NULL;
- }
- } else {
- if (file->details->monitor != NULL
- && !find_any_monitor (directory, file)) {
- nautilus_monitor_cancel (file->details->monitor);
- file->details->monitor = NULL;
- }
- }
-
- update_metadata_monitors (directory);
-
- nautilus_directory_async_state_changed (directory);
-}
-
-FileMonitors *
-nautilus_directory_remove_file_monitors (NautilusDirectory *directory,
- NautilusFile *file)
-{
- GList *result, **list, *node, *next;
- Monitor *monitor;
-
- g_assert (NAUTILUS_IS_DIRECTORY (directory));
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (file->details->directory == directory);
-
- result = NULL;
-
- list = &directory->details->monitor_list;
- for (node = directory->details->monitor_list; node != NULL; node = next) {
- next = node->next;
- monitor = node->data;
-
- if (monitor->file == file) {
- *list = g_list_remove_link (*list, node);
- result = g_list_concat (node, result);
- }
- }
-
- update_metadata_monitors (directory);
- nautilus_directory_async_state_changed (directory);
-
- return (FileMonitors *) result;
-}
-
-void
-nautilus_directory_add_file_monitors (NautilusDirectory *directory,
- NautilusFile *file,
- FileMonitors *monitors)
-{
- GList **list;
-
- g_assert (NAUTILUS_IS_DIRECTORY (directory));
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (file->details->directory == directory);
-
- if (monitors == NULL) {
- return;
- }
-
- list = &directory->details->monitor_list;
- *list = g_list_concat (*list, (GList *) monitors);
-
- update_metadata_monitors (directory);
- nautilus_directory_async_state_changed (directory);
-}
-
-static int
-ready_callback_key_compare (gconstpointer a, gconstpointer b)
-{
- const ReadyCallback *callback_a, *callback_b;
-
- callback_a = a;
- callback_b = b;
- if (callback_a->file < callback_b->file) {
- return -1;
- }
- if (callback_a->file > callback_b->file) {
- return 1;
- }
- if (callback_a->file == NULL) {
- if (callback_a->callback.directory < callback_b->callback.directory) {
- return -1;
- }
- if (callback_a->callback.directory > callback_b->callback.directory) {
- return 1;
- }
- } else {
- if (callback_a->callback.file < callback_b->callback.file) {
- return -1;
- }
- if (callback_a->callback.file > callback_b->callback.file) {
- return 1;
- }
- }
- if (callback_a->callback_data < callback_b->callback_data) {
- return -1;
- }
- if (callback_a->callback_data > callback_b->callback_data) {
- return 1;
- }
- return 0;
-}
-
-static void
-ready_callback_call (NautilusDirectory *directory,
- const ReadyCallback *callback)
-{
- GList *file_list;
-
- /* Call the callback. */
- if (callback->file != NULL) {
- (* callback->callback.file) (callback->file,
- callback->callback_data);
- } else {
- if (directory == NULL || !callback->request.file_list) {
- file_list = NULL;
- } else {
- file_list = get_non_tentative_file_list (directory);
- }
-
- /* Pass back the file list if the user was waiting for it. */
- (* callback->callback.directory) (directory,
- file_list,
- callback->callback_data);
-
- nautilus_file_list_free (file_list);
- }
-}
-
-void
-nautilus_directory_call_when_ready_internal (NautilusDirectory *directory,
- NautilusFile *file,
- GList *file_attributes,
- NautilusDirectoryCallback directory_callback,
- NautilusFileCallback file_callback,
- gpointer callback_data)
-{
- ReadyCallback callback;
-
- g_assert (directory == NULL || NAUTILUS_IS_DIRECTORY (directory));
- g_assert (file == NULL || NAUTILUS_IS_FILE (file));
- g_assert (file != NULL || directory_callback != NULL);
- g_assert (file == NULL || file_callback != NULL);
-
- /* Construct a callback object. */
- callback.file = file;
- if (file == NULL) {
- callback.callback.directory = directory_callback;
- } else {
- callback.callback.file = file_callback;
- }
- callback.callback_data = callback_data;
- nautilus_directory_set_up_request (&callback.request, file_attributes);
- callback.request.file_list = file == NULL && file_attributes != NULL;
-
- /* Handle the NULL case. */
- if (directory == NULL) {
- ready_callback_call (NULL, &callback);
- return;
- }
-
- /* Check if the callback is already there. */
- if (g_list_find_custom (directory->details->call_when_ready_list,
- &callback,
- ready_callback_key_compare) != NULL) {
- g_warning ("tried to add a new callback while an old one was pending");
- return;
- }
-
- /* Add the new callback to the list. */
- directory->details->call_when_ready_list = g_list_prepend
- (directory->details->call_when_ready_list,
- g_memdup (&callback, sizeof (callback)));
-
- /* When we change the ready list we need to sync up metadata monitors.
- * We could just call update_metadata_monitors here, but we can be smarter
- * since we know what was just added.
- */
- if (callback.request.metafile && directory->details->metafile_monitor == NULL) {
- nautilus_directory_register_metadata_monitor (directory);
- }
-
- nautilus_directory_async_state_changed (directory);
-}
-
-gboolean
-nautilus_directory_check_if_ready_internal (NautilusDirectory *directory,
- NautilusFile *file,
- GList *file_attributes)
-{
- Request request;
-
- g_assert (NAUTILUS_IS_DIRECTORY (directory));
-
- nautilus_directory_set_up_request (&request, file_attributes);
- return request_is_satisfied (directory, file, &request);
-}
-
-static void
-remove_callback_link_keep_data (NautilusDirectory *directory,
- GList *link)
-{
- directory->details->call_when_ready_list = g_list_remove_link
- (directory->details->call_when_ready_list, link);
- g_list_free_1 (link);
-}
-
-static void
-remove_callback_link (NautilusDirectory *directory,
- GList *link)
-{
- g_free (link->data);
- remove_callback_link_keep_data (directory, link);
-}
-
-void
-nautilus_directory_cancel_callback_internal (NautilusDirectory *directory,
- NautilusFile *file,
- NautilusDirectoryCallback directory_callback,
- NautilusFileCallback file_callback,
- gpointer callback_data)
-{
- ReadyCallback callback;
- GList *node;
-
- if (directory == NULL) {
- return;
- }
-
- g_assert (NAUTILUS_IS_DIRECTORY (directory));
- g_assert (file == NULL || NAUTILUS_IS_FILE (file));
- g_assert (file != NULL || directory_callback != NULL);
- g_assert (file == NULL || file_callback != NULL);
-
- /* Construct a callback object. */
- callback.file = file;
- if (file == NULL) {
- callback.callback.directory = directory_callback;
- } else {
- callback.callback.file = file_callback;
- }
- callback.callback_data = callback_data;
-
- /* Remove queued callback from the list. */
- node = g_list_find_custom (directory->details->call_when_ready_list,
- &callback,
- ready_callback_key_compare);
- if (node != NULL) {
- remove_callback_link (directory, node);
- /* When we change the ready list we need to sync up metadata monitors. */
- update_metadata_monitors (directory);
-
- nautilus_directory_async_state_changed (directory);
- }
-}
-
-static void
-directory_count_callback (GnomeVFSAsyncHandle *handle,
- GnomeVFSResult result,
- GList *list,
- guint entries_read,
- gpointer callback_data)
-{
- NautilusDirectory *directory;
- NautilusFile *count_file;
-
- directory = NAUTILUS_DIRECTORY (callback_data);
-
- g_assert (directory->details->count_in_progress == handle);
- count_file = directory->details->count_file;
- g_assert (NAUTILUS_IS_FILE (count_file));
-
- if (result == GNOME_VFS_OK) {
- 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;
- } else {
- count_file->details->got_directory_count = TRUE;
- count_file->details->directory_count = entries_read;
- }
- 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);
- }
- }
-
- nautilus_directory_unref (directory);
-}
-
-void
-nautilus_directory_get_info_for_new_files (NautilusDirectory *directory,
- GList *vfs_uri_list)
-{
- GnomeVFSAsyncHandle *handle;
- gnome_vfs_async_get_file_info
- (&handle,
- vfs_uri_list,
- (GNOME_VFS_FILE_INFO_GET_MIME_TYPE
- | GNOME_VFS_FILE_INFO_FOLLOW_LINKS),
- new_files_callback,
- directory);
-
- directory->details->get_file_infos_in_progress
- = g_list_prepend (directory->details->get_file_infos_in_progress,
- handle);
-}
-
-void
-nautilus_async_destroying_file (NautilusFile *file)
-{
- NautilusDirectory *directory;
- gboolean changed;
- GList *node, *next;
- ReadyCallback *callback;
- Monitor *monitor;
-
- directory = file->details->directory;
- changed = FALSE;
-
- /* Check for callbacks. */
- for (node = directory->details->call_when_ready_list; node != NULL; node = next) {
- next = node->next;
- callback = node->data;
-
- if (callback->file == file) {
- /* Client should have cancelled callback. */
- g_warning ("destroyed file has call_when_ready pending");
- remove_callback_link (directory, node);
- changed = TRUE;
- }
- }
-
- /* Check for monitors. */
- for (node = directory->details->monitor_list; node != NULL; node = next) {
- next = node->next;
- monitor = node->data;
-
- if (monitor->file == file) {
- /* Client should have removed monitor earlier. */
- g_warning ("destroyed file still being monitored");
- remove_monitor_link (directory, node);
- changed = TRUE;
- }
- }
-
- /* When we change the monitor or ready list we need to sync up metadata monitors */
- if (changed) {
- update_metadata_monitors (directory);
- }
-
- /* Check if it's a file that's currently being worked on.
- * If so, make that NULL so it gets canceled right away.
- */
- if (directory->details->count_file == file) {
- directory->details->count_file = NULL;
- changed = TRUE;
- }
- if (directory->details->deep_count_file == file) {
- directory->details->deep_count_file = NULL;
- changed = TRUE;
- }
- if (directory->details->mime_list_file == file) {
- directory->details->mime_list_file = NULL;
- changed = TRUE;
- }
- if (directory->details->get_info_file == file) {
- directory->details->get_info_file = NULL;
- changed = TRUE;
- }
- if (directory->details->top_left_read_state != NULL
- && directory->details->top_left_read_state->file == file) {
- directory->details->top_left_read_state->file = NULL;
- changed = TRUE;
- }
- if (directory->details->activation_uri_read_state != NULL
- && directory->details->activation_uri_read_state->file == file) {
- directory->details->activation_uri_read_state->file = NULL;
- changed = TRUE;
- }
-
- /* Let the directory take care of the rest. */
- if (changed) {
- nautilus_directory_async_state_changed (directory);
- }
-}
-
-static gboolean
-lacks_directory_count (NautilusFile *file)
-{
- return nautilus_file_is_directory (file)
- && nautilus_file_should_show_directory_item_count (file)
- && !file->details->directory_count_is_up_to_date;
-}
-
-static gboolean
-should_get_directory_count_now (NautilusFile *file)
-{
- return lacks_directory_count (file)
- && !file->details->loading_directory;
-}
-
-static gboolean
-wants_directory_count (const Request *request)
-{
- return request->directory_count;
-}
-
-static gboolean
-lacks_top_left (NautilusFile *file)
-{
- return nautilus_file_should_get_top_left_text (file)
- && nautilus_file_contains_text (file)
- && !file->details->top_left_text_is_up_to_date;
-}
-
-static gboolean
-wants_top_left (const Request *request)
-{
- return request->top_left_text;
-}
-
-static gboolean
-lacks_info (NautilusFile *file)
-{
- return !file->details->file_info_is_up_to_date
- && !file->details->is_gone;
-}
-
-static gboolean
-wants_info (const Request *request)
-{
- return request->file_info;
-}
-
-static gboolean
-lacks_deep_count (NautilusFile *file)
-{
- return nautilus_file_is_directory (file)
- && file->details->deep_counts_status != NAUTILUS_REQUEST_DONE;
-}
-
-static gboolean
-wants_deep_count (const Request *request)
-{
- return request->deep_count;
-}
-
-static gboolean
-lacks_mime_list (NautilusFile *file)
-{
- return nautilus_file_is_directory (file)
- && !file->details->mime_list_is_up_to_date;
-}
-
-static gboolean
-should_get_mime_list (NautilusFile *file)
-{
- return lacks_mime_list (file)
- && !file->details->loading_directory;
-}
-
-static gboolean
-wants_mime_list (const Request *request)
-{
- return request->mime_list;
-}
-
-static gboolean
-lacks_activation_uri (NautilusFile *file)
-{
- return file->details->info != NULL
- && !file->details->activation_uri_is_up_to_date;
-}
-
-static gboolean
-wants_activation_uri (const Request *request)
-{
- return request->activation_uri;
-}
-
-
-static gboolean
-has_problem (NautilusDirectory *directory, NautilusFile *file, FileCheck problem)
-{
- GList *node;
-
- if (file != NULL) {
- return (* problem) (file);
- }
-
- for (node = directory->details->file_list; node != NULL; node = node->next) {
- if ((* problem) (node->data)) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static gboolean
-request_is_satisfied (NautilusDirectory *directory,
- NautilusFile *file,
- Request *request)
-{
- if (request->metafile && !nautilus_directory_is_metadata_read (directory)) {
- return FALSE;
- }
-
- if (request->file_list && !(directory->details->directory_loaded &&
- directory->details->directory_loaded_sent_notification)) {
- return FALSE;
- }
-
- if (request->directory_count) {
- if (has_problem (directory, file, lacks_directory_count)) {
- return FALSE;
- }
- }
-
- if (request->file_info) {
- if (has_problem (directory, file, lacks_info)) {
- return FALSE;
- }
- }
-
- if (request->top_left_text) {
- if (has_problem (directory, file, lacks_top_left)) {
- return FALSE;
- }
- }
-
- if (request->deep_count) {
- if (has_problem (directory, file, lacks_deep_count)) {
- return FALSE;
- }
- }
-
- if (request->mime_list) {
- if (has_problem (directory, file, lacks_mime_list)) {
- return FALSE;
- }
- }
-
- if (request->activation_uri) {
- if (has_problem (directory, file, lacks_activation_uri)) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static gboolean
-call_ready_callbacks (NautilusDirectory *directory)
-{
- gboolean called_any;
- GList *node, *next;
- ReadyCallback *callback;
-
- callback = NULL;
- called_any = FALSE;
- while (1) {
- /* Check if any callbacks are satisifed and call them if they are. */
- for (node = directory->details->call_when_ready_list;
- node != NULL; node = next) {
- next = node->next;
- callback = node->data;
- if (request_is_satisfied (directory, callback->file, &callback->request)) {
- break;
- }
- }
- if (node == NULL) {
- if (called_any) {
- /* When we change the ready list we need to sync up metadata monitors. */
- update_metadata_monitors (directory);
- }
- return called_any;
- }
-
- /* Callbacks are one-shots, so remove it now. */
- remove_callback_link_keep_data (directory, node);
-
- /* Call the callback. */
- ready_callback_call (directory, callback);
- g_free (callback);
- called_any = TRUE;
- }
-}
-
-/* This checks if there's a request for monitoring the file list. */
-gboolean
-nautilus_directory_is_anyone_monitoring_file_list (NautilusDirectory *directory)
-{
- GList *node;
- ReadyCallback *callback;
- Monitor *monitor;
-
- for (node = directory->details->call_when_ready_list;
- node != NULL; node = node->next) {
- callback = node->data;
- if (callback->request.file_list) {
- return TRUE;
- }
- }
-
- for (node = directory->details->monitor_list;
- node != NULL; node = node->next) {
- monitor = node->data;
- if (monitor->request.file_list) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/* This checks if the file list being monitored. */
-gboolean
-nautilus_directory_is_file_list_monitored (NautilusDirectory *directory)
-{
- return directory->details->file_list_monitored;
-}
-
-static void
-mark_all_files_unconfirmed (NautilusDirectory *directory)
-{
- GList *node;
- NautilusFile *file;
-
- for (node = directory->details->file_list; node != NULL; node = node->next) {
- file = node->data;
- set_file_unconfirmed (file, TRUE);
- }
-}
-
-static gboolean
-should_display_file_name (const char *name,
- GnomeVFSDirectoryFilterOptions options)
-{
- /* Note that the name is URI-encoded, but this should not
- * affect the . or the ~.
- */
-
- if ((options & GNOME_VFS_DIRECTORY_FILTER_NODOTFILES) != 0
- && nautilus_file_name_matches_hidden_pattern (name)) {
- return FALSE;
- }
-
- if ((options & GNOME_VFS_DIRECTORY_FILTER_NOBACKUPFILES) != 0
- && nautilus_file_name_matches_backup_pattern (name)) {
- return FALSE;
- }
-
- /* Note that we don't bother to check for "." or ".." here, because
- * this function is used only for search results, which never include
- * those special files. If we later use this function more generally,
- * we might have to change this.
- */
- return TRUE;
-}
-
-/* Filter search results based on user preferences. This must be done
- * differently than filtering other files because the search results
- * are encoded: the entire file path is encoded and stored as the file
- * name.
- */
-static gboolean
-filter_search_uri (const GnomeVFSFileInfo *info, gpointer data)
-{
- GnomeVFSDirectoryFilterOptions options;
- char *real_file_uri;
- gboolean result;
-
- options = GPOINTER_TO_INT (data);
-
- real_file_uri = nautilus_get_target_uri_from_search_result_name (info->name);
- result = should_display_file_name (g_basename (real_file_uri), options);
- g_free (real_file_uri);
-
- return result;
-}
-
-static GnomeVFSDirectoryFilter *
-get_file_count_filter (NautilusDirectory *directory)
-{
- if (nautilus_is_search_uri (directory->details->uri)) {
- return gnome_vfs_directory_filter_new_custom
- (filter_search_uri,
- GNOME_VFS_DIRECTORY_FILTER_NEEDS_NAME,
- GINT_TO_POINTER (get_filter_options_for_directory_count ()));
- }
-
- return gnome_vfs_directory_filter_new
- (GNOME_VFS_DIRECTORY_FILTER_NONE,
- get_filter_options_for_directory_count (),
- NULL);
-}
-
-/* Start monitoring the file list if it isn't already. */
-static void
-start_monitoring_file_list (NautilusDirectory *directory)
-{
- if (!directory->details->file_list_monitored) {
- g_assert (directory->details->directory_load_in_progress == NULL);
- 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) {
- return;
- }
-
- if (!async_job_start (directory, "file list")) {
- return;
- }
-
- mark_all_files_unconfirmed (directory);
-
- g_assert (directory->details->uri != NULL);
- directory->details->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_file_count_filter = get_file_count_filter (directory);
- directory->details->load_mime_list_hash = istr_set_new ();
-#ifdef DEBUG_LOAD_DIRECTORY
- g_message ("load_directory called to monitor file list of %s", directory->details->uri);
-#endif
- gnome_vfs_async_load_directory
- (&directory->details->directory_load_in_progress, /* handle */
- directory->details->uri, /* uri */
- (GNOME_VFS_FILE_INFO_GET_MIME_TYPE /* options */
- | GNOME_VFS_FILE_INFO_FOLLOW_LINKS),
- GNOME_VFS_DIRECTORY_FILTER_NONE, /* filter_type */
- (GNOME_VFS_DIRECTORY_FILTER_NOSELFDIR /* filter_options */
- | GNOME_VFS_DIRECTORY_FILTER_NOPARENTDIR),
- NULL, /* filter_pattern */
- DIRECTORY_LOAD_ITEMS_PER_CALLBACK, /* items_per_notification */
- directory_load_callback, /* callback */
- directory);
-}
-
-/* Stop monitoring the file list if it is being monitored. */
-void
-nautilus_directory_stop_monitoring_file_list (NautilusDirectory *directory)
-{
- if (!directory->details->file_list_monitored) {
- g_assert (directory->details->directory_load_in_progress == NULL);
- return;
- }
-
- directory->details->file_list_monitored = FALSE;
- file_list_cancel (directory);
- nautilus_file_list_unref (directory->details->file_list);
- directory->details->directory_loaded = FALSE;
-}
-
-static void
-file_list_start (NautilusDirectory *directory)
-{
- if (nautilus_directory_is_anyone_monitoring_file_list (directory)) {
- start_monitoring_file_list (directory);
- } else {
- nautilus_directory_stop_monitoring_file_list (directory);
- }
-}
-
-/* Reset count and mime list. Invalidating deep counts is handled by
- * itself elsewhere because it's a relatively heavyweight and
- * special-purpose operation (see bug 5863). Also, the shallow count
- * needs to be refreshed when filtering changes, but the deep count
- * deliberately does not take filtering into account.
- */
-void
-nautilus_directory_invalidate_count_and_mime_list (NautilusDirectory *directory)
-{
- NautilusFile *file;
- NautilusDirectory *parent_directory;
-
- file = nautilus_directory_get_existing_corresponding_file (directory);
- if (file != NULL) {
- parent_directory = file->details->directory;
-
- if (parent_directory->details->count_file == file) {
- directory_count_cancel (parent_directory);
- }
- if (parent_directory->details->mime_list_file == file) {
- mime_list_cancel (parent_directory);
- }
-
- file->details->directory_count_is_up_to_date = FALSE;
- file->details->mime_list_is_up_to_date = FALSE;
-
- nautilus_file_unref (file);
-
- nautilus_directory_async_state_changed (parent_directory);
- }
-}
-
-static void
-nautilus_directory_invalidate_file_attributes (NautilusDirectory *directory,
- GList *file_attributes)
-{
- GList *node;
-
- cancel_loading_attributes (directory, file_attributes);
-
- for (node = directory->details->file_list; node != NULL; node = node->next) {
- nautilus_file_invalidate_attributes_internal (NAUTILUS_FILE (node->data),
- file_attributes);
- }
-
- if (directory->details->as_file != NULL) {
- nautilus_file_invalidate_attributes_internal (directory->details->as_file,
- file_attributes);
- }
-}
-
-void
-nautilus_directory_force_reload_internal (NautilusDirectory *directory,
- GList *file_attributes)
-{
- /* invalidate attributes that are getting reloaded for all files */
- nautilus_directory_invalidate_file_attributes (directory, file_attributes);
-
- /* Start a new directory load. */
- file_list_cancel (directory);
- directory->details->directory_loaded = FALSE;
-
- /* Start a new directory count. */
- nautilus_directory_invalidate_count_and_mime_list (directory);
-
- nautilus_directory_async_state_changed (directory);
-}
-
-static gboolean
-monitor_includes_file (const Monitor *monitor,
- NautilusFile *file)
-{
- if (monitor->file == file) {
- return TRUE;
- }
- if (monitor->file != NULL) {
- return FALSE;
- }
- if (file == file->details->directory->details->as_file) {
- return FALSE;
- }
- return nautilus_file_should_show (file,
- monitor->monitor_hidden_files,
- monitor->monitor_backup_files);
-}
-
-static gboolean
-is_needy (NautilusFile *file,
- FileCheck check_missing,
- RequestCheck check_wanted)
-{
- NautilusDirectory *directory;
- GList *node;
- ReadyCallback *callback;
- Monitor *monitor;
-
- g_assert (NAUTILUS_IS_FILE (file));
-
- if (!(* check_missing) (file)) {
- return FALSE;
- }
-
- directory = file->details->directory;
- for (node = directory->details->call_when_ready_list;
- node != NULL; node = node->next) {
- callback = node->data;
- if ((* check_wanted) (&callback->request)) {
- if (callback->file == file) {
- return TRUE;
- }
- if (callback->file == NULL
- && file != directory->details->as_file) {
- return TRUE;
- }
- }
- }
- for (node = directory->details->monitor_list;
- node != NULL; node = node->next) {
- monitor = node->data;
- if ((* check_wanted) (&monitor->request)) {
- if (monitor_includes_file (monitor, file)) {
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-static NautilusFile *
-select_needy_file (NautilusDirectory *directory,
- FileCheck check_missing,
- RequestCheck check_wanted)
-{
- GList *node, *node_2;
- ReadyCallback *callback;
- Monitor *monitor;
- NautilusFile *file;
-
- /* Quick out if no one is interested. */
- for (node = directory->details->call_when_ready_list;
- node != NULL; node = node->next) {
- callback = node->data;
- if ((* check_wanted) (&callback->request)) {
- break;
- }
- }
- if (node == NULL) {
- for (node = directory->details->monitor_list;
- node != NULL; node = node->next) {
- monitor = node->data;
- if ((* check_wanted) (&monitor->request)) {
- break;
- }
- }
- if (node == NULL) {
- return NULL;
- }
- }
-
- /* Search for a file that has an unfulfilled request. */
- for (node = directory->details->file_list;
- node != NULL; node = node->next) {
- file = node->data;
- if ((* check_missing) (file)) {
- for (node_2 = directory->details->call_when_ready_list;
- node_2 != NULL; node_2 = node_2->next) {
- callback = node_2->data;
- if ((callback->file == NULL || callback->file == file)
- && (* check_wanted) (&callback->request)) {
- break;
- }
- }
- if (node_2 != NULL) {
- return file;
- }
- for (node_2 = directory->details->monitor_list;
- node_2 != NULL; node_2 = node_2->next) {
- monitor = node_2->data;
- if (monitor_includes_file (monitor, file)
- && (* check_wanted) (&monitor->request)) {
- break;
- }
- }
- if (node_2 != NULL) {
- return file;
- }
- }
- }
-
- /* Finally, check the file for the directory itself. */
- file = directory->details->as_file;
- if (file != NULL) {
- if ((* check_missing) (file)) {
- for (node_2 = directory->details->call_when_ready_list;
- node_2 != NULL; node_2 = node_2->next) {
- callback = node_2->data;
- if (callback->file == file
- && (* check_wanted) (&callback->request)) {
- break;
- }
- }
- if (node_2 != NULL) {
- return file;
- }
- for (node_2 = directory->details->monitor_list;
- node_2 != NULL; node_2 = node_2->next) {
- monitor = node_2->data;
- if (monitor->file == file
- && (* check_wanted) (&monitor->request)) {
- break;
- }
- }
- if (node_2 != NULL) {
- return file;
- }
- }
- }
-
- return NULL;
-}
-
-static void
-directory_count_start (NautilusDirectory *directory)
-{
- NautilusFile *file;
- char *uri;
-
- /* If there's already a count in progress, check to be sure
- * it's still wanted.
- */
- if (directory->details->count_in_progress != NULL) {
- file = directory->details->count_file;
- if (file != NULL) {
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (file->details->directory == directory);
- if (is_needy (file,
- should_get_directory_count_now,
- wants_directory_count)) {
- return;
- }
- }
-
- /* The count is not wanted, so stop it. */
- directory_count_cancel (directory);
- }
-
- /* Figure out which file to get a count for. */
- file = select_needy_file (directory,
- should_get_directory_count_now,
- wants_directory_count);
- if (file == NULL) {
- return;
- }
-
- if (!async_job_start (directory, "directory count")) {
- return;
- }
-
- /* Start counting. */
- directory->details->count_file = file;
- uri = nautilus_file_get_uri (file);
-#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_DEFAULT,
- GNOME_VFS_DIRECTORY_FILTER_NONE,
- get_filter_options_for_directory_count (),
- NULL,
- G_MAXINT,
- directory_count_callback,
- directory);
- g_free (uri);
-}
-
-static void
-deep_count_one (NautilusDirectory *directory,
- GnomeVFSFileInfo *info)
-{
- NautilusFile *file;
- char *escaped_name, *uri;
-
- file = directory->details->deep_count_file;
-
- if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) != 0
- && info->type == GNOME_VFS_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 = nautilus_make_path (directory->details->deep_count_uri, escaped_name);
- g_free (escaped_name);
- directory->details->deep_count_subdirectories = g_list_prepend
- (directory->details->deep_count_subdirectories, uri);
- } 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;
- }
-}
-
-static void
-deep_count_callback (GnomeVFSAsyncHandle *handle,
- GnomeVFSResult result,
- GList *list,
- guint entries_read,
- gpointer callback_data)
-{
- NautilusDirectory *directory;
- NautilusFile *file;
- GList *element;
- char *uri;
- 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);
- }
-
- done = FALSE;
- if (result != GNOME_VFS_OK) {
- if (result != GNOME_VFS_ERROR_EOF) {
- file->details->deep_unreadable_count += 1;
- }
-
- 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;
- }
- }
-
- nautilus_file_updated_deep_count_in_progress (file);
-
- if (done) {
- nautilus_file_changed (file);
- async_job_end (directory, "deep count");
- nautilus_directory_async_state_changed (directory);
- }
-
- nautilus_directory_unref (directory);
-}
-
-static void
-deep_count_load (NautilusDirectory *directory, const char *uri)
-{
- g_assert (directory->details->deep_count_uri == NULL);
- directory->details->deep_count_uri = g_strdup (uri);
-#ifdef DEBUG_LOAD_DIRECTORY
- g_message ("load_directory called to get deep file count for %s", uri);
-#endif
- gnome_vfs_async_load_directory
- (&directory->details->deep_count_in_progress,
- uri,
- GNOME_VFS_FILE_INFO_DEFAULT,
- GNOME_VFS_DIRECTORY_FILTER_NONE,
- (GNOME_VFS_DIRECTORY_FILTER_NOSELFDIR
- | GNOME_VFS_DIRECTORY_FILTER_NOPARENTDIR),
- NULL,
- G_MAXINT,
- deep_count_callback,
- directory);
-}
-
-static void
-deep_count_start (NautilusDirectory *directory)
-{
- NautilusFile *file;
- char *uri;
-
- /* If there's already a count in progress, check to be sure
- * it's still wanted.
- */
- if (directory->details->deep_count_in_progress != NULL) {
- file = directory->details->deep_count_file;
- if (file != NULL) {
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (file->details->directory == directory);
- if (is_needy (file,
- lacks_deep_count,
- wants_deep_count)) {
- return;
- }
- }
-
- /* The count is not wanted, so stop it. */
- deep_count_cancel (directory);
- }
-
- /* Figure out which file to get a count for. */
- file = select_needy_file (directory,
- lacks_deep_count,
- wants_deep_count);
- if (file == NULL) {
- return;
- }
-
- if (!async_job_start (directory, "deep count")) {
- return;
- }
-
- /* Start counting. */
- file->details->deep_counts_status = NAUTILUS_REQUEST_IN_PROGRESS;
- file->details->deep_directory_count = 0;
- file->details->deep_file_count = 0;
- 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 ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) != 0) {
- istr_set_insert (directory->details->mime_list_hash, info->mime_type);
- }
-}
-
-static void
-mime_list_callback (GnomeVFSAsyncHandle *handle,
- GnomeVFSResult result,
- GList *list,
- guint entries_read,
- gpointer callback_data)
-{
- 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));
-
- for (element = list; element != NULL; element = element->next) {
- mime_list_one (directory, element->data);
- }
-
- if (result == GNOME_VFS_OK) {
- return;
- }
-
- nautilus_directory_ref (directory);
-
- file->details->mime_list_is_up_to_date = TRUE;
-
- /* Record either a failure or success. */
- eel_g_list_free_deep (file->details->mime_list);
- if (result != GNOME_VFS_ERROR_EOF) {
- 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);
- }
- 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
- * unknowable and not-yet-known cases.
- */
- nautilus_file_changed (file);
-
- /* 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_load (NautilusDirectory *directory, const char *uri)
-{
- 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,
- GNOME_VFS_DIRECTORY_FILTER_NONE,
- (GNOME_VFS_DIRECTORY_FILTER_NOSELFDIR
- | GNOME_VFS_DIRECTORY_FILTER_NOPARENTDIR),
- NULL,
- DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
- mime_list_callback,
- directory);
-}
-
-static void
-mime_list_start (NautilusDirectory *directory)
-{
- NautilusFile *file;
- char *uri;
-
- /* If there's already a count in progress, check to be sure
- * it's still wanted.
- */
- 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;
- }
- }
-
- /* The count is not wanted, so stop it. */
- mime_list_cancel (directory);
- }
-
- /* Figure out which file to get a mime list for. */
- file = select_needy_file (directory,
- should_get_mime_list,
- wants_mime_list);
- if (file == NULL) {
- return;
- }
-
- if (!async_job_start (directory, "MIME list")) {
- return;
- }
-
- directory->details->mime_list_file = file;
- uri = nautilus_file_get_uri (file);
- mime_list_load (directory, uri);
- g_free (uri);
-}
-
-static int
-count_lines (const char *text, int length)
-{
- int count, i;
-
- count = 0;
- for (i = 0; i < length; i++) {
- count += *text++ == '\n';
- }
- return count;
-}
-
-static void
-top_left_read_done (NautilusDirectory *directory)
-{
- g_assert (directory->details->top_left_read_state->handle == NULL);
- g_assert (NAUTILUS_IS_FILE (directory->details->top_left_read_state->file));
-
- directory->details->top_left_read_state->file->details->got_top_left_text = TRUE;
-
- 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);
-}
-
-static void
-top_left_read_callback (GnomeVFSResult result,
- GnomeVFSFileSize bytes_read,
- char *file_contents,
- gpointer callback_data)
-{
- NautilusDirectory *directory;
- NautilusFile *changed_file;
-
- directory = NAUTILUS_DIRECTORY (callback_data);
-
- nautilus_directory_ref (directory);
-
- directory->details->top_left_read_state->handle = NULL;
-
- directory->details->top_left_read_state->file->details->top_left_text_is_up_to_date = TRUE;
-
- changed_file = NULL;
- if (result == GNOME_VFS_OK) {
- g_free (directory->details->top_left_read_state->file->details->top_left_text);
- directory->details->top_left_read_state->file->details->top_left_text =
- nautilus_extract_top_left_text (file_contents, bytes_read);
-
- directory->details->top_left_read_state->file->details->got_top_left_text = TRUE;
-
- changed_file = directory->details->top_left_read_state->file;
- nautilus_file_ref (changed_file);
-
- g_free (file_contents);
- }
-
- top_left_read_done (directory);
-
- if (changed_file != NULL) {
- nautilus_file_changed (changed_file);
- nautilus_file_unref (changed_file);
- }
-
- nautilus_directory_unref (directory);
-}
-
-static gboolean
-top_left_read_more_callback (GnomeVFSFileSize bytes_read,
- const char *file_contents,
- gpointer callback_data)
-{
- g_assert (NAUTILUS_IS_DIRECTORY (callback_data));
-
- /* Stop reading when we have enough. */
- return bytes_read < NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_BYTES
- && count_lines (file_contents, bytes_read) <= NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_LINES;
-}
-
-static void
-top_left_start (NautilusDirectory *directory)
-{
- NautilusFile *file;
- char *uri;
-
- /* If there's already a read in progress, check to be sure
- * it's still wanted.
- */
- 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)) {
- return;
- }
- }
-
- /* The top left is not wanted, so stop it. */
- top_left_cancel (directory);
- }
-
- /* Figure out which file to read the top left for. */
- file = select_needy_file (directory,
- lacks_top_left,
- wants_top_left);
- if (file == NULL) {
- return;
- }
-
- if (!async_job_start (directory, "top left")) {
- return;
- }
-
- /* Start reading. */
- directory->details->top_left_read_state = g_new0 (TopLeftTextReadState, 1);
- 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,
- top_left_read_callback,
- top_left_read_more_callback,
- directory);
- g_free (uri);
-}
-
-static void
-get_info_callback (GnomeVFSAsyncHandle *handle,
- GList *results,
- gpointer callback_data)
-{
- NautilusDirectory *directory;
- NautilusFile *get_info_file;
- GnomeVFSGetFileInfoResult *result;
-
- 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);
-
- directory->details->get_info_file = NULL;
- directory->details->get_info_in_progress = NULL;
-
- /* 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
- * least long enough to send the change notification.
- */
- nautilus_file_ref (get_info_file);
-
- result = results->data;
-
- if (result->result != GNOME_VFS_OK) {
- 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;
- }
- get_info_file->details->get_info_failed = TRUE;
- get_info_file->details->get_info_error = result->result;
- if (result->result == GNOME_VFS_ERROR_NOT_FOUND) {
- /* mark file as gone */
-
- get_info_file->details->is_gone = TRUE;
- if (get_info_file != directory->details->as_file) {
- nautilus_directory_remove_file (directory, get_info_file);
- }
- }
- } else {
- nautilus_file_update_info (get_info_file, result->file_info);
- }
-
- nautilus_file_changed (get_info_file);
- nautilus_file_unref (get_info_file);
-
- async_job_end (directory, "file info");
- nautilus_directory_async_state_changed (directory);
-
- nautilus_directory_unref (directory);
-}
-
-static void
-file_info_start (NautilusDirectory *directory)
-{
- NautilusFile *file;
- char *uri;
- GnomeVFSURI *vfs_uri;
- GList fake_list;
-
- /* If there's already a file info fetch in progress, check to
- * be sure it's still wanted.
- */
- if (directory->details->get_info_in_progress != NULL) {
- file = directory->details->get_info_file;
- if (file != NULL) {
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (file->details->directory == directory);
- if (is_needy (file, lacks_info, wants_info)) {
- return;
- }
- }
-
- /* The info is not wanted, so stop it. */
- file_info_cancel (directory);
- }
-
- /* Figure out which file to get file info for. */
- do {
- file = select_needy_file (directory, lacks_info, wants_info);
- if (file == NULL) {
- return;
- }
-
- uri = nautilus_file_get_uri (file);
- vfs_uri = gnome_vfs_uri_new (uri);
- g_free (uri);
-
- 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;
- nautilus_file_changed (file);
- }
- } while (vfs_uri == NULL);
-
- /* Found one we need to get the info for. */
- if (!async_job_start (directory, "file info")) {
- return;
- }
- directory->details->get_info_file = file;
- fake_list.data = vfs_uri;
- fake_list.prev = NULL;
- fake_list.next = NULL;
- gnome_vfs_async_get_file_info
- (&directory->details->get_info_in_progress,
- &fake_list,
- GNOME_VFS_FILE_INFO_GET_MIME_TYPE
- | GNOME_VFS_FILE_INFO_FOLLOW_LINKS,
- get_info_callback,
- directory);
- gnome_vfs_uri_unref (vfs_uri);
-}
-
-static void
-activation_uri_done (NautilusDirectory *directory,
- NautilusFile *file,
- const char *uri)
-{
- file->details->activation_uri_is_up_to_date = TRUE;
-
- file->details->got_activation_uri = TRUE;
- g_free (file->details->activation_uri);
- file->details->activation_uri = g_strdup (uri);
-
- nautilus_file_changed (file);
-
- async_job_end (directory, "activation URI");
- nautilus_directory_async_state_changed (directory);
-}
-
-static void
-activation_uri_read_done (NautilusDirectory *directory,
- const char *uri)
-{
- NautilusFile *file;
-
- file = directory->details->activation_uri_read_state->file;
- g_free (directory->details->activation_uri_read_state);
- directory->details->activation_uri_read_state = NULL;
-
- activation_uri_done (directory, file, uri);
-}
-
-static void
-activation_uri_nautilus_link_read_callback (GnomeVFSResult result,
- GnomeVFSFileSize bytes_read,
- char *file_contents,
- gpointer callback_data)
-{
- NautilusDirectory *directory;
- char *buffer, *uri;
-
- directory = NAUTILUS_DIRECTORY (callback_data);
-
- nautilus_directory_ref (directory);
-
- /* Handle the case where we read the Nautilus link. */
- if (result != GNOME_VFS_OK) {
- /* FIXME bugzilla.eazel.com 2433: We should report this error to the user. */
- g_free (file_contents);
- uri = NULL;
- } else {
- /* The gnome-xml parser requires a zero-terminated array. */
- buffer = g_realloc (file_contents, bytes_read + 1);
- buffer[bytes_read] = '\0';
- uri = nautilus_link_get_link_uri_given_file_contents (buffer, bytes_read);
- g_free (buffer);
- }
-
- activation_uri_read_done (directory, uri);
- g_free (uri);
-
- nautilus_directory_unref (directory);
-}
-
-static void
-activation_uri_gmc_link_read_callback (GnomeVFSResult result,
- GnomeVFSFileSize bytes_read,
- char *file_contents,
- gpointer callback_data)
-{
- NautilusDirectory *directory;
- char *end_of_line, *uri;
-
- directory = NAUTILUS_DIRECTORY (callback_data);
-
- nautilus_directory_ref (directory);
-
- /* Handle the case where we read the GMC link. */
- if (result != GNOME_VFS_OK || !eel_str_has_prefix (file_contents, "URL: ")) {
- /* FIXME bugzilla.eazel.com 2433: We should report this error to the user. */
- uri = NULL;
- } else {
- /* Make sure we don't run off the end of the buffer. */
- end_of_line = memchr (file_contents, '\n', bytes_read);
- if (end_of_line != NULL) {
- uri = g_strndup (file_contents, end_of_line - file_contents);
- } else {
- uri = g_strndup (file_contents, bytes_read);
- }
- }
-
- g_free (file_contents);
- activation_uri_read_done (directory, uri ? uri + 5 : NULL);
- g_free (uri);
-
- nautilus_directory_unref (directory);
-}
-
-static gboolean
-activation_uri_gmc_link_read_more_callback (GnomeVFSFileSize bytes_read,
- const char *file_contents,
- gpointer callback_data)
-{
- g_assert (NAUTILUS_IS_DIRECTORY (callback_data));
-
- /* We need the first 512 bytes to see if something is a gmc link. */
- return bytes_read < 512;
-}
-
-static void
-activation_uri_start (NautilusDirectory *directory)
-{
- NautilusFile *file;
- char *mime_type, *uri;
- gboolean gmc_style_link, nautilus_style_link;
-
- /* If there's already a activation URI read in progress, check
- * to be sure it's still wanted.
- */
- if (directory->details->activation_uri_read_state != NULL) {
- file = directory->details->activation_uri_read_state->file;
- if (file != NULL) {
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (file->details->directory == directory);
- if (is_needy (file, lacks_info, wants_info)) {
- return;
- }
- }
-
- /* The count is not wanted, so stop it. */
- activation_uri_cancel (directory);
- }
-
- /* Figure out which file to get activation_uri for. */
- file = select_needy_file (directory,
- lacks_activation_uri,
- wants_activation_uri);
- if (file == NULL) {
- return;
- }
-
- if (!async_job_start (directory, "activation URI")) {
- return;
- }
-
- /* Figure out if it is a link. */
- mime_type = nautilus_file_get_mime_type (file);
- gmc_style_link = eel_strcasecmp (mime_type, "application/x-gmc-link") == 0;
- g_free (mime_type);
- nautilus_style_link = nautilus_file_is_nautilus_link (file);
-
- /* If it's not a link we are done. If it is, we need to read it. */
- if (!(gmc_style_link || nautilus_style_link)) {
- activation_uri_done (directory, file, NULL);
- } else {
- directory->details->activation_uri_read_state = g_new0 (ActivationURIReadState, 1);
- directory->details->activation_uri_read_state->file = file;
- uri = nautilus_file_get_uri (file);
- if (gmc_style_link) {
- directory->details->activation_uri_read_state->handle = eel_read_file_async
- (uri,
- activation_uri_gmc_link_read_callback,
- activation_uri_gmc_link_read_more_callback,
- directory);
- } else {
- directory->details->activation_uri_read_state->handle = eel_read_entire_file_async
- (uri,
- activation_uri_nautilus_link_read_callback,
- directory);
- }
- g_free (uri);
- }
-}
-
-static void
-start_or_stop_io (NautilusDirectory *directory)
-{
- /* Start or stop getting file info. */
- file_info_start (directory);
-
- /* Start or stop reading files. */
- file_list_start (directory);
-
- /* Start or stop getting directory counts. */
- directory_count_start (directory);
- deep_count_start (directory);
-
- /* Start or stop getting mime lists. */
- mime_list_start (directory);
-
- /* Start or stop getting top left pieces of files. */
- top_left_start (directory);
-
- /* Start or stop getting activation URIs, which includes
- * reading the contents of Nautilus and GMC link files.
- */
- activation_uri_start (directory);
-}
-
-/* Call this when the monitor or call when ready list changes,
- * or when some I/O is completed.
- */
-void
-nautilus_directory_async_state_changed (NautilusDirectory *directory)
-{
- /* Check if any callbacks are satisfied and call them if they
- * are. Do this last so that any changes done in start or stop
- * I/O functions immediately (not in callbacks) are taken into
- * consideration. If any callbacks are called, consider the
- * I/O state again so that we can release or cancel I/O that
- * is not longer needed once the callbacks are satisfied.
- */
-
- if (GTK_OBJECT_DESTROYED (directory)) {
- return;
- }
- if (directory->details->in_async_service_loop) {
- directory->details->state_changed = TRUE;
- return;
- }
- directory->details->in_async_service_loop = TRUE;
- nautilus_directory_ref (directory);
- do {
- directory->details->state_changed = FALSE;
- start_or_stop_io (directory);
- if (call_ready_callbacks (directory)) {
- directory->details->state_changed = TRUE;
- }
- } while (directory->details->state_changed);
- directory->details->in_async_service_loop = FALSE;
- nautilus_directory_unref (directory);
-
- /* Check if any directories should wake up. */
- async_job_wake_up ();
-}
-
-void
-nautilus_directory_cancel (NautilusDirectory *directory)
-{
- /* Arbitrary order (kept alphabetical). */
- activation_uri_cancel (directory);
- deep_count_cancel (directory);
- directory_count_cancel (directory);
- file_info_cancel (directory);
- file_list_cancel (directory);
- mime_list_cancel (directory);
- top_left_cancel (directory);
-
- /* We aren't waiting for anything any more. */
- if (waiting_directories != NULL) {
- g_hash_table_remove (waiting_directories, directory);
- }
-
- /* Check if any directories should wake up. */
- async_job_wake_up ();
-}
-
-static void
-cancel_directory_count_for_file (NautilusDirectory *directory,
- NautilusFile *file)
-{
- if (directory->details->count_file == file) {
- directory_count_cancel (directory);
- }
-}
-
-static void
-cancel_deep_counts_for_file (NautilusDirectory *directory,
- NautilusFile *file)
-{
- if (directory->details->deep_count_file == file) {
- deep_count_cancel (directory);
- }
-}
-
-static void
-cancel_mime_list_for_file (NautilusDirectory *directory,
- NautilusFile *file)
-{
- if (directory->details->mime_list_file == file) {
- mime_list_cancel (directory);
- }
-}
-
-static void
-cancel_top_left_text_for_file (NautilusDirectory *directory,
- NautilusFile *file)
-{
- if (directory->details->top_left_read_state != NULL &&
- directory->details->top_left_read_state->file == file) {
- top_left_cancel (directory);
- }
-}
-
-static void
-cancel_file_info_for_file (NautilusDirectory *directory,
- NautilusFile *file)
-{
- if (directory->details->get_info_file == file) {
- file_info_cancel (directory);
- }
-}
-
-static void
-cancel_activation_uri_for_file (NautilusDirectory *directory,
- NautilusFile *file)
-{
- if (directory->details->activation_uri_read_state != NULL &&
- directory->details->activation_uri_read_state->file == file) {
- activation_uri_cancel (directory);
- }
-}
-
-static void
-cancel_loading_attributes (NautilusDirectory *directory,
- GList *file_attributes)
-{
- Request request;
-
- nautilus_directory_set_up_request (&request,
- file_attributes);
-
- if (request.directory_count) {
- directory_count_cancel (directory);
- }
- if (request.deep_count) {
- deep_count_cancel (directory);
- }
- if (request.mime_list) {
- mime_list_cancel (directory);
- }
- if (request.top_left_text) {
- top_left_cancel (directory);
- }
- if (request.file_info) {
- file_info_cancel (directory);
- }
- if (request.activation_uri) {
- file_info_cancel (directory);
- }
-
- /* FIXME bugzilla.eazel.com 5064: implement cancelling metadata when we
- implement invalidating metadata */
-
- nautilus_directory_async_state_changed (directory);
-}
-
-void
-nautilus_directory_cancel_loading_file_attributes (NautilusDirectory *directory,
- NautilusFile *file,
- GList *file_attributes)
-{
- Request request;
-
- nautilus_directory_set_up_request (&request,
- file_attributes);
-
- if (request.directory_count) {
- cancel_directory_count_for_file (directory, file);
- }
- if (request.deep_count) {
- cancel_deep_counts_for_file (directory, file);
- }
- if (request.mime_list) {
- cancel_mime_list_for_file (directory, file);
- }
- if (request.top_left_text) {
- cancel_top_left_text_for_file (directory, file);
- }
- if (request.file_info) {
- cancel_file_info_for_file (directory, file);
- }
- if (request.activation_uri) {
- cancel_activation_uri_for_file (directory, file);
- }
-
- /* FIXME bugzilla.eazel.com 5064: implement cancelling metadata when we
- implement invalidating metadata */
-
- nautilus_directory_async_state_changed (directory);
-}