nautilus-3.6.3/libnautilus-private/nautilus-directory-async.c

No issues found

   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
   2 
   3    nautilus-directory-async.c: Nautilus directory model state machine.
   4  
   5    Copyright (C) 1999, 2000, 2001 Eazel, Inc.
   6   
   7    This program is free software; you can redistribute it and/or
   8    modify it under the terms of the GNU General Public License as
   9    published by the Free Software Foundation; either version 2 of the
  10    License, or (at your option) any later version.
  11   
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15    General Public License for more details.
  16   
  17    You should have received a copy of the GNU General Public
  18    License along with this program; if not, write to the
  19    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20    Boston, MA 02111-1307, USA.
  21   
  22    Author: Darin Adler <darin@bentspoon.com>
  23 */
  24 
  25 #include <config.h>
  26 
  27 #include "nautilus-directory-notify.h"
  28 #include "nautilus-directory-private.h"
  29 #include "nautilus-file-attributes.h"
  30 #include "nautilus-file-private.h"
  31 #include "nautilus-file-utilities.h"
  32 #include "nautilus-signaller.h"
  33 #include "nautilus-global-preferences.h"
  34 #include "nautilus-link.h"
  35 #include "nautilus-profile.h"
  36 #include <eel/eel-glib-extensions.h>
  37 #include <gtk/gtk.h>
  38 #include <libxml/parser.h>
  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 
  42 /* turn this on to see messages about each load_directory call: */
  43 #if 0
  44 #define DEBUG_LOAD_DIRECTORY
  45 #endif
  46 
  47 /* turn this on to check if async. job calls are balanced */
  48 #if 0
  49 #define DEBUG_ASYNC_JOBS
  50 #endif
  51 
  52 /* turn this on to log things starting and stopping */
  53 #if 0
  54 #define DEBUG_START_STOP
  55 #endif
  56 
  57 #define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100
  58 
  59 /* Keep async. jobs down to this number for all directories. */
  60 #define MAX_ASYNC_JOBS 10
  61 
  62 struct TopLeftTextReadState {
  63 	NautilusDirectory *directory;
  64 	NautilusFile *file;
  65 	gboolean large;
  66 	GCancellable *cancellable;
  67 };
  68 
  69 struct LinkInfoReadState {
  70 	NautilusDirectory *directory;
  71 	GCancellable *cancellable;
  72 	NautilusFile *file;
  73 };
  74 
  75 struct ThumbnailState {
  76 	NautilusDirectory *directory;
  77 	GCancellable *cancellable;
  78 	NautilusFile *file;
  79 	gboolean trying_original;
  80 	gboolean tried_original;
  81 };
  82 
  83 struct MountState {
  84 	NautilusDirectory *directory;
  85 	GCancellable *cancellable;
  86 	NautilusFile *file;
  87 };
  88 
  89 struct FilesystemInfoState {
  90 	NautilusDirectory *directory;
  91 	GCancellable *cancellable;
  92 	NautilusFile *file;
  93 };
  94 
  95 struct DirectoryLoadState {
  96 	NautilusDirectory *directory;
  97 	GCancellable *cancellable;
  98 	GFileEnumerator *enumerator;
  99 	GHashTable *load_mime_list_hash;
 100 	NautilusFile *load_directory_file;
 101 	int load_file_count;
 102 };
 103 
 104 struct MimeListState {
 105 	NautilusDirectory *directory;
 106 	NautilusFile *mime_list_file;
 107 	GCancellable *cancellable;
 108 	GFileEnumerator *enumerator;
 109 	GHashTable *mime_list_hash;
 110 };
 111 
 112 struct GetInfoState {
 113 	NautilusDirectory *directory;
 114 	GCancellable *cancellable;
 115 };
 116 
 117 struct NewFilesState {
 118 	NautilusDirectory *directory;
 119 	GCancellable *cancellable;
 120 	int count;
 121 };
 122 
 123 struct DirectoryCountState {
 124 	NautilusDirectory *directory;
 125 	NautilusFile *count_file;
 126 	GCancellable *cancellable;
 127 	GFileEnumerator *enumerator;
 128 	int file_count;
 129 };
 130 
 131 struct DeepCountState {
 132 	NautilusDirectory *directory;
 133 	GCancellable *cancellable;
 134 	GFileEnumerator *enumerator;
 135 	GFile *deep_count_location;
 136 	GList *deep_count_subdirectories;
 137 	GArray *seen_deep_count_inodes;
 138 };
 139 
 140 
 141 
 142 typedef struct {
 143 	NautilusFile *file; /* Which file, NULL means all. */
 144 	union {
 145 		NautilusDirectoryCallback directory;
 146 		NautilusFileCallback file;
 147 	} callback;
 148 	gpointer callback_data;
 149 	Request request;
 150 	gboolean active; /* Set to FALSE when the callback is triggered and
 151 			  * scheduled to be called at idle, its still kept
 152 			  * in the list so we can kill it when the file
 153 			  * goes away.
 154 			  */
 155 } ReadyCallback;
 156 
 157 typedef struct {
 158 	NautilusFile *file; /* Which file, NULL means all. */
 159 	gboolean monitor_hidden_files; /* defines whether "all" includes hidden files */
 160 	gconstpointer client;
 161 	Request request;
 162 } Monitor;
 163 
 164 typedef struct {
 165 	NautilusDirectory *directory;
 166 	NautilusInfoProvider *provider;
 167 	NautilusOperationHandle *handle;
 168 	NautilusOperationResult result;
 169 } InfoProviderResponse;
 170 
 171 typedef gboolean (* RequestCheck) (Request);
 172 typedef gboolean (* FileCheck) (NautilusFile *);
 173 
 174 /* Current number of async. jobs. */
 175 static int async_job_count;
 176 static GHashTable *waiting_directories;
 177 #ifdef DEBUG_ASYNC_JOBS
 178 static GHashTable *async_jobs;
 179 #endif
 180 
 181 /* Hide kde trashcan directory */
 182 static char *kde_trash_dir_name = NULL;
 183 
 184 /* Forward declarations for functions that need them. */
 185 static void     deep_count_load                               (DeepCountState         *state,
 186 							       GFile                  *location);
 187 static gboolean request_is_satisfied                          (NautilusDirectory      *directory,
 188 							       NautilusFile           *file,
 189 							       Request                 request);
 190 static void     cancel_loading_attributes                     (NautilusDirectory      *directory,
 191 							       NautilusFileAttributes  file_attributes);
 192 static void     add_all_files_to_work_queue                   (NautilusDirectory      *directory);
 193 static void     link_info_done                                (NautilusDirectory      *directory,
 194 							       NautilusFile           *file,
 195 							       const char             *uri,
 196 							       const char             *name,
 197 							       GIcon                  *icon,
 198 							       gboolean                is_launcher,
 199 							       gboolean                is_foreign);
 200 static void     move_file_to_low_priority_queue               (NautilusDirectory      *directory,
 201 							       NautilusFile           *file);
 202 static void     move_file_to_extension_queue                  (NautilusDirectory      *directory,
 203 							       NautilusFile           *file);
 204 static void     nautilus_directory_invalidate_file_attributes (NautilusDirectory      *directory,
 205 							       NautilusFileAttributes  file_attributes);
 206 
 207 void
 208 nautilus_set_kde_trash_name (const char *trash_dir)
 209 {
 210 	g_free (kde_trash_dir_name);
 211 	kde_trash_dir_name = g_strdup (trash_dir);
 212 }
 213 
 214 /* Some helpers for case-insensitive strings.
 215  * Move to nautilus-glib-extensions?
 216  */
 217 
 218 static gboolean
 219 istr_equal (gconstpointer v, gconstpointer v2)
 220 {
 221 	return g_ascii_strcasecmp (v, v2) == 0;
 222 }
 223 
 224 static guint
 225 istr_hash (gconstpointer key)
 226 {
 227 	const char *p;
 228 	guint h;
 229 
 230 	h = 0;
 231 	for (p = key; *p != '\0'; p++) {
 232 		h = (h << 5) - h + g_ascii_tolower (*p);
 233 	}
 234 	
 235 	return h;
 236 }
 237 
 238 static GHashTable *
 239 istr_set_new (void)
 240 {
 241 	return g_hash_table_new_full (istr_hash, istr_equal, g_free, NULL);
 242 }
 243 
 244 static void
 245 istr_set_insert (GHashTable *table, const char *istr)
 246 {
 247 	char *key;
 248 
 249 	key = g_strdup (istr);
 250 	g_hash_table_replace (table, key, key);
 251 }
 252 
 253 static void
 254 add_istr_to_list (gpointer key, gpointer value, gpointer callback_data)
 255 {
 256 	GList **list;
 257 
 258 	list = callback_data;
 259 	*list = g_list_prepend (*list, g_strdup (key));
 260 }
 261 
 262 static GList *
 263 istr_set_get_as_list (GHashTable *table)
 264 {
 265 	GList *list;
 266 
 267 	list = NULL;
 268 	g_hash_table_foreach (table, add_istr_to_list, &list);
 269 	return list;
 270 }
 271 
 272 static void
 273 istr_set_destroy (GHashTable *table)
 274 {
 275 	g_hash_table_destroy (table);
 276 }
 277 
 278 static void
 279 request_counter_add_request (RequestCounter counter,
 280 			     Request request)
 281 {
 282 	guint i;
 283 
 284 	for (i = 0; i < REQUEST_TYPE_LAST; i++) {
 285 		if (REQUEST_WANTS_TYPE (request, i)) {
 286 			counter[i]++;
 287 		}
 288 	}
 289 }
 290 
 291 static void
 292 request_counter_remove_request (RequestCounter counter,
 293 				Request request)
 294 {
 295 	guint i;
 296 
 297 	for (i = 0; i < REQUEST_TYPE_LAST; i++) {
 298 		if (REQUEST_WANTS_TYPE (request, i)) {
 299 			counter[i]--;
 300 		}
 301 	}
 302 }
 303 
 304 #if 0
 305 static void
 306 nautilus_directory_verify_request_counts (NautilusDirectory *directory)
 307 {
 308 	GList *l;
 309 	RequestCounter counters;
 310 	int i;
 311 	gboolean fail;
 312 
 313 	fail = FALSE;
 314 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
 315 		counters[i] = 0;
 316 	}
 317 	for (l = directory->details->monitor_list; l != NULL; l = l->next) {
 318 		Monitor *monitor = l->data;
 319 		request_counter_add_request (counters, monitor->request);
 320 	}
 321 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
 322 		if (counters[i] != directory->details->monitor_counters[i]) {
 323 			g_warning ("monitor counter for %i is wrong, expecting %d but found %d",
 324 				   i, counters[i], directory->details->monitor_counters[i]);
 325 			fail = TRUE;
 326 		}
 327 	}
 328 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
 329 		counters[i] = 0;
 330 	}
 331 	for (l = directory->details->call_when_ready_list; l != NULL; l = l->next) {
 332 		ReadyCallback *callback = l->data;
 333 		request_counter_add_request (counters, callback->request);
 334 	}
 335 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
 336 		if (counters[i] != directory->details->call_when_ready_counters[i]) {
 337 			g_warning ("call when ready counter for %i is wrong, expecting %d but found %d",
 338 				   i, counters[i], directory->details->call_when_ready_counters[i]);
 339 			fail = TRUE;
 340 		}
 341 	}
 342 	g_assert (!fail);
 343 }
 344 #endif
 345 
 346 /* Start a job. This is really just a way of limiting the number of
 347  * async. requests that we issue at any given time. Without this, the
 348  * number of requests is unbounded.
 349  */
 350 static gboolean
 351 async_job_start (NautilusDirectory *directory,
 352 		 const char *job)
 353 {
 354 #ifdef DEBUG_ASYNC_JOBS
 355 	char *key;
 356 #endif
 357 
 358 #ifdef DEBUG_START_STOP
 359 	g_message ("starting %s in %p", job, directory->details->location);
 360 #endif
 361 
 362 	g_assert (async_job_count >= 0);
 363 	g_assert (async_job_count <= MAX_ASYNC_JOBS);
 364 
 365 	if (async_job_count >= MAX_ASYNC_JOBS) {
 366 		if (waiting_directories == NULL) {
 367 			waiting_directories = g_hash_table_new (NULL, NULL);
 368 		}
 369 
 370 		g_hash_table_insert (waiting_directories,
 371 				     directory,
 372 				     directory);
 373 		
 374 		return FALSE;
 375 	}
 376 
 377 #ifdef DEBUG_ASYNC_JOBS
 378 	{
 379 		char *uri;
 380 		if (async_jobs == NULL) {
 381 			async_jobs = g_hash_table_new (g_str_hash, g_str_equal);
 382 		}
 383 		uri = nautilus_directory_get_uri (directory);
 384 		key = g_strconcat (uri, ": ", job, NULL);
 385 		if (g_hash_table_lookup (async_jobs, key) != NULL) {
 386 			g_warning ("same job twice: %s in %s",
 387 				   job, uri);
 388 		}
 389 		g_free (uri);
 390 		g_hash_table_insert (async_jobs, key, directory);
 391 	}
 392 #endif	
 393 
 394 	async_job_count += 1;
 395 	return TRUE;
 396 }
 397 
 398 /* End a job. */
 399 static void
 400 async_job_end (NautilusDirectory *directory,
 401 	       const char *job)
 402 {
 403 #ifdef DEBUG_ASYNC_JOBS
 404 	char *key;
 405 	gpointer table_key, value;
 406 #endif
 407 
 408 #ifdef DEBUG_START_STOP
 409 	g_message ("stopping %s in %p", job, directory->details->location);
 410 #endif
 411 
 412 	g_assert (async_job_count > 0);
 413 
 414 #ifdef DEBUG_ASYNC_JOBS
 415 	{
 416 		char *uri;
 417 		uri = nautilus_directory_get_uri (directory);
 418 		g_assert (async_jobs != NULL);
 419 		key = g_strconcat (uri, ": ", job, NULL);
 420 		if (!g_hash_table_lookup_extended (async_jobs, key, &table_key, &value)) {
 421 			g_warning ("ending job we didn't start: %s in %s",
 422 				   job, uri);
 423 		} else {
 424 			g_hash_table_remove (async_jobs, key);
 425 			g_free (table_key);
 426 		}
 427 		g_free (uri);
 428 		g_free (key);
 429 	}
 430 #endif
 431 
 432 	async_job_count -= 1;
 433 }
 434 
 435 /* Helper to get one value from a hash table. */
 436 static void
 437 get_one_value_callback (gpointer key, gpointer value, gpointer callback_data)
 438 {
 439 	gpointer *returned_value;
 440 
 441 	returned_value = callback_data;
 442 	*returned_value = value;
 443 }
 444 
 445 /* return a single value from a hash table. */
 446 static gpointer
 447 get_one_value (GHashTable *table)
 448 {
 449 	gpointer value;
 450 
 451 	value = NULL;
 452 	if (table != NULL) {
 453 		g_hash_table_foreach (table, get_one_value_callback, &value);
 454 	}
 455 	return value;
 456 }
 457 
 458 /* Wake up directories that are "blocked" as long as there are job
 459  * slots available.
 460  */
 461 static void
 462 async_job_wake_up (void)
 463 {
 464 	static gboolean already_waking_up = FALSE;
 465 	gpointer value;
 466 
 467 	g_assert (async_job_count >= 0);
 468 	g_assert (async_job_count <= MAX_ASYNC_JOBS);
 469 
 470 	if (already_waking_up) {
 471 		return;
 472 	}
 473 	
 474 	already_waking_up = TRUE;
 475 	while (async_job_count < MAX_ASYNC_JOBS) {
 476 		value = get_one_value (waiting_directories);
 477 		if (value == NULL) {
 478 			break;
 479 		}
 480 		g_hash_table_remove (waiting_directories, value);
 481 		nautilus_directory_async_state_changed
 482 			(NAUTILUS_DIRECTORY (value));
 483 	}
 484 	already_waking_up = FALSE;
 485 }
 486 
 487 static void
 488 directory_count_cancel (NautilusDirectory *directory)
 489 {
 490 	if (directory->details->count_in_progress != NULL) {
 491 		g_cancellable_cancel (directory->details->count_in_progress->cancellable);
 492 	}
 493 }
 494 
 495 static void
 496 deep_count_cancel (NautilusDirectory *directory)
 497 {
 498 	if (directory->details->deep_count_in_progress != NULL) {
 499 		g_assert (NAUTILUS_IS_FILE (directory->details->deep_count_file));
 500 		
 501 		g_cancellable_cancel (directory->details->deep_count_in_progress->cancellable);
 502 
 503 		directory->details->deep_count_file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED;
 504 
 505 		directory->details->deep_count_in_progress->directory = NULL;
 506 		directory->details->deep_count_in_progress = NULL;
 507 		directory->details->deep_count_file = NULL;
 508 
 509 		async_job_end (directory, "deep count");
 510 	}
 511 }
 512 
 513 static void
 514 mime_list_cancel (NautilusDirectory *directory)
 515 {
 516 	if (directory->details->mime_list_in_progress != NULL) {
 517 		g_cancellable_cancel (directory->details->mime_list_in_progress->cancellable);
 518 	}
 519 }
 520 
 521 static void
 522 top_left_cancel (NautilusDirectory *directory)
 523 {
 524 	if (directory->details->top_left_read_state != NULL) {
 525 		g_cancellable_cancel (directory->details->top_left_read_state->cancellable);
 526 		directory->details->top_left_read_state->directory = NULL;
 527 		directory->details->top_left_read_state = NULL;
 528 		
 529 		async_job_end (directory, "top left");
 530 	}
 531 }
 532 
 533 static void
 534 link_info_cancel (NautilusDirectory *directory)
 535 {
 536 	if (directory->details->link_info_read_state != NULL) {
 537 		g_cancellable_cancel (directory->details->link_info_read_state->cancellable);
 538 		directory->details->link_info_read_state->directory = NULL;
 539 		directory->details->link_info_read_state = NULL;
 540 		async_job_end (directory, "link info");
 541 	}
 542 }
 543 
 544 static void
 545 thumbnail_cancel (NautilusDirectory *directory)
 546 {
 547 	if (directory->details->thumbnail_state != NULL) {
 548 		g_cancellable_cancel (directory->details->thumbnail_state->cancellable);
 549 		directory->details->thumbnail_state->directory = NULL;
 550 		directory->details->thumbnail_state = NULL;
 551 		async_job_end (directory, "thumbnail");
 552 	}
 553 }
 554 
 555 static void
 556 mount_cancel (NautilusDirectory *directory)
 557 {
 558 	if (directory->details->mount_state != NULL) {
 559 		g_cancellable_cancel (directory->details->mount_state->cancellable);
 560 		directory->details->mount_state->directory = NULL;
 561 		directory->details->mount_state = NULL;
 562 		async_job_end (directory, "mount");
 563 	}
 564 }
 565 
 566 static void
 567 file_info_cancel (NautilusDirectory *directory)
 568 {
 569 	if (directory->details->get_info_in_progress != NULL) {
 570 		g_cancellable_cancel (directory->details->get_info_in_progress->cancellable);
 571 		directory->details->get_info_in_progress->directory = NULL;
 572 		directory->details->get_info_in_progress = NULL;
 573 		directory->details->get_info_file = NULL;
 574 
 575 		async_job_end (directory, "file info");
 576 	}
 577 }
 578 
 579 static void
 580 new_files_cancel (NautilusDirectory *directory)
 581 {
 582 	GList *l;
 583 	NewFilesState *state;
 584 	
 585 	if (directory->details->new_files_in_progress != NULL) {
 586 		for (l = directory->details->new_files_in_progress; l != NULL; l = l->next) {
 587 			state = l->data;
 588 			g_cancellable_cancel (state->cancellable);
 589 			state->directory = NULL;
 590 		}
 591 		g_list_free (directory->details->new_files_in_progress);
 592 		directory->details->new_files_in_progress = NULL;
 593 	}
 594 }
 595 
 596 static int
 597 monitor_key_compare (gconstpointer a,
 598 		     gconstpointer data)
 599 {
 600 	const Monitor *monitor;
 601 	const Monitor *compare_monitor;
 602 
 603 	monitor = a;
 604 	compare_monitor = data;
 605 	
 606 	if (monitor->client < compare_monitor->client) {
 607 		return -1;
 608 	}
 609 	if (monitor->client > compare_monitor->client) {
 610 		return +1;
 611 	}
 612 
 613 	if (monitor->file < compare_monitor->file) {
 614 		return -1;
 615 	}
 616 	if (monitor->file > compare_monitor->file) {
 617 		return +1;
 618 	}
 619 	
 620 	return 0;
 621 }
 622 
 623 static GList *
 624 find_monitor (NautilusDirectory *directory,
 625 	      NautilusFile *file,
 626 	      gconstpointer client)
 627 {
 628 	Monitor monitor;
 629 
 630 	monitor.client = client;
 631 	monitor.file = file;
 632 
 633 	return g_list_find_custom (directory->details->monitor_list,
 634 				   &monitor,
 635 				   monitor_key_compare);
 636 }
 637 
 638 static void
 639 remove_monitor_link (NautilusDirectory *directory,
 640 		     GList *link)
 641 {
 642 	Monitor *monitor;
 643 
 644 	if (link != NULL) {
 645 		monitor = link->data;
 646 		request_counter_remove_request (directory->details->monitor_counters,
 647 						monitor->request);
 648 		directory->details->monitor_list =
 649 			g_list_remove_link (directory->details->monitor_list, link);
 650 		g_free (monitor);
 651 		g_list_free_1 (link);
 652 	}
 653 }
 654 
 655 static void
 656 remove_monitor (NautilusDirectory *directory,
 657 		NautilusFile *file,
 658 		gconstpointer client)
 659 {
 660 	remove_monitor_link (directory, find_monitor (directory, file, client));
 661 }
 662 
 663 Request
 664 nautilus_directory_set_up_request (NautilusFileAttributes file_attributes)
 665 {
 666 	Request request;
 667 
 668 	request = 0;
 669 	
 670 	if ((file_attributes & NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT) != 0) {
 671 		REQUEST_SET_TYPE (request, REQUEST_DIRECTORY_COUNT);
 672 	}
 673 	
 674 	if ((file_attributes & NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS) != 0) {
 675 		REQUEST_SET_TYPE (request, REQUEST_DEEP_COUNT);
 676 	}
 677 
 678 	if ((file_attributes & NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES) != 0) {
 679 		REQUEST_SET_TYPE (request, REQUEST_MIME_LIST);
 680 	}
 681 	if ((file_attributes & NAUTILUS_FILE_ATTRIBUTE_INFO) != 0) {
 682 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
 683 	}
 684 	
 685 	if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_LINK_INFO) {
 686 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
 687 		REQUEST_SET_TYPE (request, REQUEST_LINK_INFO);
 688 	}
 689 	
 690 	if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT) {
 691 		REQUEST_SET_TYPE (request, REQUEST_TOP_LEFT_TEXT);
 692 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
 693 	}
 694 	
 695 	if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT) {
 696 		REQUEST_SET_TYPE (request, REQUEST_LARGE_TOP_LEFT_TEXT);
 697 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
 698 	}
 699 
 700 	if ((file_attributes & NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO) != 0) {
 701 		REQUEST_SET_TYPE (request, REQUEST_EXTENSION_INFO);
 702 	}
 703 
 704 	if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL) {
 705 		REQUEST_SET_TYPE (request, REQUEST_THUMBNAIL);
 706 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
 707 	}
 708 
 709 	if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_MOUNT) {
 710 		REQUEST_SET_TYPE (request, REQUEST_MOUNT);
 711 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
 712 	}
 713 
 714 	if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO) {
 715 		REQUEST_SET_TYPE (request, REQUEST_FILESYSTEM_INFO);
 716 	}
 717 
 718 	return request;
 719 }
 720 
 721 static void
 722 mime_db_changed_callback (GObject *ignore, NautilusDirectory *dir)
 723 {
 724 	NautilusFileAttributes attrs;
 725 
 726 	g_assert (dir != NULL);
 727 	g_assert (dir->details != NULL);
 728 
 729 	attrs = NAUTILUS_FILE_ATTRIBUTE_INFO |
 730 		NAUTILUS_FILE_ATTRIBUTE_LINK_INFO |
 731 		NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES;
 732 
 733 	nautilus_directory_force_reload_internal (dir, attrs);
 734 }
 735 
 736 void
 737 nautilus_directory_monitor_add_internal (NautilusDirectory *directory,
 738 					 NautilusFile *file,
 739 					 gconstpointer client,
 740 					 gboolean monitor_hidden_files,
 741 					 NautilusFileAttributes file_attributes,
 742 					 NautilusDirectoryCallback callback,
 743 					 gpointer callback_data)
 744 {
 745 	Monitor *monitor;
 746 	GList *file_list;
 747 	char *file_uri = NULL;
 748 	char *dir_uri = NULL;
 749 
 750 	g_assert (NAUTILUS_IS_DIRECTORY (directory));
 751 
 752 	if (file != NULL)
 753 		file_uri = nautilus_file_get_uri (file);
 754 	if (directory != NULL)
 755 		dir_uri = nautilus_directory_get_uri (directory);
 756 	nautilus_profile_start ("uri %s file-uri %s client %p", dir_uri, file_uri, client);
 757 	g_free (dir_uri);
 758 	g_free (file_uri);
 759 
 760 	/* Replace any current monitor for this client/file pair. */
 761 	remove_monitor (directory, file, client);
 762 
 763 	/* Add the new monitor. */
 764 	monitor = g_new (Monitor, 1);
 765 	monitor->file = file;
 766 	monitor->monitor_hidden_files = monitor_hidden_files;
 767 	monitor->client = client;
 768 	monitor->request = nautilus_directory_set_up_request (file_attributes);
 769 
 770 	if (file == NULL) {
 771 		REQUEST_SET_TYPE (monitor->request, REQUEST_FILE_LIST);
 772 	}
 773 	directory->details->monitor_list =
 774 		g_list_prepend (directory->details->monitor_list, monitor);
 775 	request_counter_add_request (directory->details->monitor_counters,
 776 				     monitor->request);
 777 
 778 	if (callback != NULL) {
 779 		file_list = nautilus_directory_get_file_list (directory);
 780 		(* callback) (directory, file_list, callback_data);
 781 		nautilus_file_list_free (file_list);
 782 	}
 783 	
 784 	/* Start the "real" monitoring (FAM or whatever). */
 785 	/* We always monitor the whole directory since in practice
 786 	 * nautilus almost always shows the whole directory anyway, and
 787 	 * it allows us to avoid one file monitor per file in a directory.
 788 	 */
 789 	if (directory->details->monitor == NULL) {
 790 		directory->details->monitor = nautilus_monitor_directory (directory->details->location);
 791 	}
 792 	
 793 
 794 	if (REQUEST_WANTS_TYPE (monitor->request, REQUEST_FILE_INFO) &&
 795 	    directory->details->mime_db_monitor == 0) {
 796 		directory->details->mime_db_monitor =
 797 			g_signal_connect_object (nautilus_signaller_get_current (),
 798 						 "mime_data_changed",
 799 						 G_CALLBACK (mime_db_changed_callback), directory, 0);
 800 	}
 801 
 802 	/* Put the monitor file or all the files on the work queue. */
 803 	if (file != NULL) {
 804 		nautilus_directory_add_file_to_work_queue (directory, file);
 805 	} else {
 806 		add_all_files_to_work_queue (directory);
 807 	}
 808 
 809 	/* Kick off I/O. */
 810 	nautilus_directory_async_state_changed (directory);
 811 	nautilus_profile_end (NULL);
 812 }
 813 
 814 static void
 815 set_file_unconfirmed (NautilusFile *file, gboolean unconfirmed)
 816 {
 817 	NautilusDirectory *directory;
 818 
 819 	g_assert (NAUTILUS_IS_FILE (file));
 820 	g_assert (unconfirmed == FALSE || unconfirmed == TRUE);
 821 
 822 	if (file->details->unconfirmed == unconfirmed) {
 823 		return;
 824 	}
 825 	file->details->unconfirmed = unconfirmed;
 826 
 827 	directory = file->details->directory;
 828 	if (unconfirmed) {
 829 		directory->details->confirmed_file_count--;
 830 	} else {
 831 		directory->details->confirmed_file_count++;
 832 	}
 833 }
 834 
 835 static gboolean show_hidden_files = TRUE;
 836 
 837 static void
 838 show_hidden_files_changed_callback (gpointer callback_data)
 839 {
 840 	show_hidden_files = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES);
 841 }
 842 
 843 static gboolean
 844 should_skip_file (NautilusDirectory *directory, GFileInfo *info)
 845 {
 846 	static gboolean show_hidden_files_changed_callback_installed = FALSE;
 847 
 848 	/* Add the callback once for the life of our process */
 849 	if (!show_hidden_files_changed_callback_installed) {
 850 		g_signal_connect_swapped (nautilus_preferences,
 851 					  "changed::" NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES,
 852 					  G_CALLBACK(show_hidden_files_changed_callback),
 853 					  NULL);
 854 
 855 		show_hidden_files_changed_callback_installed = TRUE;
 856 
 857 		/* Peek for the first time */
 858 		show_hidden_files_changed_callback (NULL);
 859 	}
 860 
 861 	if (!show_hidden_files &&
 862 	    (g_file_info_get_is_hidden (info) ||
 863 	     g_file_info_get_is_backup (info) ||
 864 	     (directory != NULL && directory->details->hidden_file_hash != NULL &&
 865 	      g_hash_table_lookup (directory->details->hidden_file_hash,
 866 				   g_file_info_get_name (info)) != NULL))) {
 867 		return TRUE;
 868 	}
 869 
 870 	return FALSE;
 871 }
 872 
 873 static gboolean
 874 dequeue_pending_idle_callback (gpointer callback_data)
 875 {
 876 	NautilusDirectory *directory;
 877 	GList *pending_file_info;
 878 	GList *node, *next;
 879 	NautilusFile *file;
 880 	GList *changed_files, *added_files;
 881 	GFileInfo *file_info;
 882 	const char *mimetype, *name;
 883 	DirectoryLoadState *dir_load_state;
 884 
 885 	directory = NAUTILUS_DIRECTORY (callback_data);
 886 
 887 	nautilus_directory_ref (directory);
 888 
 889 	nautilus_profile_start ("nitems %d", g_list_length (directory->details->pending_file_info));
 890 
 891 	directory->details->dequeue_pending_idle_id = 0;
 892 
 893 	/* Handle the files in the order we saw them. */
 894 	pending_file_info = g_list_reverse (directory->details->pending_file_info);
 895 	directory->details->pending_file_info = NULL;
 896 
 897 	/* If we are no longer monitoring, then throw away these. */
 898 	if (!nautilus_directory_is_file_list_monitored (directory)) {
 899 		nautilus_directory_async_state_changed (directory);
 900 		goto drain;
 901 	}
 902 
 903 	added_files = NULL;
 904 	changed_files = NULL;
 905 
 906 	dir_load_state = directory->details->directory_load_in_progress;
 907 	
 908 	/* Build a list of NautilusFile objects. */
 909 	for (node = pending_file_info; node != NULL; node = node->next) {
 910 		file_info = node->data;
 911 
 912 		name = g_file_info_get_name (file_info);
 913 		
 914 		/* Update the file count. */
 915 		/* FIXME bugzilla.gnome.org 45063: This could count a
 916 		 * file twice if we get it from both load_directory
 917 		 * and from new_files_callback. Not too hard to fix by
 918 		 * moving this into the actual callback instead of
 919 		 * waiting for the idle function.
 920 		 */
 921 		if (dir_load_state &&
 922 		    !should_skip_file (directory, file_info)) {
 923 			dir_load_state->load_file_count += 1;
 924 
 925 			/* Add the MIME type to the set. */
 926 			mimetype = g_file_info_get_content_type (file_info);
 927 			if (mimetype != NULL) {
 928 				istr_set_insert (dir_load_state->load_mime_list_hash,
 929 						 mimetype);
 930 			}
 931 		}
 932 		
 933 		/* check if the file already exists */
 934 		file = nautilus_directory_find_file_by_name (directory, name);
 935 		if (file != NULL) {
 936 			/* file already exists in dir, check if we still need to
 937 			 *  emit file_added or if it changed */
 938 			set_file_unconfirmed (file, FALSE);
 939 			if (!file->details->is_added) {
 940 				/* We consider this newly added even if its in the list.
 941 				 * This can happen if someone called nautilus_file_get_by_uri()
 942 				 * on a file in the folder before the add signal was
 943 				 * emitted */
 944 				nautilus_file_ref (file);
 945 				file->details->is_added = TRUE;
 946 				added_files = g_list_prepend (added_files, file);
 947 			} else if (nautilus_file_update_info (file, file_info)) {
 948 				/* File changed, notify about the change. */
 949 				nautilus_file_ref (file);
 950 				changed_files = g_list_prepend (changed_files, file);
 951 			}
 952 		} else {
 953 			/* new file, create a nautilus file object and add it to the list */
 954 			file = nautilus_file_new_from_info (directory, file_info);
 955 			nautilus_directory_add_file (directory, file);			
 956 			file->details->is_added = TRUE;
 957 			added_files = g_list_prepend (added_files, file);
 958 		}
 959 	}
 960 
 961 	/* If we are done loading, then we assume that any unconfirmed
 962          * files are gone.
 963 	 */
 964 	if (directory->details->directory_loaded) {
 965 		for (node = directory->details->file_list;
 966 		     node != NULL; node = next) {
 967 			file = NAUTILUS_FILE (node->data);
 968 			next = node->next;
 969 
 970 			if (file->details->unconfirmed) {
 971 				nautilus_file_ref (file);
 972 				changed_files = g_list_prepend (changed_files, file);
 973 				
 974 				nautilus_file_mark_gone (file);
 975 			}
 976 		}
 977 	}
 978 
 979 	/* Send the changed and added signals. */
 980 	nautilus_directory_emit_change_signals (directory, changed_files);
 981 	nautilus_file_list_free (changed_files);
 982 	nautilus_directory_emit_files_added (directory, added_files);
 983 	nautilus_file_list_free (added_files);
 984 
 985 	if (directory->details->directory_loaded &&
 986 	    !directory->details->directory_loaded_sent_notification) {
 987 		/* Send the done_loading signal. */
 988 		nautilus_directory_emit_done_loading (directory);
 989 
 990 		if (dir_load_state) {
 991 			file = dir_load_state->load_directory_file;
 992 			
 993 			file->details->directory_count = dir_load_state->load_file_count;
 994 			file->details->directory_count_is_up_to_date = TRUE;
 995 			file->details->got_directory_count = TRUE;
 996 
 997 			file->details->got_mime_list = TRUE;
 998 			file->details->mime_list_is_up_to_date = TRUE;
 999 			g_list_free_full (file->details->mime_list, g_free);
1000 			file->details->mime_list = istr_set_get_as_list
1001 				(dir_load_state->load_mime_list_hash);
1002 
1003 			nautilus_file_changed (file);
1004 		}
1005 		
1006 		nautilus_directory_async_state_changed (directory);
1007 
1008 		directory->details->directory_loaded_sent_notification = TRUE;
1009 	}
1010 
1011  drain:
1012 	g_list_free_full (pending_file_info, g_object_unref);
1013 
1014 	/* Get the state machine running again. */
1015 	nautilus_directory_async_state_changed (directory);
1016 
1017 	nautilus_profile_end (NULL);
1018 
1019 	nautilus_directory_unref (directory);
1020 	return FALSE;
1021 }
1022 
1023 void
1024 nautilus_directory_schedule_dequeue_pending (NautilusDirectory *directory)
1025 {
1026 	if (directory->details->dequeue_pending_idle_id == 0) {
1027 		directory->details->dequeue_pending_idle_id
1028 			= g_idle_add (dequeue_pending_idle_callback, directory);
1029 	}
1030 }
1031 
1032 static void
1033 directory_load_one (NautilusDirectory *directory,
1034 		    GFileInfo *info)
1035 {
1036 	if (info == NULL) {
1037 		return;
1038 	}
1039 
1040 	if (g_file_info_get_name (info) == NULL) {
1041 		char *uri;
1042 
1043 		uri = nautilus_directory_get_uri (directory);
1044 		g_warning ("Got GFileInfo with NULL name in %s, ignoring. This shouldn't happen unless the gvfs backend is broken.\n", uri);
1045 		g_free (uri);
1046 		
1047 		return;
1048 	}
1049 	
1050 	/* Arrange for the "loading" part of the work. */
1051 	g_object_ref (info);
1052 	directory->details->pending_file_info
1053 		= g_list_prepend (directory->details->pending_file_info, info);
1054 	nautilus_directory_schedule_dequeue_pending (directory);
1055 }
1056 
1057 static void
1058 directory_load_cancel (NautilusDirectory *directory)
1059 {
1060 	NautilusFile *file;
1061 	DirectoryLoadState *state;
1062 
1063 	state = directory->details->directory_load_in_progress;
1064 	if (state != NULL) {
1065 		file = state->load_directory_file;
1066 		file->details->loading_directory = FALSE;
1067 		if (file->details->directory != directory) {
1068 			nautilus_directory_async_state_changed (file->details->directory);
1069 		}
1070 		
1071 		g_cancellable_cancel (state->cancellable);
1072 		state->directory = NULL;
1073 		directory->details->directory_load_in_progress = NULL;
1074 		async_job_end (directory, "file list");
1075 	}
1076 }
1077 
1078 static void
1079 file_list_cancel (NautilusDirectory *directory)
1080 {
1081 	directory_load_cancel (directory);
1082 	
1083 	if (directory->details->dequeue_pending_idle_id != 0) {
1084 		g_source_remove (directory->details->dequeue_pending_idle_id);
1085 		directory->details->dequeue_pending_idle_id = 0;
1086 	}
1087 
1088 	if (directory->details->pending_file_info != NULL) {
1089 		g_list_free_full (directory->details->pending_file_info, g_object_unref);
1090 		directory->details->pending_file_info = NULL;
1091 	}
1092 
1093 	if (directory->details->hidden_file_hash) {
1094 		g_hash_table_remove_all (directory->details->hidden_file_hash);
1095 	}
1096 }
1097 
1098 static void
1099 directory_load_done (NautilusDirectory *directory,
1100 		     GError *error)
1101 {
1102 	GList *node;
1103 
1104 	nautilus_profile_start (NULL);
1105 
1106 	directory->details->directory_loaded = TRUE;
1107 	directory->details->directory_loaded_sent_notification = FALSE;
1108 
1109 	if (error != NULL) {
1110 		/* The load did not complete successfully. This means
1111 		 * we don't know the status of the files in this directory.
1112 		 * We clear the unconfirmed bit on each file here so that
1113 		 * they won't be marked "gone" later -- we don't know enough
1114 		 * about them to know whether they are really gone.
1115 		 */
1116 		for (node = directory->details->file_list;
1117 		     node != NULL; node = node->next) {
1118 			set_file_unconfirmed (NAUTILUS_FILE (node->data), FALSE);
1119 		}
1120 
1121 		nautilus_directory_emit_load_error (directory, error);
1122 	}
1123 
1124 	/* Call the idle function right away. */
1125 	if (directory->details->dequeue_pending_idle_id != 0) {
1126 		g_source_remove (directory->details->dequeue_pending_idle_id);
1127 	}
1128 	dequeue_pending_idle_callback (directory);
1129 
1130 	directory_load_cancel (directory);
1131 
1132 	nautilus_profile_end (NULL);
1133 }
1134 
1135 void
1136 nautilus_directory_monitor_remove_internal (NautilusDirectory *directory,
1137 					    NautilusFile *file,
1138 					    gconstpointer client)
1139 {
1140 	g_assert (NAUTILUS_IS_DIRECTORY (directory));
1141 	g_assert (file == NULL || NAUTILUS_IS_FILE (file));
1142 	g_assert (client != NULL);
1143 
1144 	remove_monitor (directory, file, client);
1145 
1146 	if (directory->details->monitor != NULL
1147 	    && directory->details->monitor_list == NULL) {
1148 		nautilus_monitor_cancel (directory->details->monitor);
1149 		directory->details->monitor = NULL;
1150 	}
1151 
1152 	/* XXX - do we need to remove anything from the work queue? */
1153 
1154 	nautilus_directory_async_state_changed (directory);
1155 }
1156 
1157 FileMonitors *
1158 nautilus_directory_remove_file_monitors (NautilusDirectory *directory,
1159 					 NautilusFile *file)
1160 {
1161 	GList *result, **list, *node, *next;
1162 	Monitor *monitor;
1163 
1164 	g_assert (NAUTILUS_IS_DIRECTORY (directory));
1165 	g_assert (NAUTILUS_IS_FILE (file));
1166 	g_assert (file->details->directory == directory);
1167 
1168 	result = NULL;
1169 
1170 	list = &directory->details->monitor_list;
1171 	for (node = directory->details->monitor_list; node != NULL; node = next) {
1172 		next = node->next;
1173 		monitor = node->data;
1174 
1175 		if (monitor->file == file) {
1176 			*list = g_list_remove_link (*list, node);
1177 			result = g_list_concat (node, result);
1178 			request_counter_remove_request (directory->details->monitor_counters,
1179 							monitor->request);
1180 		}
1181 	}
1182 
1183 	/* XXX - do we need to remove anything from the work queue? */
1184 
1185 	nautilus_directory_async_state_changed (directory);
1186 
1187 	return (FileMonitors *) result;
1188 }
1189 
1190 void
1191 nautilus_directory_add_file_monitors (NautilusDirectory *directory,
1192 				      NautilusFile *file,
1193 				      FileMonitors *monitors)
1194 {
1195 	GList **list;
1196 	GList *l;
1197 	Monitor *monitor;
1198 
1199 	g_assert (NAUTILUS_IS_DIRECTORY (directory));
1200 	g_assert (NAUTILUS_IS_FILE (file));
1201 	g_assert (file->details->directory == directory);
1202 
1203 	if (monitors == NULL) {
1204 		return;
1205 	}
1206 
1207 	for (l = (GList *)monitors; l != NULL; l = l->next) {
1208 		monitor = l->data;
1209 		request_counter_add_request (directory->details->monitor_counters,
1210 					     monitor->request);
1211 	}
1212 
1213 	list = &directory->details->monitor_list;
1214 	*list = g_list_concat (*list, (GList *) monitors);
1215 
1216 	nautilus_directory_add_file_to_work_queue (directory, file);
1217 
1218 	nautilus_directory_async_state_changed (directory);
1219 }
1220 
1221 static int
1222 ready_callback_key_compare (gconstpointer a, gconstpointer b)
1223 {
1224 	const ReadyCallback *callback_a, *callback_b;
1225 
1226 	callback_a = a;
1227 	callback_b = b;
1228 
1229 	if (callback_a->file < callback_b->file) {
1230 		return -1;
1231 	}
1232 	if (callback_a->file > callback_b->file) {
1233 		return 1;
1234 	}
1235 	if (callback_a->file == NULL) {
1236 		/* ANSI C doesn't allow ordered compares of function pointers, so we cast them to
1237 		 * normal pointers to make some overly pedantic compilers (*cough* HP-UX *cough*)
1238 		 * compile this. Of course, on any compiler where ordered function pointers actually
1239 		 * break this probably won't work, but at least it will compile on platforms where it
1240 		 * works, but stupid compilers won't let you use it.
1241 		 */
1242 		if ((void *)callback_a->callback.directory < (void *)callback_b->callback.directory) {
1243 			return -1;
1244 		}
1245 		if ((void *)callback_a->callback.directory > (void *)callback_b->callback.directory) {
1246 			return 1;
1247 		}
1248 	} else {
1249 		if ((void *)callback_a->callback.file < (void *)callback_b->callback.file) {
1250 			return -1;
1251 		}
1252 		if ((void *)callback_a->callback.file > (void *)callback_b->callback.file) {
1253 			return 1;
1254 		}
1255 	}
1256 	if (callback_a->callback_data < callback_b->callback_data) {
1257 		return -1;
1258 	}
1259 	if (callback_a->callback_data > callback_b->callback_data) {
1260 		return 1;
1261 	}
1262 	return 0;
1263 }
1264 
1265 static int
1266 ready_callback_key_compare_only_active (gconstpointer a, gconstpointer b)
1267 {
1268 	const ReadyCallback *callback_a;
1269 
1270 	callback_a = a;
1271 
1272 	/* Non active callbacks never match */
1273 	if (!callback_a->active) {
1274 		return -1;
1275 	}
1276 
1277 	return ready_callback_key_compare (a, b);
1278 }
1279 
1280 static void
1281 ready_callback_call (NautilusDirectory *directory,
1282 		     const ReadyCallback *callback)
1283 {
1284 	GList *file_list;
1285 
1286 	/* Call the callback. */
1287 	if (callback->file != NULL) {
1288 		if (callback->callback.file) {
1289 			(* callback->callback.file) (callback->file,
1290 						     callback->callback_data);
1291 		}
1292 	} else if (callback->callback.directory != NULL) {
1293 		if (directory == NULL ||
1294 		    !REQUEST_WANTS_TYPE (callback->request, REQUEST_FILE_LIST)) {
1295 			file_list = NULL;
1296 		} else {
1297 			file_list = nautilus_directory_get_file_list (directory);
1298 		}
1299 
1300 		/* Pass back the file list if the user was waiting for it. */
1301 		(* callback->callback.directory) (directory,
1302 						  file_list,
1303 						  callback->callback_data);
1304 
1305 		nautilus_file_list_free (file_list);
1306 	}
1307 }
1308 
1309 void
1310 nautilus_directory_call_when_ready_internal (NautilusDirectory *directory,
1311 					     NautilusFile *file,
1312 					     NautilusFileAttributes file_attributes,
1313 					     gboolean wait_for_file_list,
1314 					     NautilusDirectoryCallback directory_callback,
1315 					     NautilusFileCallback file_callback,
1316 					     gpointer callback_data)
1317 {
1318 	ReadyCallback callback;
1319 
1320 	g_assert (directory == NULL || NAUTILUS_IS_DIRECTORY (directory));
1321 	g_assert (file == NULL || NAUTILUS_IS_FILE (file));
1322 	g_assert (file != NULL || directory_callback != NULL);
1323 
1324 	/* Construct a callback object. */
1325 	callback.active = TRUE;
1326 	callback.file = file;
1327 	if (file == NULL) {
1328 		callback.callback.directory = directory_callback;
1329 	} else {
1330 		callback.callback.file = file_callback;
1331 	}
1332 	callback.callback_data = callback_data;
1333 	callback.request = nautilus_directory_set_up_request (file_attributes);
1334 	if (wait_for_file_list) {
1335 		REQUEST_SET_TYPE (callback.request, REQUEST_FILE_LIST);
1336 	}
1337 
1338 	/* Handle the NULL case. */
1339 	if (directory == NULL) {
1340 		ready_callback_call (NULL, &callback);
1341 		return;
1342 	}
1343 
1344 	/* Check if the callback is already there. */
1345 	if (g_list_find_custom (directory->details->call_when_ready_list,
1346 				&callback,
1347 				ready_callback_key_compare_only_active) != NULL) {
1348 		if (file_callback != NULL && directory_callback != NULL) {
1349 			g_warning ("tried to add a new callback while an old one was pending");
1350 		}
1351 		/* NULL callback means, just read it. Conflicts are ok. */
1352 		return;
1353 	}
1354 
1355 	/* Add the new callback to the list. */
1356 	directory->details->call_when_ready_list = g_list_prepend
1357 		(directory->details->call_when_ready_list,
1358 		 g_memdup (&callback, sizeof (callback)));
1359 	request_counter_add_request (directory->details->call_when_ready_counters,
1360 				     callback.request);
1361 
1362 	/* Put the callback file or all the files on the work queue. */
1363 	if (file != NULL) {
1364 		nautilus_directory_add_file_to_work_queue (directory, file);
1365 	} else {
1366 		add_all_files_to_work_queue (directory);
1367 	}
1368 
1369 	nautilus_directory_async_state_changed (directory);
1370 }
1371 
1372 gboolean      
1373 nautilus_directory_check_if_ready_internal (NautilusDirectory *directory,
1374 					    NautilusFile *file,
1375 					    NautilusFileAttributes file_attributes)
1376 {
1377 	Request request;
1378 
1379 	g_assert (NAUTILUS_IS_DIRECTORY (directory));
1380 
1381 	request = nautilus_directory_set_up_request (file_attributes);
1382 	return request_is_satisfied (directory, file, request);
1383 }
1384 
1385 static void
1386 remove_callback_link_keep_data (NautilusDirectory *directory,
1387 				GList *link)
1388 {
1389 	ReadyCallback *callback;
1390 
1391 	callback = link->data;
1392 	
1393 	directory->details->call_when_ready_list = g_list_remove_link
1394 		(directory->details->call_when_ready_list, link);
1395 	
1396 	request_counter_remove_request (directory->details->call_when_ready_counters,
1397 					callback->request);
1398 	g_list_free_1 (link);
1399 }
1400 
1401 static void
1402 remove_callback_link (NautilusDirectory *directory,
1403 		      GList *link)
1404 {
1405 	ReadyCallback *callback;
1406 	
1407 	callback = link->data;
1408 	remove_callback_link_keep_data (directory, link);
1409 	g_free (callback);
1410 }
1411 
1412 void
1413 nautilus_directory_cancel_callback_internal (NautilusDirectory *directory,
1414 					     NautilusFile *file,
1415 					     NautilusDirectoryCallback directory_callback,
1416 					     NautilusFileCallback file_callback,
1417 					     gpointer callback_data)
1418 {
1419 	ReadyCallback callback;
1420 	GList *node;
1421 
1422 	if (directory == NULL) {
1423 		return;
1424 	}
1425 
1426 	g_assert (NAUTILUS_IS_DIRECTORY (directory));
1427 	g_assert (file == NULL || NAUTILUS_IS_FILE (file));
1428 	g_assert (file != NULL || directory_callback != NULL);
1429 	g_assert (file == NULL || file_callback != NULL);
1430 
1431 	/* Construct a callback object. */
1432 	callback.file = file;
1433 	if (file == NULL) {
1434 		callback.callback.directory = directory_callback;
1435 	} else {
1436 		callback.callback.file = file_callback;
1437 	}
1438 	callback.callback_data = callback_data;
1439 
1440 	/* Remove all queued callback from the list (including non-active). */
1441 	do {
1442 		node = g_list_find_custom (directory->details->call_when_ready_list,
1443 					   &callback,
1444 					   ready_callback_key_compare);
1445 		if (node != NULL) {
1446 			remove_callback_link (directory, node);
1447 			
1448 			nautilus_directory_async_state_changed (directory);
1449 		}
1450 	} while (node != NULL);
1451 }
1452 
1453 static void
1454 new_files_state_unref (NewFilesState *state)
1455 {
1456 	state->count--;
1457 
1458 	if (state->count == 0) {
1459 		if (state->directory) {
1460 			state->directory->details->new_files_in_progress =
1461 				g_list_remove (state->directory->details->new_files_in_progress,
1462 					       state);
1463 		}
1464 		
1465 		g_object_unref (state->cancellable);
1466 		g_free (state);
1467 	}
1468 }
1469 
1470 static void
1471 new_files_callback (GObject *source_object,
1472 		    GAsyncResult *res,
1473 		    gpointer user_data)
1474 {
1475 	NautilusDirectory *directory;
1476 	GFileInfo *info;
1477 	NewFilesState *state;
1478 
1479 	state = user_data;
1480 
1481 	if (state->directory == NULL) {
1482 		/* Operation was cancelled. Bail out */
1483 		new_files_state_unref (state);
1484 		return;
1485 	}
1486 	
1487 	directory = nautilus_directory_ref (state->directory);
1488 	
1489 	/* Queue up the new file. */
1490 	info = g_file_query_info_finish (G_FILE (source_object), res, NULL);
1491 	if (info != NULL) {
1492 		directory_load_one (directory, info);
1493 		g_object_unref (info);
1494 	}
1495 
1496 	new_files_state_unref (state);
1497 
1498 	nautilus_directory_unref (directory);
1499 }
1500 
1501 void
1502 nautilus_directory_get_info_for_new_files (NautilusDirectory *directory,
1503 					   GList *location_list)
1504 {
1505 	NewFilesState *state;
1506 	GFile *location;
1507 	GList *l;
1508 
1509 	if (location_list == NULL) {
1510 		return;
1511 	}
1512 	
1513 	state = g_new (NewFilesState, 1);
1514 	state->directory = directory;
1515 	state->cancellable = g_cancellable_new ();
1516 	state->count = 0;
1517 	
1518 	for (l = location_list; l != NULL; l = l->next) {
1519 		location = l->data;
1520 		
1521 		state->count++;
1522 		
1523 		g_file_query_info_async (location,
1524 					 NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
1525 					 0,
1526 					 G_PRIORITY_DEFAULT,
1527 					 state->cancellable,
1528 					 new_files_callback, state);
1529 	}
1530 	
1531 	directory->details->new_files_in_progress
1532 		= g_list_prepend (directory->details->new_files_in_progress,
1533 				  state);
1534 }
1535 
1536 void
1537 nautilus_async_destroying_file (NautilusFile *file)
1538 {
1539 	NautilusDirectory *directory;
1540 	gboolean changed;
1541 	GList *node, *next;
1542 	ReadyCallback *callback;
1543 	Monitor *monitor;
1544 
1545 	directory = file->details->directory;
1546 	changed = FALSE;
1547 
1548 	/* Check for callbacks. */
1549 	for (node = directory->details->call_when_ready_list; node != NULL; node = next) {
1550 		next = node->next;
1551 		callback = node->data;
1552 
1553 		if (callback->file == file) {
1554 			/* Client should have cancelled callback. */
1555 			if (callback->active) {
1556 				g_warning ("destroyed file has call_when_ready pending");
1557 			}
1558 			remove_callback_link (directory, node);
1559 			changed = TRUE;
1560 		}
1561 	}
1562 
1563 	/* Check for monitors. */
1564 	for (node = directory->details->monitor_list; node != NULL; node = next) {
1565 		next = node->next;
1566 		monitor = node->data;
1567 
1568 		if (monitor->file == file) {
1569 			/* Client should have removed monitor earlier. */
1570 			g_warning ("destroyed file still being monitored");
1571 			remove_monitor_link (directory, node);
1572 			changed = TRUE;
1573 		}
1574 	}
1575 
1576 	/* Check if it's a file that's currently being worked on.
1577 	 * If so, make that NULL so it gets canceled right away.
1578 	 */
1579 	if (directory->details->count_in_progress != NULL &&
1580 	    directory->details->count_in_progress->count_file == file) {
1581 		directory->details->count_in_progress->count_file = NULL;
1582 		changed = TRUE;
1583 	}
1584 	if (directory->details->deep_count_file == file) {
1585 		directory->details->deep_count_file = NULL;
1586 		changed = TRUE;
1587 	}
1588 	if (directory->details->mime_list_in_progress != NULL &&
1589 	    directory->details->mime_list_in_progress->mime_list_file == file) {
1590 		directory->details->mime_list_in_progress->mime_list_file = NULL;
1591 		changed = TRUE;
1592 	}
1593 	if (directory->details->get_info_file == file) {
1594 		directory->details->get_info_file = NULL;
1595 		changed = TRUE;
1596 	}
1597 	if (directory->details->top_left_read_state != NULL
1598 	    && directory->details->top_left_read_state->file == file) {
1599 		directory->details->top_left_read_state->file = NULL;
1600 		changed = TRUE;
1601 	}
1602 	if (directory->details->link_info_read_state != NULL &&
1603 	    directory->details->link_info_read_state->file == file) {
1604 		directory->details->link_info_read_state->file = NULL;
1605 		changed = TRUE;
1606 	}
1607 	if (directory->details->extension_info_file == file) {
1608 		directory->details->extension_info_file = NULL;
1609 		changed = TRUE;
1610 	}
1611 
1612 	if (directory->details->thumbnail_state != NULL &&
1613 	    directory->details->thumbnail_state->file ==  file) {
1614 		directory->details->thumbnail_state->file = NULL;
1615 		changed = TRUE;
1616 	}
1617 	
1618 	if (directory->details->mount_state != NULL &&
1619 	    directory->details->mount_state->file ==  file) {
1620 		directory->details->mount_state->file = NULL;
1621 		changed = TRUE;
1622 	}
1623 
1624 	if (directory->details->filesystem_info_state != NULL &&
1625 	    directory->details->filesystem_info_state->file == file) {
1626 		directory->details->filesystem_info_state->file = NULL;
1627 		changed = TRUE;
1628 	}
1629 	
1630 	/* Let the directory take care of the rest. */
1631 	if (changed) {
1632 		nautilus_directory_async_state_changed (directory);
1633 	}
1634 }
1635 
1636 static gboolean
1637 lacks_directory_count (NautilusFile *file)
1638 {
1639 	return !file->details->directory_count_is_up_to_date
1640 		&& nautilus_file_should_show_directory_item_count (file);
1641 }
1642 
1643 static gboolean
1644 should_get_directory_count_now (NautilusFile *file)
1645 {
1646 	return lacks_directory_count (file)
1647 		&& !file->details->loading_directory;
1648 }
1649 
1650 static gboolean
1651 lacks_top_left (NautilusFile *file)
1652 {
1653 	return file->details->file_info_is_up_to_date &&
1654 		!file->details->top_left_text_is_up_to_date 
1655 		&& nautilus_file_should_get_top_left_text (file);
1656 }
1657 
1658 static gboolean
1659 lacks_large_top_left (NautilusFile *file)
1660 {
1661 	return file->details->file_info_is_up_to_date &&
1662 		(!file->details->top_left_text_is_up_to_date ||
1663 		 file->details->got_large_top_left_text != file->details->got_top_left_text)
1664 		&& nautilus_file_should_get_top_left_text (file);
1665 }
1666 static gboolean
1667 lacks_info (NautilusFile *file)
1668 {
1669 	return !file->details->file_info_is_up_to_date
1670 		&& !file->details->is_gone;
1671 }
1672 
1673 static gboolean
1674 lacks_filesystem_info (NautilusFile *file)
1675 {
1676 	return !file->details->filesystem_info_is_up_to_date;
1677 }
1678 
1679 static gboolean
1680 lacks_deep_count (NautilusFile *file)
1681 {
1682 	return file->details->deep_counts_status != NAUTILUS_REQUEST_DONE;
1683 }
1684 
1685 static gboolean
1686 lacks_mime_list (NautilusFile *file)
1687 {
1688 	return !file->details->mime_list_is_up_to_date;
1689 }
1690 
1691 static gboolean
1692 should_get_mime_list (NautilusFile *file)
1693 {
1694 	return lacks_mime_list (file)
1695 		&& !file->details->loading_directory;
1696 }
1697 
1698 static gboolean
1699 lacks_link_info (NautilusFile *file)
1700 {
1701 	if (file->details->file_info_is_up_to_date && 
1702 	    !file->details->link_info_is_up_to_date) {
1703 		if (nautilus_file_is_nautilus_link (file)) {
1704 			return TRUE;
1705 		} else {
1706 			link_info_done (file->details->directory, file, NULL, NULL, NULL, FALSE, FALSE);
1707 			return FALSE;
1708 		}
1709 	} else {
1710 		return FALSE;
1711 	}
1712 }
1713 
1714 static gboolean
1715 lacks_extension_info (NautilusFile *file)
1716 {
1717 	return file->details->pending_info_providers != NULL;
1718 }
1719 
1720 static gboolean
1721 lacks_thumbnail (NautilusFile *file)
1722 {
1723 	return nautilus_file_should_show_thumbnail (file) &&
1724 		file->details->thumbnail_path != NULL &&
1725 		!file->details->thumbnail_is_up_to_date;
1726 }
1727 
1728 static gboolean
1729 lacks_mount (NautilusFile *file)
1730 {
1731 	return (!file->details->mount_is_up_to_date &&
1732 		(
1733 		 /* Unix mountpoint, could be a GMount */
1734 		 file->details->is_mountpoint ||
1735 		 
1736 		 /* The toplevel directory of something */
1737 		 (file->details->type == G_FILE_TYPE_DIRECTORY &&
1738 		  nautilus_file_is_self_owned (file)) ||
1739 		 
1740 		 /* Mountable, could be a mountpoint */
1741 		 (file->details->type == G_FILE_TYPE_MOUNTABLE)
1742 
1743 		 )
1744 		);
1745 }
1746 
1747 static gboolean
1748 has_problem (NautilusDirectory *directory, NautilusFile *file, FileCheck problem)
1749 {
1750 	GList *node;
1751 
1752 	if (file != NULL) {
1753 		return (* problem) (file);
1754 	}
1755 
1756 	for (node = directory->details->file_list; node != NULL; node = node->next) {
1757 		if ((* problem) (node->data)) {
1758 			return TRUE;
1759 		}
1760 	}
1761 
1762 	return FALSE;
1763 }
1764 
1765 static gboolean
1766 request_is_satisfied (NautilusDirectory *directory,
1767 		      NautilusFile *file,
1768 		      Request request)
1769 {
1770 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_LIST) &&
1771 	    !(directory->details->directory_loaded &&
1772 				    directory->details->directory_loaded_sent_notification)) {
1773 		return FALSE;
1774 	}
1775 
1776 	if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
1777 		if (has_problem (directory, file, lacks_directory_count)) {
1778 			return FALSE;
1779 		}
1780 	}
1781 
1782 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
1783 		if (has_problem (directory, file, lacks_info)) {
1784 			return FALSE;
1785 		}
1786 	}
1787 
1788 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) {
1789 		if (has_problem (directory, file, lacks_filesystem_info)) {
1790 			return FALSE;
1791 		}
1792 	}
1793 
1794 	if (REQUEST_WANTS_TYPE (request, REQUEST_TOP_LEFT_TEXT)) {
1795 		if (has_problem (directory, file, lacks_top_left)) {
1796 			return FALSE;
1797 		}
1798 	}
1799 		
1800 	if (REQUEST_WANTS_TYPE (request, REQUEST_LARGE_TOP_LEFT_TEXT)) {
1801 		if (has_problem (directory, file, lacks_large_top_left)) {
1802 			return FALSE;
1803 		}
1804 	}
1805 
1806 	if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
1807 		if (has_problem (directory, file, lacks_deep_count)) {
1808 			return FALSE;
1809 		}
1810 	}
1811 
1812 	if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
1813 		if (has_problem (directory, file, lacks_thumbnail)) {
1814 			return FALSE;
1815 		}
1816 	}
1817 	
1818 	if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
1819 		if (has_problem (directory, file, lacks_mount)) {
1820 			return FALSE;
1821 		}
1822 	}
1823 	
1824 	if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
1825 		if (has_problem (directory, file, lacks_mime_list)) {
1826 			return FALSE;
1827 		}
1828 	}
1829 
1830 	if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
1831 		if (has_problem (directory, file, lacks_link_info)) {
1832 			return FALSE;
1833 		}
1834 	}
1835 
1836 	return TRUE;
1837 }
1838 
1839 static gboolean
1840 call_ready_callbacks_at_idle (gpointer callback_data)
1841 {
1842 	NautilusDirectory *directory;
1843 	GList *node, *next;
1844 	ReadyCallback *callback;
1845 
1846 	directory = NAUTILUS_DIRECTORY (callback_data);
1847 	directory->details->call_ready_idle_id = 0;
1848 
1849 	nautilus_directory_ref (directory);
1850 	
1851 	callback = NULL;
1852 	while (1) {
1853 		/* Check if any callbacks are non-active and call them if they are. */
1854 		for (node = directory->details->call_when_ready_list;
1855 		     node != NULL; node = next) {
1856 			next = node->next;
1857 			callback = node->data;
1858 			if (!callback->active) {
1859 				/* Non-active, remove and call */
1860 				break;
1861 			}
1862 		}
1863 		if (node == NULL) {
1864 			break;
1865 		}
1866 
1867 		/* Callbacks are one-shots, so remove it now. */
1868 		remove_callback_link_keep_data (directory, node);
1869 		
1870 		/* Call the callback. */
1871 		ready_callback_call (directory, callback);
1872 		g_free (callback);
1873 	}
1874 
1875 	nautilus_directory_async_state_changed (directory);
1876 
1877 	nautilus_directory_unref (directory);
1878 	
1879 	return FALSE;
1880 }
1881 
1882 static void
1883 schedule_call_ready_callbacks (NautilusDirectory *directory)
1884 {
1885 	if (directory->details->call_ready_idle_id == 0) {
1886 		directory->details->call_ready_idle_id
1887 			= g_idle_add (call_ready_callbacks_at_idle, directory);
1888 	}
1889 }
1890 
1891 /* Marks all callbacks that are ready as non-active and
1892  * calls them at idle time, unless they are removed
1893  * before then */
1894 static gboolean
1895 call_ready_callbacks (NautilusDirectory *directory)
1896 {
1897 	gboolean found_any;
1898 	GList *node, *next;
1899 	ReadyCallback *callback;
1900 
1901 	found_any = FALSE;
1902 	
1903 	/* Check if any callbacks are satisifed and mark them for call them if they are. */
1904 	for (node = directory->details->call_when_ready_list;
1905 	     node != NULL; node = next) {
1906 		next = node->next;
1907 		callback = node->data;
1908 		if (callback->active &&
1909 		    request_is_satisfied (directory, callback->file, callback->request)) {
1910 			callback->active = FALSE;
1911 			found_any = TRUE;
1912 		}
1913 	}
1914 	
1915 	if (found_any) {
1916 		schedule_call_ready_callbacks (directory);
1917 	}
1918 	
1919 	return found_any;
1920 }
1921 
1922 gboolean
1923 nautilus_directory_has_active_request_for_file (NautilusDirectory *directory,
1924 						NautilusFile *file)
1925 {
1926 	GList *node;
1927 	ReadyCallback *callback;
1928 	Monitor *monitor;
1929 
1930 	for (node = directory->details->call_when_ready_list;
1931 	     node != NULL; node = node->next) {
1932 		callback = node->data;
1933 		if (callback->file == file ||
1934 		    callback->file == NULL) {
1935 			return TRUE;
1936 		}
1937 	}
1938 
1939 	for (node = directory->details->monitor_list;
1940 	     node != NULL; node = node->next) {
1941 		monitor = node->data;
1942 		if (monitor->file == file ||
1943 		    monitor->file == NULL) {
1944 			return TRUE;
1945 		}
1946 	}
1947 
1948 	return FALSE;
1949 }
1950 
1951 
1952 /* This checks if there's a request for monitoring the file list. */
1953 gboolean
1954 nautilus_directory_is_anyone_monitoring_file_list (NautilusDirectory *directory)
1955 {
1956 	if (directory->details->call_when_ready_counters[REQUEST_FILE_LIST] > 0) {
1957 		return TRUE;
1958 	}
1959 
1960 	if (directory->details->monitor_counters[REQUEST_FILE_LIST] > 0) {
1961 		return TRUE;
1962 	}
1963 
1964 	return FALSE;
1965 }
1966 
1967 /* This checks if the file list being monitored. */
1968 gboolean
1969 nautilus_directory_is_file_list_monitored (NautilusDirectory *directory) 
1970 {
1971 	return directory->details->file_list_monitored;
1972 }
1973 
1974 static void
1975 mark_all_files_unconfirmed (NautilusDirectory *directory)
1976 {
1977 	GList *node;
1978 	NautilusFile *file;
1979 
1980 	for (node = directory->details->file_list; node != NULL; node = node->next) {
1981 		file = node->data;
1982 		set_file_unconfirmed (file, TRUE);
1983 	}
1984 }
1985 
1986 static void
1987 read_dot_hidden_file (NautilusDirectory *directory)
1988 {
1989 	gsize file_size;
1990 	char *file_contents;
1991 	GFile *child;
1992 	GFileInfo *info;
1993 	GFileType type;
1994 	int i;
1995 
1996 
1997 	/* FIXME: We only support .hidden on file: uri's for the moment.
1998 	 * Need to figure out if we should do this async or sync to extend
1999 	 * it to all types of uris.
2000 	 */
2001 	if (directory->details->location == NULL ||
2002 	    !g_file_is_native (directory->details->location)) {
2003 		return;
2004 	}
2005 	
2006 	child = g_file_get_child (directory->details->location, ".hidden");
2007 
2008 	type = G_FILE_TYPE_UNKNOWN;
2009 	
2010 	info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL);
2011 	if (info != NULL) {
2012 		type = g_file_info_get_file_type (info);
2013 		g_object_unref (info);
2014 	}
2015 	
2016 	if (type != G_FILE_TYPE_REGULAR) {
2017 		g_object_unref (child);
2018 		return;
2019 	}
2020 
2021 	if (!g_file_load_contents (child, NULL, &file_contents, &file_size, NULL, NULL)) {
2022 		g_object_unref (child);
2023 		return;
2024 	}
2025 
2026 	g_object_unref (child);
2027 
2028 	if (directory->details->hidden_file_hash == NULL) {
2029 		directory->details->hidden_file_hash =
2030 			g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
2031 	}
2032 	
2033 	/* Now parse the data */
2034 	i = 0;
2035 	while (i < file_size) {
2036 		int start;
2037 
2038 		start = i;
2039 		while (i < file_size && file_contents[i] != '\n') {
2040 			i++;
2041 		}
2042 
2043 		if (i > start) {
2044 			char *hidden_filename;
2045 		
2046 			hidden_filename = g_strndup (file_contents + start, i - start);
2047 			g_hash_table_replace (directory->details->hidden_file_hash,
2048 					     hidden_filename, hidden_filename);
2049 		}
2050 
2051 		i++;
2052 		
2053 	}
2054 
2055 	g_free (file_contents);
2056 }
2057 
2058 static void
2059 directory_load_state_free (DirectoryLoadState *state)
2060 {
2061 	if (state->enumerator) {
2062 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2063 			g_file_enumerator_close_async (state->enumerator,
2064 						       0, NULL, NULL, NULL);
2065 		}
2066 		g_object_unref (state->enumerator);
2067 	}
2068 
2069 	if (state->load_mime_list_hash != NULL) {
2070 		istr_set_destroy (state->load_mime_list_hash);
2071 	}
2072 	nautilus_file_unref (state->load_directory_file);
2073 	g_object_unref (state->cancellable);
2074 	g_free (state);
2075 }
2076 
2077 static void
2078 more_files_callback (GObject *source_object,
2079 		     GAsyncResult *res,
2080 		     gpointer user_data)
2081 {
2082 	DirectoryLoadState *state;
2083 	NautilusDirectory *directory;
2084 	GError *error;
2085 	GList *files, *l;
2086 	GFileInfo *info;
2087 
2088 	state = user_data;
2089 
2090 	if (state->directory == NULL) {
2091 		/* Operation was cancelled. Bail out */
2092 		directory_load_state_free (state);
2093 		return;
2094 	}
2095 
2096 	directory = nautilus_directory_ref (state->directory);
2097 
2098 	g_assert (directory->details->directory_load_in_progress != NULL);
2099 	g_assert (directory->details->directory_load_in_progress == state);
2100 
2101 	error = NULL;
2102 	files = g_file_enumerator_next_files_finish (state->enumerator,
2103 						     res, &error);
2104 
2105 	for (l = files; l != NULL; l = l->next) {
2106 		info = l->data;
2107 		directory_load_one (directory, info);
2108 		g_object_unref (info);
2109 	}
2110 
2111 	if (files == NULL) {
2112 		directory_load_done (directory, error);
2113 		directory_load_state_free (state);
2114 	} else {
2115 		g_file_enumerator_next_files_async (state->enumerator,
2116 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2117 						    G_PRIORITY_DEFAULT,
2118 						    state->cancellable,
2119 						    more_files_callback,
2120 						    state);
2121 	}
2122 
2123 	nautilus_directory_unref (directory);
2124 
2125 	if (error) {
2126 		g_error_free (error);
2127 	}
2128 
2129 	g_list_free (files);
2130 }
2131 
2132 static void
2133 enumerate_children_callback (GObject *source_object,
2134 			     GAsyncResult *res,
2135 			     gpointer user_data)
2136 {
2137 	DirectoryLoadState *state;
2138 	GFileEnumerator *enumerator;
2139 	GError *error;
2140 
2141 	state = user_data;
2142 
2143 	if (state->directory == NULL) {
2144 		/* Operation was cancelled. Bail out */
2145 		directory_load_state_free (state);
2146 		return;
2147 	}
2148 	
2149 	error = NULL;
2150 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),
2151 							res, &error);
2152 
2153 	if (enumerator == NULL) {
2154 		directory_load_done (state->directory, error);
2155 		g_error_free (error);
2156 		directory_load_state_free (state);
2157 		return;
2158 	} else {
2159 		state->enumerator = enumerator;
2160 		g_file_enumerator_next_files_async (state->enumerator,
2161 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2162 						    G_PRIORITY_DEFAULT,
2163 						    state->cancellable,
2164 						    more_files_callback,
2165 						    state);
2166 	}
2167 }
2168 
2169 
2170 /* Start monitoring the file list if it isn't already. */
2171 static void
2172 start_monitoring_file_list (NautilusDirectory *directory)
2173 {
2174 	DirectoryLoadState *state;
2175 	
2176 	if (!directory->details->file_list_monitored) {
2177 		g_assert (!directory->details->directory_load_in_progress);
2178 		directory->details->file_list_monitored = TRUE;
2179 		nautilus_file_list_ref (directory->details->file_list);
2180 	}
2181 
2182 	if (directory->details->directory_loaded  ||
2183 	    directory->details->directory_load_in_progress != NULL) {
2184 		return;
2185 	}
2186 
2187 	if (!async_job_start (directory, "file list")) {
2188 		return;
2189 	}
2190 
2191 	mark_all_files_unconfirmed (directory);
2192 
2193 	state = g_new0 (DirectoryLoadState, 1);
2194 	state->directory = directory;
2195 	state->cancellable = g_cancellable_new ();
2196 	state->load_mime_list_hash = istr_set_new ();
2197 	state->load_file_count = 0;
2198 	
2199 	g_assert (directory->details->location != NULL);
2200         state->load_directory_file =
2201 		nautilus_directory_get_corresponding_file (directory);
2202 	state->load_directory_file->details->loading_directory = TRUE;
2203 
2204 	read_dot_hidden_file (directory);
2205 	
2206 	/* Hack to work around kde trash dir */
2207 	if (kde_trash_dir_name != NULL && nautilus_directory_is_desktop_directory (directory)) {
2208 		char *fn;
2209 
2210 		if (directory->details->hidden_file_hash == NULL) {
2211 			directory->details->hidden_file_hash =
2212 				g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
2213 		}
2214 		
2215 		fn = g_strdup (kde_trash_dir_name);
2216 		g_hash_table_replace (directory->details->hidden_file_hash,
2217 				     fn, fn);
2218 	}
2219 
2220 	
2221 #ifdef DEBUG_LOAD_DIRECTORY
2222 	g_message ("load_directory called to monitor file list of %p", directory->details->location);
2223 #endif
2224 	
2225 	directory->details->directory_load_in_progress = state;
2226 	
2227 	g_file_enumerate_children_async (directory->details->location,
2228 					 NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
2229 					 0, /* flags */
2230 					 G_PRIORITY_DEFAULT, /* prio */
2231 					 state->cancellable,
2232 					 enumerate_children_callback,
2233 					 state);
2234 }
2235 
2236 /* Stop monitoring the file list if it is being monitored. */
2237 void
2238 nautilus_directory_stop_monitoring_file_list (NautilusDirectory *directory)
2239 {
2240 	if (!directory->details->file_list_monitored) {
2241 		g_assert (directory->details->directory_load_in_progress == NULL);
2242 		return;
2243 	}
2244 
2245 	directory->details->file_list_monitored = FALSE;
2246 	file_list_cancel (directory);
2247 	nautilus_file_list_unref (directory->details->file_list);
2248 	directory->details->directory_loaded = FALSE;
2249 }
2250 
2251 static void
2252 file_list_start_or_stop (NautilusDirectory *directory)
2253 {
2254 	if (nautilus_directory_is_anyone_monitoring_file_list (directory)) {
2255 		start_monitoring_file_list (directory);
2256 	} else {
2257 		nautilus_directory_stop_monitoring_file_list (directory);
2258 	}
2259 }
2260 
2261 void
2262 nautilus_file_invalidate_count_and_mime_list (NautilusFile *file)
2263 {
2264 	NautilusFileAttributes attributes;
2265 	
2266 	attributes = NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
2267 		NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES;
2268 	
2269 	nautilus_file_invalidate_attributes (file, attributes);
2270 }
2271 
2272 
2273 /* Reset count and mime list. Invalidating deep counts is handled by
2274  * itself elsewhere because it's a relatively heavyweight and
2275  * special-purpose operation (see bug 5863). Also, the shallow count
2276  * needs to be refreshed when filtering changes, but the deep count
2277  * deliberately does not take filtering into account.
2278  */
2279 void
2280 nautilus_directory_invalidate_count_and_mime_list (NautilusDirectory *directory)
2281 {
2282 	NautilusFile *file;
2283 
2284 	file = nautilus_directory_get_existing_corresponding_file (directory);
2285 	if (file != NULL) {
2286 		nautilus_file_invalidate_count_and_mime_list (file);
2287 	}
2288 	
2289 	nautilus_file_unref (file);
2290 }
2291 
2292 static void
2293 nautilus_directory_invalidate_file_attributes (NautilusDirectory      *directory,
2294 					       NautilusFileAttributes  file_attributes)
2295 {
2296 	GList *node;
2297 
2298 	cancel_loading_attributes (directory, file_attributes);
2299 
2300 	for (node = directory->details->file_list; node != NULL; node = node->next) {
2301 		nautilus_file_invalidate_attributes_internal (NAUTILUS_FILE (node->data),
2302 							      file_attributes);
2303 	}
2304 
2305 	if (directory->details->as_file != NULL) {
2306 		nautilus_file_invalidate_attributes_internal (directory->details->as_file,
2307 							      file_attributes);
2308 	}
2309 }
2310 
2311 void
2312 nautilus_directory_force_reload_internal (NautilusDirectory     *directory,
2313 					  NautilusFileAttributes file_attributes)
2314 {
2315 	nautilus_profile_start (NULL);
2316 
2317 	/* invalidate attributes that are getting reloaded for all files */
2318 	nautilus_directory_invalidate_file_attributes (directory, file_attributes);
2319 
2320 	/* Start a new directory load. */
2321 	file_list_cancel (directory);
2322 	directory->details->directory_loaded = FALSE;
2323 
2324 	/* Start a new directory count. */
2325 	nautilus_directory_invalidate_count_and_mime_list (directory);
2326 
2327 	add_all_files_to_work_queue (directory);
2328 	nautilus_directory_async_state_changed (directory);
2329 
2330 	nautilus_profile_end (NULL);
2331 }
2332 
2333 static gboolean
2334 monitor_includes_file (const Monitor *monitor,
2335 		       NautilusFile *file)
2336 {
2337 	if (monitor->file == file) {
2338 		return TRUE;
2339 	}
2340 	if (monitor->file != NULL) {
2341 		return FALSE;
2342 	}
2343 	if (file == file->details->directory->details->as_file) {
2344 		return FALSE;
2345 	}
2346 	return nautilus_file_should_show (file,
2347 					  monitor->monitor_hidden_files,
2348 					  TRUE);
2349 }
2350 
2351 static gboolean
2352 is_needy (NautilusFile *file,
2353 	  FileCheck check_missing,
2354 	  RequestType request_type_wanted)
2355 {
2356 	NautilusDirectory *directory;
2357 	GList *node;
2358 	ReadyCallback *callback;
2359 	Monitor *monitor;
2360 
2361 	if (!(* check_missing) (file)) {
2362 		return FALSE;
2363 	}
2364 
2365 	directory = file->details->directory;
2366 	if (directory->details->call_when_ready_counters[request_type_wanted] > 0) {
2367 		for (node = directory->details->call_when_ready_list;
2368 		     node != NULL; node = node->next) {
2369 			callback = node->data;
2370 			if (callback->active &&
2371 			    REQUEST_WANTS_TYPE (callback->request, request_type_wanted)) {
2372 				if (callback->file == file) {
2373 					return TRUE;
2374 				}
2375 				if (callback->file == NULL
2376 				    && file != directory->details->as_file) {
2377 					return TRUE;
2378 				}
2379 			}
2380 		}
2381 	}
2382 	
2383 	if (directory->details->monitor_counters[request_type_wanted] > 0) {
2384 		for (node = directory->details->monitor_list;
2385 		     node != NULL; node = node->next) {
2386 			monitor = node->data;
2387 			if (REQUEST_WANTS_TYPE (monitor->request, request_type_wanted)) {
2388 				if (monitor_includes_file (monitor, file)) {
2389 					return TRUE;
2390 				}
2391 			}
2392 		}
2393 	}
2394 	return FALSE;
2395 }
2396 
2397 static void
2398 directory_count_stop (NautilusDirectory *directory)
2399 {
2400 	NautilusFile *file;
2401 
2402 	if (directory->details->count_in_progress != NULL) {
2403 		file = directory->details->count_in_progress->count_file;
2404 		if (file != NULL) {
2405 			g_assert (NAUTILUS_IS_FILE (file));
2406 			g_assert (file->details->directory == directory);
2407 			if (is_needy (file,
2408 				      should_get_directory_count_now,
2409 				      REQUEST_DIRECTORY_COUNT)) {
2410 				return;
2411 			}
2412 		}
2413 
2414 		/* The count is not wanted, so stop it. */
2415 		directory_count_cancel (directory);
2416 	}
2417 }
2418 
2419 static guint
2420 count_non_skipped_files (GList *list)
2421 {
2422 	guint count;
2423 	GList *node;
2424 	GFileInfo *info;
2425 
2426 	count = 0;
2427 	for (node = list; node != NULL; node = node->next) {
2428 		info = node->data;
2429 		if (!should_skip_file (NULL, info)) {
2430 			count += 1;
2431 		}
2432 	}
2433 	return count;
2434 }
2435 
2436 static void
2437 count_children_done (NautilusDirectory *directory,
2438 		     NautilusFile *count_file,
2439 		     gboolean succeeded,
2440 		     int count)
2441 {
2442 	g_assert (NAUTILUS_IS_FILE (count_file));
2443 
2444 	count_file->details->directory_count_is_up_to_date = TRUE;
2445 
2446 	/* Record either a failure or success. */
2447 	if (!succeeded) {
2448 		count_file->details->directory_count_failed = TRUE;
2449 		count_file->details->got_directory_count = FALSE;
2450 		count_file->details->directory_count = 0;
2451 	} else {
2452 		count_file->details->directory_count_failed = FALSE;
2453 		count_file->details->got_directory_count = TRUE;
2454 		count_file->details->directory_count = count;
2455 	}
2456 	directory->details->count_in_progress = NULL;
2457 
2458 	/* Send file-changed even if count failed, so interested parties can
2459 	 * distinguish between unknowable and not-yet-known cases.
2460 	 */
2461 	nautilus_file_changed (count_file);
2462 
2463 	/* Start up the next one. */
2464 	async_job_end (directory, "directory count");
2465 	nautilus_directory_async_state_changed (directory);
2466 }
2467 
2468 static void
2469 directory_count_state_free (DirectoryCountState *state)
2470 {
2471 	if (state->enumerator) {
2472 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2473 			g_file_enumerator_close_async (state->enumerator,
2474 						       0, NULL, NULL, NULL);
2475 		}
2476 		g_object_unref (state->enumerator);
2477 	}
2478 	g_object_unref (state->cancellable);
2479 	nautilus_directory_unref (state->directory);
2480 	g_free (state);
2481 }
2482 
2483 static void
2484 count_more_files_callback (GObject *source_object,
2485 			   GAsyncResult *res,
2486 			   gpointer user_data)
2487 {
2488 	DirectoryCountState *state;
2489 	NautilusDirectory *directory;
2490 	GError *error;
2491 	GList *files;
2492 
2493 	state = user_data;
2494 	directory = state->directory;
2495 	
2496 	if (g_cancellable_is_cancelled (state->cancellable)) {
2497 		/* Operation was cancelled. Bail out */
2498 		directory->details->count_in_progress = NULL;
2499 
2500 		async_job_end (directory, "directory count");
2501 		nautilus_directory_async_state_changed (directory);
2502 		
2503 		directory_count_state_free (state);
2504 
2505 		return;
2506 	}
2507 
2508 	g_assert (directory->details->count_in_progress != NULL);
2509 	g_assert (directory->details->count_in_progress == state);
2510 
2511 	error = NULL;
2512 	files = g_file_enumerator_next_files_finish (state->enumerator,
2513 						     res, &error);
2514 
2515 	state->file_count += count_non_skipped_files (files);
2516 	
2517 	if (files == NULL) {
2518 		count_children_done (directory, state->count_file,
2519 				     TRUE, state->file_count);
2520 		directory_count_state_free (state);
2521 	} else {
2522 		g_file_enumerator_next_files_async (state->enumerator,
2523 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2524 						    G_PRIORITY_DEFAULT,
2525 						    state->cancellable,
2526 						    count_more_files_callback,
2527 						    state);
2528 	}
2529 
2530 	g_list_free_full (files, g_object_unref);
2531 
2532 	if (error) {
2533 		g_error_free (error);
2534 	}
2535 }
2536 
2537 static void
2538 count_children_callback (GObject *source_object,
2539 			 GAsyncResult *res,
2540 			 gpointer user_data)
2541 {
2542 	DirectoryCountState *state;
2543 	GFileEnumerator *enumerator;
2544 	NautilusDirectory *directory;
2545 	GError *error;
2546 
2547 	state = user_data;
2548 
2549 	if (g_cancellable_is_cancelled (state->cancellable)) {
2550 		/* Operation was cancelled. Bail out */
2551 		directory = state->directory;
2552 		directory->details->count_in_progress = NULL;
2553 
2554 		async_job_end (directory, "directory count");
2555 		nautilus_directory_async_state_changed (directory);
2556 		
2557 		directory_count_state_free (state);
2558 
2559 		return;
2560 	}
2561 	
2562 	error = NULL;
2563 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),
2564 							res, &error);
2565 
2566 	if (enumerator == NULL) {
2567 		count_children_done (state->directory,
2568 				     state->count_file,
2569 				     FALSE, 0);
2570 		g_error_free (error);
2571 		directory_count_state_free (state);
2572 		return;
2573 	} else {
2574 		state->enumerator = enumerator;
2575 		g_file_enumerator_next_files_async (state->enumerator,
2576 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2577 						    G_PRIORITY_DEFAULT,
2578 						    state->cancellable,
2579 						    count_more_files_callback,
2580 						    state);
2581 	}
2582 }
2583 
2584 static void
2585 directory_count_start (NautilusDirectory *directory,
2586 		       NautilusFile *file,
2587 		       gboolean *doing_io)
2588 {
2589 	DirectoryCountState *state;
2590 	GFile *location;
2591 
2592 	if (directory->details->count_in_progress != NULL) {
2593 		*doing_io = TRUE;
2594 		return;
2595 	}
2596 
2597 	if (!is_needy (file, 
2598 		       should_get_directory_count_now,
2599 		       REQUEST_DIRECTORY_COUNT)) {
2600 		return;
2601 	}
2602 	*doing_io = TRUE;
2603 
2604 	if (!nautilus_file_is_directory (file)) {
2605 		file->details->directory_count_is_up_to_date = TRUE;
2606 		file->details->directory_count_failed = FALSE;
2607 		file->details->got_directory_count = FALSE;
2608 		
2609 		nautilus_directory_async_state_changed (directory);
2610 		return;
2611 	}
2612 
2613 	if (!async_job_start (directory, "directory count")) {
2614 		return;
2615 	}
2616 
2617 	/* Start counting. */
2618 	state = g_new0 (DirectoryCountState, 1);
2619 	state->count_file = file;
2620 	state->directory = nautilus_directory_ref (directory);
2621 	state->cancellable = g_cancellable_new ();
2622 	
2623 	directory->details->count_in_progress = state;
2624 	
2625 	location = nautilus_file_get_location (file);
2626 #ifdef DEBUG_LOAD_DIRECTORY		
2627 	{
2628 		char *uri;
2629 		uri = g_file_get_uri (location);
2630 		g_message ("load_directory called to get shallow file count for %s", uri);
2631 		g_free (uri);
2632 	}
2633 #endif
2634 
2635 	g_file_enumerate_children_async (location,
2636 					 G_FILE_ATTRIBUTE_STANDARD_NAME ","
2637 					 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
2638 					 G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP,
2639 					 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, /* flags */
2640 					 G_PRIORITY_DEFAULT, /* prio */
2641 					 state->cancellable,
2642 					 count_children_callback,
2643 					 state);
2644 	g_object_unref (location);
2645 }
2646 
2647 static inline gboolean
2648 seen_inode (DeepCountState *state,
2649 	    GFileInfo *info)
2650 {
2651 	guint64 inode, inode2;
2652 	guint i;
2653 
2654 	inode = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE);
2655 
2656 	if (inode != 0) {
2657 		for (i = 0; i < state->seen_deep_count_inodes->len; i++) {
2658 			inode2 = g_array_index (state->seen_deep_count_inodes, guint64, i);
2659 			if (inode == inode2) {
2660 				return TRUE;
2661 			}
2662 		}
2663 	}
2664 
2665 	return FALSE;
2666 }
2667 
2668 static inline void
2669 mark_inode_as_seen (DeepCountState *state,
2670 		    GFileInfo *info)
2671 {
2672 	guint64 inode;
2673 
2674 	inode = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE);
2675 	if (inode != 0) {
2676 		g_array_append_val (state->seen_deep_count_inodes, inode);
2677 	}
2678 }
2679 
2680 static void
2681 deep_count_one (DeepCountState *state,
2682 		GFileInfo *info)
2683 {
2684 	NautilusFile *file;
2685 	GFile *subdir;
2686 	gboolean is_seen_inode;
2687 
2688 	if (should_skip_file (NULL, info)) {
2689 		return;
2690 	}
2691 
2692 	is_seen_inode = seen_inode (state, info);
2693 	if (!is_seen_inode) {
2694 		mark_inode_as_seen (state, info);
2695 	}
2696 
2697 	file = state->directory->details->deep_count_file;
2698 
2699 	if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
2700 		/* Count the directory. */
2701 		file->details->deep_directory_count += 1;
2702 
2703 		/* Record the fact that we have to descend into this directory. */
2704 
2705 		subdir = g_file_get_child (state->deep_count_location, g_file_info_get_name (info));
2706 		state->deep_count_subdirectories = g_list_prepend
2707 			(state->deep_count_subdirectories, subdir);
2708 	} else {
2709 		/* Even non-regular files count as files. */
2710 		file->details->deep_file_count += 1;
2711 	}
2712 
2713 	/* Count the size. */
2714 	if (!is_seen_inode && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) {
2715 		file->details->deep_size += g_file_info_get_size (info);
2716 	}
2717 }
2718 
2719 static void
2720 deep_count_state_free (DeepCountState *state)
2721 {
2722 	if (state->enumerator) {
2723 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2724 			g_file_enumerator_close_async (state->enumerator,
2725 						       0, NULL, NULL, NULL);
2726 		}
2727 		g_object_unref (state->enumerator);
2728 	}
2729 	g_object_unref (state->cancellable);
2730 	if (state->deep_count_location) {
2731 		g_object_unref (state->deep_count_location);
2732 	}
2733 	g_list_free_full (state->deep_count_subdirectories, g_object_unref);
2734 	g_array_free (state->seen_deep_count_inodes, TRUE);
2735 	g_free (state);
2736 }
2737 
2738 static void
2739 deep_count_next_dir (DeepCountState *state)
2740 {
2741 	GFile *location;
2742 	NautilusFile *file;
2743 	NautilusDirectory *directory;
2744 	gboolean done;
2745 
2746 	directory = state->directory;
2747 	
2748 	g_object_unref (state->deep_count_location);
2749 	state->deep_count_location = NULL;
2750 
2751 	done = FALSE;
2752 	file = directory->details->deep_count_file;
2753 	
2754 	if (state->deep_count_subdirectories != NULL) {
2755 		/* Work on a new directory. */
2756 		location = state->deep_count_subdirectories->data;
2757 		state->deep_count_subdirectories = g_list_remove
2758 			(state->deep_count_subdirectories, location);
2759 		deep_count_load (state, location);
2760 		g_object_unref (location);
2761 	} else {
2762 		file->details->deep_counts_status = NAUTILUS_REQUEST_DONE;
2763 		directory->details->deep_count_file = NULL;
2764 		directory->details->deep_count_in_progress = NULL;
2765 		deep_count_state_free (state);
2766 		done = TRUE;
2767 	}
2768 	
2769 	nautilus_file_updated_deep_count_in_progress (file);
2770 
2771 	if (done) {
2772 		nautilus_file_changed (file);
2773 		async_job_end (directory, "deep count");
2774 		nautilus_directory_async_state_changed (directory);
2775 	}
2776 }
2777 
2778 static void
2779 deep_count_more_files_callback (GObject *source_object,
2780 				GAsyncResult *res,
2781 				gpointer user_data)
2782 {
2783 	DeepCountState *state;
2784 	NautilusDirectory *directory;
2785 	GList *files, *l;
2786 	GFileInfo *info;
2787 
2788 	state = user_data;
2789 
2790 	if (state->directory == NULL) {
2791 		/* Operation was cancelled. Bail out */
2792 		deep_count_state_free (state);
2793 		return;
2794 	}
2795 
2796 	directory = nautilus_directory_ref (state->directory);
2797 	
2798 	g_assert (directory->details->deep_count_in_progress != NULL);
2799 	g_assert (directory->details->deep_count_in_progress == state);
2800 
2801 	files = g_file_enumerator_next_files_finish (state->enumerator,
2802 						     res, NULL);
2803 
2804 	for (l = files; l != NULL; l = l->next)	{
2805 		info = l->data;
2806 		deep_count_one (state, info);
2807 		g_object_unref (info);
2808 	}
2809 	
2810 	if (files == NULL) {
2811 		g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL);
2812 		g_object_unref (state->enumerator);
2813 		state->enumerator = NULL;
2814 		
2815 		deep_count_next_dir (state);
2816 	} else {
2817 		g_file_enumerator_next_files_async (state->enumerator,
2818 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2819 						    G_PRIORITY_LOW,
2820 						    state->cancellable,
2821 						    deep_count_more_files_callback,
2822 						    state);
2823 	}
2824 
2825 	g_list_free (files);
2826 
2827 	nautilus_directory_unref (directory);
2828 }
2829 
2830 static void
2831 deep_count_callback (GObject *source_object,
2832 		     GAsyncResult *res,
2833 		     gpointer user_data)
2834 {
2835 	DeepCountState *state;
2836 	GFileEnumerator *enumerator;
2837 	NautilusFile *file;
2838 
2839 	state = user_data;
2840 
2841 	if (state->directory == NULL) {
2842 		/* Operation was cancelled. Bail out */
2843 		deep_count_state_free (state);
2844 		return;
2845 	}
2846 
2847 	file = state->directory->details->deep_count_file;
2848 
2849 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),	res, NULL);
2850 	
2851 	if (enumerator == NULL) {
2852 		file->details->deep_unreadable_count += 1;
2853 		
2854 		deep_count_next_dir (state);
2855 	} else {
2856 		state->enumerator = enumerator;
2857 		g_file_enumerator_next_files_async (state->enumerator,
2858 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2859 						    G_PRIORITY_LOW,
2860 						    state->cancellable,
2861 						    deep_count_more_files_callback,
2862 						    state);
2863 	}
2864 }
2865 
2866 
2867 static void
2868 deep_count_load (DeepCountState *state, GFile *location)
2869 {
2870 	state->deep_count_location = g_object_ref (location);
2871 
2872 #ifdef DEBUG_LOAD_DIRECTORY		
2873 	g_message ("load_directory called to get deep file count for %p", location);
2874 #endif	
2875 	g_file_enumerate_children_async (state->deep_count_location,
2876 					 G_FILE_ATTRIBUTE_STANDARD_NAME ","
2877 					 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
2878 					 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
2879 					 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
2880 					 G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP ","
2881 					 G_FILE_ATTRIBUTE_UNIX_INODE,
2882 					 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, /* flags */
2883 					 G_PRIORITY_LOW, /* prio */
2884 					 state->cancellable,
2885 					 deep_count_callback,
2886 					 state);
2887 }
2888 
2889 static void
2890 deep_count_stop (NautilusDirectory *directory)
2891 {
2892 	NautilusFile *file;
2893 
2894 	if (directory->details->deep_count_in_progress != NULL) {
2895 		file = directory->details->deep_count_file;
2896 		if (file != NULL) {
2897 			g_assert (NAUTILUS_IS_FILE (file));
2898 			g_assert (file->details->directory == directory);
2899 			if (is_needy (file,
2900 				      lacks_deep_count,
2901 				      REQUEST_DEEP_COUNT)) {
2902 				return;
2903 			}
2904 		}
2905 
2906 		/* The count is not wanted, so stop it. */
2907 		deep_count_cancel (directory);
2908 	}
2909 }
2910 
2911 static void
2912 deep_count_start (NautilusDirectory *directory,
2913 		  NautilusFile *file,
2914 		  gboolean *doing_io)
2915 {
2916 	GFile *location;
2917 	DeepCountState *state;
2918 	
2919 	if (directory->details->deep_count_in_progress != NULL) {
2920 		*doing_io = TRUE;
2921 		return;
2922 	}
2923 
2924 	if (!is_needy (file,
2925 		       lacks_deep_count,
2926 		       REQUEST_DEEP_COUNT)) {
2927 		return;
2928 	}
2929 	*doing_io = TRUE;
2930 
2931 	if (!nautilus_file_is_directory (file)) {
2932 		file->details->deep_counts_status = NAUTILUS_REQUEST_DONE;
2933 
2934 		nautilus_directory_async_state_changed (directory);
2935 		return;
2936 	}
2937 
2938 	if (!async_job_start (directory, "deep count")) {
2939 		return;
2940 	}
2941 
2942 	/* Start counting. */
2943 	file->details->deep_counts_status = NAUTILUS_REQUEST_IN_PROGRESS;
2944 	file->details->deep_directory_count = 0;
2945 	file->details->deep_file_count = 0;
2946 	file->details->deep_unreadable_count = 0;
2947 	file->details->deep_size = 0;
2948 	directory->details->deep_count_file = file;
2949 
2950 	state = g_new0 (DeepCountState, 1);
2951 	state->directory = directory;
2952 	state->cancellable = g_cancellable_new ();
2953 	state->seen_deep_count_inodes = g_array_new (FALSE, TRUE, sizeof (guint64));
2954 
2955 	directory->details->deep_count_in_progress = state;
2956 	
2957 	location = nautilus_file_get_location (file);
2958 	deep_count_load (state, location);
2959 	g_object_unref (location);
2960 }
2961 
2962 static void
2963 mime_list_stop (NautilusDirectory *directory)
2964 {
2965 	NautilusFile *file;
2966 
2967 	if (directory->details->mime_list_in_progress != NULL) {
2968 		file = directory->details->mime_list_in_progress->mime_list_file;
2969 		if (file != NULL) {
2970 			g_assert (NAUTILUS_IS_FILE (file));
2971 			g_assert (file->details->directory == directory);
2972 			if (is_needy (file,
2973 				      should_get_mime_list,
2974 				      REQUEST_MIME_LIST)) {
2975 				return;
2976 			}
2977 		}
2978 		
2979 		/* The count is not wanted, so stop it. */
2980 		mime_list_cancel (directory);
2981 	}
2982 }
2983 
2984 static void
2985 mime_list_state_free (MimeListState *state)
2986 {
2987 	if (state->enumerator) {
2988 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2989 			g_file_enumerator_close_async (state->enumerator,
2990 						       0, NULL, NULL, NULL);
2991 		}
2992 		g_object_unref (state->enumerator);
2993 	}
2994 	g_object_unref (state->cancellable);
2995 	istr_set_destroy (state->mime_list_hash);
2996 	nautilus_directory_unref (state->directory);
2997 	g_free (state);
2998 }
2999 
3000 
3001 static void
3002 mime_list_done (MimeListState *state, gboolean success)
3003 {
3004 	NautilusFile *file;
3005 	NautilusDirectory *directory;
3006 
3007 	directory = state->directory;
3008 	g_assert (directory != NULL);
3009 	
3010 	file = state->mime_list_file;
3011 	
3012 	file->details->mime_list_is_up_to_date = TRUE;
3013 	g_list_free_full (file->details->mime_list, g_free);
3014 	if (success) {
3015 		file->details->mime_list_failed = TRUE;
3016 		file->details->mime_list = NULL;
3017 	} else {
3018 		file->details->got_mime_list = TRUE;
3019 		file->details->mime_list = istr_set_get_as_list	(state->mime_list_hash);
3020 	}
3021 	directory->details->mime_list_in_progress = NULL;
3022 
3023 	/* Send file-changed even if getting the item type list
3024 	 * failed, so interested parties can distinguish between
3025 	 * unknowable and not-yet-known cases.
3026 	 */
3027 	nautilus_file_changed (file);
3028 
3029 	/* Start up the next one. */
3030 	async_job_end (directory, "MIME list");
3031 	nautilus_directory_async_state_changed (directory);
3032 }
3033 
3034 static void
3035 mime_list_one (MimeListState *state,
3036 	       GFileInfo *info)
3037 {
3038 	const char *mime_type;
3039 	
3040 	if (should_skip_file (NULL, info)) {
3041 		g_object_unref (info);
3042 		return;
3043 	}
3044 
3045 	mime_type = g_file_info_get_content_type (info);
3046 	if (mime_type != NULL) {
3047 		istr_set_insert (state->mime_list_hash, mime_type);
3048 	}
3049 }
3050 
3051 static void
3052 mime_list_callback (GObject *source_object,
3053 		    GAsyncResult *res,
3054 		    gpointer user_data)
3055 {
3056 	MimeListState *state;
3057 	NautilusDirectory *directory;
3058 	GError *error;
3059 	GList *files, *l;
3060 	GFileInfo *info;
3061 
3062 	state = user_data;
3063 	directory = state->directory;
3064 
3065 	if (g_cancellable_is_cancelled (state->cancellable)) {
3066 		/* Operation was cancelled. Bail out */
3067 		directory->details->mime_list_in_progress = NULL;
3068 
3069 		async_job_end (directory, "MIME list");
3070 		nautilus_directory_async_state_changed (directory);
3071 		
3072 		mime_list_state_free (state);
3073 
3074 		return;
3075 	}
3076 
3077 	g_assert (directory->details->mime_list_in_progress != NULL);
3078 	g_assert (directory->details->mime_list_in_progress == state);
3079 
3080 	error = NULL;
3081 	files = g_file_enumerator_next_files_finish (state->enumerator,
3082 						     res, &error);
3083 
3084 	for (l = files; l != NULL; l = l->next) {
3085 		info = l->data;
3086 		mime_list_one (state, info);
3087 		g_object_unref (info);
3088 	}
3089 
3090 	if (files == NULL) {
3091 		mime_list_done (state, error != NULL);
3092 		mime_list_state_free (state);
3093 	} else {
3094 		g_file_enumerator_next_files_async (state->enumerator,
3095 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
3096 						    G_PRIORITY_DEFAULT,
3097 						    state->cancellable,
3098 						    mime_list_callback,
3099 						    state);
3100 	}
3101 
3102 	g_list_free (files);
3103 	
3104 	if (error) {
3105 		g_error_free (error);
3106 	}
3107 }
3108 
3109 static void
3110 list_mime_enum_callback (GObject *source_object,
3111 			 GAsyncResult *res,
3112 			 gpointer user_data)
3113 {
3114 	MimeListState *state;
3115 	GFileEnumerator *enumerator;
3116 	NautilusDirectory *directory;
3117 	GError *error;
3118 
3119 	state = user_data;
3120 
3121 	if (g_cancellable_is_cancelled (state->cancellable)) {
3122 		/* Operation was cancelled. Bail out */
3123 		directory = state->directory;
3124 		directory->details->mime_list_in_progress = NULL;
3125 
3126 		async_job_end (directory, "MIME list");
3127 		nautilus_directory_async_state_changed (directory);
3128 		
3129 		mime_list_state_free (state);
3130 
3131 		return;
3132 	}
3133 	
3134 	error = NULL;
3135 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),
3136 							res, &error);
3137 
3138 	if (enumerator == NULL) {
3139 		mime_list_done (state, FALSE);
3140 		g_error_free (error);
3141 		mime_list_state_free (state);
3142 		return;
3143 	} else {
3144 		state->enumerator = enumerator;
3145 		g_file_enumerator_next_files_async (state->enumerator,
3146 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
3147 						    G_PRIORITY_DEFAULT,
3148 						    state->cancellable,
3149 						    mime_list_callback,
3150 						    state);
3151 	}
3152 }
3153 
3154 static void
3155 mime_list_start (NautilusDirectory *directory,
3156 		 NautilusFile *file,
3157 		 gboolean *doing_io)
3158 {
3159 	MimeListState *state;
3160 	GFile *location;
3161 
3162 	mime_list_stop (directory);
3163 
3164 	if (directory->details->mime_list_in_progress != NULL) {
3165 		*doing_io = TRUE;
3166 		return;
3167 	}
3168 
3169 	/* Figure out which file to get a mime list for. */
3170 	if (!is_needy (file,
3171 		       should_get_mime_list,
3172 		       REQUEST_MIME_LIST)) {
3173 		return;
3174 	}
3175 	*doing_io = TRUE;
3176 
3177 	if (!nautilus_file_is_directory (file)) {
3178 		g_list_free (file->details->mime_list);
3179 		file->details->mime_list_failed = FALSE;
3180 		file->details->got_mime_list = FALSE;
3181 		file->details->mime_list_is_up_to_date = TRUE;
3182 
3183 		nautilus_directory_async_state_changed (directory);
3184 		return;
3185 	}
3186 
3187 	if (!async_job_start (directory, "MIME list")) {
3188 		return;
3189 	}
3190 
3191 
3192 	state = g_new0 (MimeListState, 1);
3193 	state->mime_list_file = file;
3194 	state->directory = nautilus_directory_ref (directory);
3195 	state->cancellable = g_cancellable_new ();
3196 	state->mime_list_hash = istr_set_new ();
3197 
3198 	directory->details->mime_list_in_progress = state;
3199 
3200 	location = nautilus_file_get_location (file);
3201 #ifdef DEBUG_LOAD_DIRECTORY		
3202 	{
3203 		char *uri;
3204 		uri = g_file_get_uri (location);
3205 		g_message ("load_directory called to get MIME list of %s", uri);
3206 		g_free (uri);
3207 	}
3208 #endif	
3209 	
3210 	g_file_enumerate_children_async (location,
3211 					 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
3212 					 0, /* flags */
3213 					 G_PRIORITY_LOW, /* prio */
3214 					 state->cancellable,
3215 					 list_mime_enum_callback,
3216 					 state);
3217 	g_object_unref (location);
3218 }
3219 
3220 static void
3221 top_left_stop (NautilusDirectory *directory)
3222 {
3223 	NautilusFile *file;
3224 
3225 	if (directory->details->top_left_read_state != NULL) {
3226 		file = directory->details->top_left_read_state->file;
3227 		if (file != NULL) {
3228 			g_assert (NAUTILUS_IS_FILE (file));
3229 			g_assert (file->details->directory == directory);
3230 			if (is_needy (file,
3231 				      lacks_top_left,
3232 				      REQUEST_TOP_LEFT_TEXT) ||
3233 			    is_needy (file,
3234 				      lacks_large_top_left,
3235 				      REQUEST_LARGE_TOP_LEFT_TEXT)) {
3236 				return;
3237 			}
3238 		}
3239 
3240 		/* The top left is not wanted, so stop it. */
3241 		top_left_cancel (directory);
3242 	}
3243 }
3244 
3245 static void
3246 top_left_read_state_free (TopLeftTextReadState *state)
3247 {
3248 	g_object_unref (state->cancellable);
3249 	g_free (state);
3250 }
3251 
3252 static void
3253 top_left_read_callback (GObject *source_object,
3254 			GAsyncResult *res,
3255 			gpointer callback_data)
3256 {
3257 	TopLeftTextReadState *state;
3258 	NautilusDirectory *directory;
3259 	NautilusFileDetails *file_details;
3260 	gsize file_size;
3261 	char *file_contents;
3262 
3263 	state = callback_data;
3264 
3265 	if (state->directory == NULL) {
3266 		/* Operation was cancelled. Bail out */
3267 		top_left_read_state_free (state);
3268 		return;
3269 	}
3270 	
3271 	directory = nautilus_directory_ref (state->directory);
3272 	
3273 	file_details = state->file->details;
3274 
3275 	file_details->top_left_text_is_up_to_date = TRUE;
3276 	g_free (file_details->top_left_text);
3277 
3278 	if (g_file_load_partial_contents_finish (G_FILE (source_object),
3279 						 res,
3280 						 &file_contents, &file_size,
3281 						 NULL, NULL)) {
3282 		file_details->top_left_text = nautilus_extract_top_left_text (file_contents, state->large, file_size);
3283 		file_details->got_top_left_text = TRUE;
3284 		file_details->got_large_top_left_text = state->large;
3285 		g_free (file_contents);
3286 	} else {
3287 		file_details->top_left_text = NULL;
3288 		file_details->got_top_left_text = FALSE;
3289 		file_details->got_large_top_left_text = FALSE;
3290 	}
3291 
3292 	nautilus_file_changed (state->file);
3293 
3294 	directory->details->top_left_read_state = NULL;
3295 	async_job_end (directory, "top left");
3296 
3297 	top_left_read_state_free (state);
3298 	
3299 	nautilus_directory_async_state_changed (directory);
3300 
3301 	nautilus_directory_unref (directory);
3302 }
3303 
3304 static int
3305 count_lines (const char *text, int length)
3306 {
3307 	int count, i;
3308 
3309 	count = 0;
3310 	for (i = 0; i < length; i++) {
3311 		count += *text++ == '\n';
3312 	}
3313 	return count;
3314 }
3315 
3316 static gboolean
3317 top_left_read_more_callback (const char *file_contents,
3318 			     goffset bytes_read,
3319 			     gpointer callback_data)
3320 {
3321 	TopLeftTextReadState *state;
3322 
3323 	state = callback_data;
3324 
3325 	/* Stop reading when we have enough. */
3326 	if (state->large) {
3327 		return bytes_read < NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_BYTES &&
3328 			count_lines (file_contents, bytes_read) <= NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_LINES;
3329 	} else {
3330 		return bytes_read < NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_BYTES &&
3331 			count_lines (file_contents, bytes_read) <= NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_LINES;
3332 	}
3333 }
3334 
3335 static void
3336 top_left_start (NautilusDirectory *directory,
3337 		NautilusFile *file,
3338 		gboolean *doing_io)
3339 {
3340 	GFile *location;
3341 	gboolean needs_large;
3342 	TopLeftTextReadState *state;
3343 
3344 	if (directory->details->top_left_read_state != NULL) {
3345  		*doing_io = TRUE;
3346 		return;
3347 	}
3348 	
3349 	needs_large = FALSE;
3350 
3351 	if (is_needy (file,
3352 		      lacks_large_top_left,
3353 		      REQUEST_LARGE_TOP_LEFT_TEXT)) {
3354 		needs_large = TRUE;
3355 	}
3356 
3357 	/* Figure out which file to read the top left for. */
3358 	if (!(needs_large ||
3359 	      is_needy (file,
3360 			lacks_top_left,
3361 			REQUEST_TOP_LEFT_TEXT))) {
3362 		return;
3363 	}
3364 	*doing_io = TRUE;
3365 
3366 	if (!nautilus_file_contains_text (file)) {
3367 		g_free (file->details->top_left_text);
3368 		file->details->top_left_text = NULL;
3369 		file->details->got_top_left_text = FALSE;
3370 		file->details->got_large_top_left_text = FALSE;
3371 		file->details->top_left_text_is_up_to_date = TRUE;
3372 
3373 		nautilus_directory_async_state_changed (directory);
3374 		return;
3375 	}
3376 
3377 	if (!async_job_start (directory, "top left")) {
3378 		return;
3379 	}
3380 
3381 	/* Start reading. */
3382 	state = g_new0 (TopLeftTextReadState, 1);
3383 	state->directory = directory;
3384 	state->cancellable = g_cancellable_new ();
3385 	state->large = needs_large;
3386 	state->file = file;
3387 
3388 	directory->details->top_left_read_state = state;
3389 
3390 	location = nautilus_file_get_location (file);
3391 	g_file_load_partial_contents_async (location,
3392 					    state->cancellable,
3393 					    top_left_read_more_callback,
3394 					    top_left_read_callback,
3395 					    state);
3396 	g_object_unref (location);
3397 }
3398 
3399 static void
3400 get_info_state_free (GetInfoState *state)
3401 {
3402 	g_object_unref (state->cancellable);
3403 	g_free (state);
3404 }
3405 
3406 static void
3407 query_info_callback (GObject *source_object,
3408 		     GAsyncResult *res,
3409 		     gpointer user_data)
3410 {
3411 	NautilusDirectory *directory;
3412 	NautilusFile *get_info_file;
3413 	GFileInfo *info;
3414 	GetInfoState *state;
3415 	GError *error;
3416 
3417 	state = user_data;
3418 
3419 	if (state->directory == NULL) {
3420 		/* Operation was cancelled. Bail out */
3421 		get_info_state_free (state);
3422 		return;
3423 	}
3424 	
3425 	directory = nautilus_directory_ref (state->directory);
3426 
3427 	get_info_file = directory->details->get_info_file;
3428 	g_assert (NAUTILUS_IS_FILE (get_info_file));
3429 
3430 	directory->details->get_info_file = NULL;
3431 	directory->details->get_info_in_progress = NULL;
3432 	
3433 	/* ref here because we might be removing the last ref when we
3434 	 * mark the file gone below, but we need to keep a ref at
3435 	 * least long enough to send the change notification. 
3436 	 */
3437 	nautilus_file_ref (get_info_file);
3438 
3439 	error = NULL;
3440 	info = g_file_query_info_finish (G_FILE (source_object), res, &error);
3441 	
3442 	if (info == NULL) {
3443 		if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND) {
3444 			/* mark file as gone */
3445 			nautilus_file_mark_gone (get_info_file);
3446 		}
3447 		get_info_file->details->file_info_is_up_to_date = TRUE;
3448 		nautilus_file_clear_info (get_info_file);
3449 		get_info_file->details->get_info_failed = TRUE;
3450 		get_info_file->details->get_info_error = error;
3451 	} else {
3452 		nautilus_file_update_info (get_info_file, info);
3453 		g_object_unref (info);
3454 	}
3455 
3456 	nautilus_file_changed (get_info_file);
3457 	nautilus_file_unref (get_info_file);
3458 
3459 	async_job_end (directory, "file info");
3460 	nautilus_directory_async_state_changed (directory);
3461 
3462 	nautilus_directory_unref (directory);
3463 
3464 	get_info_state_free (state);
3465 }
3466 
3467 static void
3468 file_info_stop (NautilusDirectory *directory)
3469 {
3470 	NautilusFile *file;
3471 
3472 	if (directory->details->get_info_in_progress != NULL) {
3473 		file = directory->details->get_info_file;
3474 		if (file != NULL) {
3475 			g_assert (NAUTILUS_IS_FILE (file));
3476 			g_assert (file->details->directory == directory);
3477 			if (is_needy (file, lacks_info, REQUEST_FILE_INFO)) {
3478 				return;
3479 			}
3480 		}
3481 
3482 		/* The info is not wanted, so stop it. */
3483 		file_info_cancel (directory);
3484 	}
3485 }
3486 
3487 static void
3488 file_info_start (NautilusDirectory *directory,
3489 		 NautilusFile *file,
3490 		 gboolean *doing_io)
3491 {
3492 	GFile *location;
3493 	GetInfoState *state;
3494 	
3495 	file_info_stop (directory);
3496 
3497 	if (directory->details->get_info_in_progress != NULL) {
3498 		*doing_io = TRUE;
3499 		return;
3500 	}
3501 
3502 	if (!is_needy (file, lacks_info, REQUEST_FILE_INFO)) {
3503 		return;
3504 	}
3505 	*doing_io = TRUE;
3506 
3507 	if (!async_job_start (directory, "file info")) {
3508 		return;
3509 	}
3510 
3511 	directory->details->get_info_file = file;
3512 	file->details->get_info_failed = FALSE;
3513 	if (file->details->get_info_error) {
3514 		g_error_free (file->details->get_info_error);
3515 		file->details->get_info_error = NULL;
3516 	}
3517 
3518 	state = g_new (GetInfoState, 1);
3519 	state->directory = directory;
3520 	state->cancellable = g_cancellable_new ();
3521 
3522 	directory->details->get_info_in_progress = state;
3523 	
3524 	location = nautilus_file_get_location (file);
3525 	g_file_query_info_async (location,
3526 				 NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
3527 				 0,
3528 				 G_PRIORITY_DEFAULT,
3529 				 state->cancellable, query_info_callback, state);
3530 	g_object_unref (location);
3531 }
3532 
3533 static gboolean
3534 is_link_trusted (NautilusFile *file,
3535 		 gboolean is_launcher)
3536 {
3537 	GFile *location;
3538 	gboolean res;
3539 	
3540 	if (!is_launcher) {
3541 		return TRUE;
3542 	}
3543 	
3544 	if (nautilus_file_can_execute (file)) {
3545 		return TRUE;
3546 	}
3547 
3548 	res = FALSE;
3549 	
3550 	if (nautilus_file_is_local (file)) {
3551 		location = nautilus_file_get_location (file);
3552 		res = nautilus_is_in_system_dir (location);
3553 		g_object_unref (location);
3554 	}
3555 	
3556 	return res;
3557 }
3558 
3559 static void
3560 link_info_done (NautilusDirectory *directory,
3561 		NautilusFile *file,
3562 		const char *uri,
3563 		const char *name, 
3564 		GIcon *icon,
3565 		gboolean is_launcher,
3566 		gboolean is_foreign)
3567 {
3568 	gboolean is_trusted;
3569 	
3570 	file->details->link_info_is_up_to_date = TRUE;
3571 
3572 	is_trusted = is_link_trusted (file, is_launcher);
3573 
3574 	if (is_trusted) {
3575 		nautilus_file_set_display_name (file, name, name, TRUE);
3576 	} else {
3577 		nautilus_file_set_display_name (file, NULL, NULL, TRUE);
3578 	}
3579 	
3580 	file->details->got_link_info = TRUE;
3581 	g_clear_object (&file->details->custom_icon);
3582 
3583 	if (uri) {
3584 		g_free (file->details->activation_uri);
3585 		file->details->activation_uri = NULL;
3586 		file->details->got_custom_activation_uri = TRUE;
3587 		file->details->activation_uri = g_strdup (uri);
3588 	}
3589 	if (is_trusted && (icon != NULL)) {
3590 		file->details->custom_icon = g_object_ref (icon);
3591 	}
3592 	file->details->is_launcher = is_launcher;
3593 	file->details->is_foreign_link = is_foreign;
3594 	file->details->is_trusted_link = is_trusted;
3595 	
3596 	nautilus_directory_async_state_changed (directory);
3597 }
3598 
3599 static void
3600 link_info_stop (NautilusDirectory *directory)
3601 {
3602 	NautilusFile *file;
3603 
3604 	if (directory->details->link_info_read_state != NULL) {
3605 		file = directory->details->link_info_read_state->file;
3606 
3607 		if (file != NULL) {
3608 			g_assert (NAUTILUS_IS_FILE (file));
3609 			g_assert (file->details->directory == directory);
3610 			if (is_needy (file,
3611 				      lacks_link_info,
3612 				      REQUEST_LINK_INFO)) {
3613 				return;
3614 			}
3615 		}
3616 
3617 		/* The link info is not wanted, so stop it. */
3618 		link_info_cancel (directory);
3619 	}
3620 }
3621 
3622 static void
3623 link_info_got_data (NautilusDirectory *directory,
3624 		    NautilusFile *file,
3625 		    gboolean result,
3626 		    goffset bytes_read,
3627 		    char *file_contents)
3628 {
3629 	char *link_uri, *uri, *name;
3630 	GIcon *icon;
3631 	gboolean is_launcher;
3632 	gboolean is_foreign;
3633 
3634 	nautilus_directory_ref (directory);
3635 
3636 	uri = NULL;
3637 	name = NULL;
3638 	icon = NULL;
3639 	is_launcher = FALSE;
3640 	is_foreign = FALSE;
3641 	
3642 	/* Handle the case where we read the Nautilus link. */
3643 	if (result) {
3644 		link_uri = nautilus_file_get_uri (file);
3645 		nautilus_link_get_link_info_given_file_contents (file_contents, bytes_read, link_uri,
3646 								 &uri, &name, &icon, &is_launcher, &is_foreign);
3647 		g_free (link_uri);
3648 	} else {
3649 		/* FIXME bugzilla.gnome.org 42433: We should report this error to the user. */
3650 	}
3651 
3652 	nautilus_file_ref (file);
3653 	link_info_done (directory, file, uri, name, icon, is_launcher, is_foreign);
3654 	nautilus_file_changed (file);
3655 	nautilus_file_unref (file);
3656 	
3657 	g_free (uri);
3658 	g_free (name);
3659 
3660 	if (icon != NULL) {
3661 		g_object_unref (icon);
3662 	}
3663 
3664 	nautilus_directory_unref (directory);
3665 }
3666 
3667 static void
3668 link_info_read_state_free (LinkInfoReadState *state)
3669 {
3670 	g_object_unref (state->cancellable);
3671 	g_free (state);
3672 }
3673 
3674 static void
3675 link_info_nautilus_link_read_callback (GObject *source_object,
3676 				       GAsyncResult *res,
3677 				       gpointer user_data)
3678 {
3679 	LinkInfoReadState *state;
3680 	gsize file_size;
3681 	char *file_contents;
3682 	gboolean result;
3683 	NautilusDirectory *directory;
3684 
3685 	state = user_data;
3686 
3687 	if (state->directory == NULL) {
3688 		/* Operation was cancelled. Bail out */
3689 		link_info_read_state_free (state);
3690 		return;
3691 	}
3692 
3693 	directory = nautilus_directory_ref (state->directory);
3694 
3695 	result = g_file_load_contents_finish (G_FILE (source_object),
3696 					      res,
3697 					      &file_contents, &file_size,
3698 					      NULL, NULL);
3699 
3700 	state->directory->details->link_info_read_state = NULL;
3701 	async_job_end (state->directory, "link info");
3702 	
3703 	link_info_got_data (state->directory, state->file, result, file_size, file_contents);
3704 
3705 	if (result) {
3706 		g_free (file_contents);
3707 	}
3708 	
3709 	link_info_read_state_free (state);
3710 	
3711 	nautilus_directory_unref (directory);
3712 }
3713 
3714 static void
3715 link_info_start (NautilusDirectory *directory,
3716 		 NautilusFile *file,
3717 		 gboolean *doing_io)
3718 {
3719 	GFile *location;
3720 	gboolean nautilus_style_link;
3721 	LinkInfoReadState *state;
3722 	
3723 	if (directory->details->link_info_read_state != NULL) {
3724 		*doing_io = TRUE;
3725 		return;
3726 	}
3727 
3728 	if (!is_needy (file,
3729 		       lacks_link_info,
3730 		       REQUEST_LINK_INFO)) {
3731 		return;
3732 	}
3733 	*doing_io = TRUE;
3734 
3735 	/* Figure out if it is a link. */
3736 	nautilus_style_link = nautilus_file_is_nautilus_link (file);
3737 	location = nautilus_file_get_location (file);
3738 	
3739 	/* If it's not a link we are done. If it is, we need to read it. */
3740 	if (!nautilus_style_link) {
3741 		link_info_done (directory, file, NULL, NULL, NULL, FALSE, FALSE);
3742 	} else {
3743 		if (!async_job_start (directory, "link info")) {
3744 			g_object_unref (location);
3745 			return;
3746 		}
3747 
3748 		state = g_new0 (LinkInfoReadState, 1);
3749 		state->directory = directory;
3750 		state->file = file;
3751 		state->cancellable = g_cancellable_new ();
3752 		
3753 		directory->details->link_info_read_state = state;
3754 
3755 		g_file_load_contents_async (location,
3756 					    state->cancellable,
3757 					    link_info_nautilus_link_read_callback,
3758 					    state);
3759 	}
3760 	g_object_unref (location);
3761 }
3762 
3763 static void
3764 thumbnail_done (NautilusDirectory *directory,
3765 		NautilusFile *file,
3766 		GdkPixbuf *pixbuf,
3767 		gboolean tried_original)
3768 {
3769 	const char *thumb_mtime_str;
3770 	time_t thumb_mtime = 0;
3771 	
3772 	file->details->thumbnail_is_up_to_date = TRUE;
3773 	file->details->thumbnail_tried_original  = tried_original;
3774 	if (file->details->thumbnail) {
3775 		g_object_unref (file->details->thumbnail);
3776 		file->details->thumbnail = NULL;
3777 	}
3778 	if (pixbuf) {
3779 		if (tried_original) {
3780 			thumb_mtime = file->details->mtime;
3781 		} else {
3782 			thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime");
3783 			if (thumb_mtime_str) {
3784 				thumb_mtime = atol (thumb_mtime_str);
3785 			}
3786 		}
3787 		
3788 		if (thumb_mtime == 0 ||
3789 		    thumb_mtime == file->details->mtime) {
3790 			file->details->thumbnail = g_object_ref (pixbuf);
3791 			file->details->thumbnail_mtime = thumb_mtime;
3792 		} else {
3793 			g_free (file->details->thumbnail_path);
3794 			file->details->thumbnail_path = NULL;
3795 		}
3796 	}
3797 	
3798 	nautilus_directory_async_state_changed (directory);
3799 }
3800 
3801 static void
3802 thumbnail_stop (NautilusDirectory *directory)
3803 {
3804 	NautilusFile *file;
3805 
3806 	if (directory->details->thumbnail_state != NULL) {
3807 		file = directory->details->thumbnail_state->file;
3808 
3809 		if (file != NULL) {
3810 			g_assert (NAUTILUS_IS_FILE (file));
3811 			g_assert (file->details->directory == directory);
3812 			if (is_needy (file,
3813 				      lacks_thumbnail,
3814 				      REQUEST_THUMBNAIL)) {
3815 				return;
3816 			}
3817 		}
3818 
3819 		/* The link info is not wanted, so stop it. */
3820 		thumbnail_cancel (directory);
3821 	}
3822 }
3823 
3824 static void
3825 thumbnail_got_pixbuf (NautilusDirectory *directory,
3826 		      NautilusFile *file,
3827 		      GdkPixbuf *pixbuf,
3828 		      gboolean tried_original)
3829 {
3830 	nautilus_directory_ref (directory);
3831 
3832 	nautilus_file_ref (file);
3833 	thumbnail_done (directory, file, pixbuf, tried_original);
3834 	nautilus_file_changed (file);
3835 	nautilus_file_unref (file);
3836 	
3837 	if (pixbuf) {
3838 		g_object_unref (pixbuf);
3839 	}
3840 
3841 	nautilus_directory_unref (directory);
3842 }
3843 
3844 static void
3845 thumbnail_state_free (ThumbnailState *state)
3846 {
3847 	g_object_unref (state->cancellable);
3848 	g_free (state);
3849 }
3850 
3851 extern int cached_thumbnail_size;
3852 
3853 /* scale very large images down to the max. size we need */
3854 static void
3855 thumbnail_loader_size_prepared (GdkPixbufLoader *loader,
3856 				int width,
3857 				int height,
3858 				gpointer user_data)
3859 {
3860 	int max_thumbnail_size;
3861 	double aspect_ratio;
3862 
3863 	aspect_ratio = ((double) width) / height;
3864 
3865 	/* cf. nautilus_file_get_icon() */
3866 	max_thumbnail_size = NAUTILUS_ICON_SIZE_LARGEST * cached_thumbnail_size / NAUTILUS_ICON_SIZE_STANDARD;
3867 	if (MAX (width, height) > max_thumbnail_size) {
3868 		if (width > height) {
3869 			width = max_thumbnail_size;
3870 			height = width / aspect_ratio;
3871 		} else {
3872 			height = max_thumbnail_size;
3873 			width = height * aspect_ratio;
3874 		}
3875 
3876 		gdk_pixbuf_loader_set_size (loader, width, height);
3877 	}
3878 }
3879 
3880 static GdkPixbuf *
3881 get_pixbuf_for_content (goffset file_len,
3882 			char *file_contents)
3883 {
3884 	gboolean res;
3885 	GdkPixbuf *pixbuf, *pixbuf2;
3886 	GdkPixbufLoader *loader;
3887 	gsize chunk_len;
3888 	pixbuf = NULL;
3889 	
3890 	loader = gdk_pixbuf_loader_new ();
3891 	g_signal_connect (loader, "size-prepared",
3892 			  G_CALLBACK (thumbnail_loader_size_prepared),
3893 			  NULL);
3894 
3895 	/* For some reason we have to write in chunks, or gdk-pixbuf fails */
3896 	res = TRUE;
3897 	while (res && file_len > 0) {
3898 		chunk_len = file_len;
3899 		res = gdk_pixbuf_loader_write (loader, (guchar *) file_contents, chunk_len, NULL);
3900 		file_contents += chunk_len;
3901 		file_len -= chunk_len;
3902 	}
3903 	if (res) {
3904 		res = gdk_pixbuf_loader_close (loader, NULL);
3905 	}
3906 	if (res) {
3907 		pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
3908 	}
3909 	g_object_unref (G_OBJECT (loader));
3910 
3911 	if (pixbuf) {
3912 		pixbuf2 = gdk_pixbuf_apply_embedded_orientation (pixbuf);
3913 		g_object_unref (pixbuf);
3914 		pixbuf = pixbuf2;
3915 	}
3916 	return pixbuf;
3917 }
3918 
3919 
3920 static void
3921 thumbnail_read_callback (GObject *source_object,
3922 			 GAsyncResult *res,
3923 			 gpointer user_data)
3924 {
3925 	ThumbnailState *state;
3926 	gsize file_size;
3927 	char *file_contents;
3928 	gboolean result;
3929 	NautilusDirectory *directory;
3930 	GdkPixbuf *pixbuf;
3931 	GFile *location;
3932 
3933 	state = user_data;
3934 
3935 	if (state->directory == NULL) {
3936 		/* Operation was cancelled. Bail out */
3937 		thumbnail_state_free (state);
3938 		return;
3939 	}
3940 
3941 	directory = nautilus_directory_ref (state->directory);
3942 
3943 	result = g_file_load_contents_finish (G_FILE (source_object),
3944 					      res,
3945 					      &file_contents, &file_size,
3946 					      NULL, NULL);
3947 
3948 	pixbuf = NULL;
3949 	if (result) {
3950 		pixbuf = get_pixbuf_for_content (file_size, file_contents);
3951 		g_free (file_contents);
3952 	}
3953 	
3954 	if (pixbuf == NULL && state->trying_original) {
3955 		state->trying_original = FALSE;
3956 
3957 		location = g_file_new_for_path (state->file->details->thumbnail_path);
3958 		g_file_load_contents_async (location,
3959 					    state->cancellable,
3960 					    thumbnail_read_callback,
3961 					    state);
3962 		g_object_unref (location);
3963 	} else {
3964 		state->directory->details->thumbnail_state = NULL;
3965 		async_job_end (state->directory, "thumbnail");
3966 		
3967 		thumbnail_got_pixbuf (state->directory, state->file, pixbuf, state->tried_original);
3968 	
3969 		thumbnail_state_free (state);
3970 	}
3971 	
3972 	nautilus_directory_unref (directory);
3973 }
3974 
3975 static void
3976 thumbnail_start (NautilusDirectory *directory,
3977 		 NautilusFile *file,
3978 		 gboolean *doing_io)
3979 {
3980 	GFile *location;
3981 	ThumbnailState *state;
3982 
3983 	if (directory->details->thumbnail_state != NULL) {
3984 		*doing_io = TRUE;
3985 		return;
3986 	}
3987 
3988 	if (!is_needy (file,
3989 		       lacks_thumbnail,
3990 		       REQUEST_THUMBNAIL)) {
3991 		return;
3992 	}
3993 	*doing_io = TRUE;
3994 
3995 	if (!async_job_start (directory, "thumbnail")) {
3996 		return;
3997 	}
3998 	
3999 	state = g_new0 (ThumbnailState, 1);
4000 	state->directory = directory;
4001 	state->file = file;
4002 	state->cancellable = g_cancellable_new ();
4003 
4004 	if (file->details->thumbnail_wants_original) {
4005 		state->tried_original = TRUE;
4006 		state->trying_original = TRUE;
4007 		location = nautilus_file_get_location (file);
4008 	} else {
4009 		location = g_file_new_for_path (file->details->thumbnail_path);
4010 	}
4011 	
4012 	directory->details->thumbnail_state = state;
4013 
4014 	g_file_load_contents_async (location,
4015 				    state->cancellable,
4016 				    thumbnail_read_callback,
4017 				    state);
4018 	g_object_unref (location);
4019 }
4020 
4021 static void
4022 mount_stop (NautilusDirectory *directory)
4023 {
4024 	NautilusFile *file;
4025 
4026 	if (directory->details->mount_state != NULL) {
4027 		file = directory->details->mount_state->file;
4028 
4029 		if (file != NULL) {
4030 			g_assert (NAUTILUS_IS_FILE (file));
4031 			g_assert (file->details->directory == directory);
4032 			if (is_needy (file,
4033 				      lacks_mount,
4034 				      REQUEST_MOUNT)) {
4035 				return;
4036 			}
4037 		}
4038 
4039 		/* The link info is not wanted, so stop it. */
4040 		mount_cancel (directory);
4041 	}
4042 }
4043 
4044 static void
4045 mount_state_free (MountState *state)
4046 {
4047 	g_object_unref (state->cancellable);
4048 	g_free (state);
4049 }
4050 
4051 static void
4052 got_mount (MountState *state, GMount *mount)
4053 {
4054 	NautilusDirectory *directory;
4055 	NautilusFile *file;
4056 	
4057 	directory = nautilus_directory_ref (state->directory);
4058 
4059 	state->directory->details->mount_state = NULL;
4060 	async_job_end (state->directory, "mount");
4061 	
4062 	file = nautilus_file_ref (state->file);
4063 
4064 	file->details->mount_is_up_to_date = TRUE;
4065 	nautilus_file_set_mount (file, mount);
4066 
4067 	nautilus_directory_async_state_changed (directory);
4068 	nautilus_file_changed (file);
4069 	
4070 	nautilus_file_unref (file);
4071 	
4072 	nautilus_directory_unref (directory);
4073 	
4074 	mount_state_free (state);
4075 
4076 }
4077 
4078 static void
4079 find_enclosing_mount_callback (GObject *source_object,
4080 			       GAsyncResult *res,
4081 			       gpointer user_data)
4082 {
4083 	GMount *mount;
4084 	MountState *state;
4085 	GFile *location, *root;
4086 
4087 	state = user_data;
4088 	if (state->directory == NULL) {
4089 		/* Operation was cancelled. Bail out */
4090 		mount_state_free (state);
4091 		return;
4092 	}
4093 
4094 	mount = g_file_find_enclosing_mount_finish (G_FILE (source_object),
4095 						    res, NULL);
4096 
4097 	if (mount) {
4098 		root = g_mount_get_root (mount);
4099 		location = nautilus_file_get_location (state->file);
4100 		if (!g_file_equal (location, root)) {
4101 			g_object_unref (mount);
4102 			mount = NULL;
4103 		}
4104 		g_object_unref (root);
4105 		g_object_unref (location);
4106 	}
4107 
4108 	got_mount (state, mount);
4109 
4110 	if (mount) {
4111 		g_object_unref (mount);
4112 	}
4113 }
4114 
4115 static GMount *
4116 get_mount_at (GFile *target)
4117 {
4118 	GVolumeMonitor *monitor;
4119 	GFile *root;
4120 	GList *mounts, *l;
4121 	GMount *found;
4122 	
4123 	monitor = g_volume_monitor_get ();
4124 	mounts = g_volume_monitor_get_mounts (monitor);
4125 
4126 	found = NULL;
4127 	for (l = mounts; l != NULL; l = l->next) {
4128 		GMount *mount = G_MOUNT (l->data);
4129 
4130 		if (g_mount_is_shadowed (mount))
4131 			continue;
4132 
4133 		root = g_mount_get_root (mount);
4134 
4135 		if (g_file_equal (target, root)) {
4136 			found = g_object_ref (mount);
4137 			break;
4138 		}
4139 		
4140 		g_object_unref (root);
4141 	}
4142 
4143 	g_list_free_full (mounts, g_object_unref);
4144 	
4145 	g_object_unref (monitor);
4146 
4147 	return found;
4148 }
4149 
4150 static void
4151 mount_start (NautilusDirectory *directory,
4152 	     NautilusFile *file,
4153 	     gboolean *doing_io)
4154 {
4155 	GFile *location;
4156 	MountState *state;
4157 	
4158 	if (directory->details->mount_state != NULL) {
4159 		*doing_io = TRUE;
4160 		return;
4161 	}
4162 
4163 	if (!is_needy (file,
4164 		       lacks_mount,
4165 		       REQUEST_MOUNT)) {
4166 		return;
4167 	}
4168 	*doing_io = TRUE;
4169 
4170 	if (!async_job_start (directory, "mount")) {
4171 		return;
4172 	}
4173 	
4174 	state = g_new0 (MountState, 1);
4175 	state->directory = directory;
4176 	state->file = file;
4177 	state->cancellable = g_cancellable_new ();
4178 
4179 	location = nautilus_file_get_location (file);
4180 	
4181 	directory->details->mount_state = state;
4182 
4183 	if (file->details->type == G_FILE_TYPE_MOUNTABLE) {
4184 		GFile *target;
4185 		GMount *mount;
4186 
4187 		mount = NULL;
4188 		target = nautilus_file_get_activation_location (file);
4189 		if (target != NULL) {
4190 			mount = get_mount_at (target);
4191 			g_object_unref (target);
4192 		}
4193 
4194 		got_mount (state, mount);
4195 
4196 		if (mount) {
4197 			g_object_unref (mount);
4198 		}
4199 	} else {
4200 		g_file_find_enclosing_mount_async (location,
4201 						   G_PRIORITY_DEFAULT,
4202 						   state->cancellable,
4203 						   find_enclosing_mount_callback,
4204 						   state);
4205 	}
4206 	g_object_unref (location);
4207 }
4208 
4209 static void
4210 filesystem_info_cancel (NautilusDirectory *directory)
4211 {
4212 	if (directory->details->filesystem_info_state != NULL) {
4213 		g_cancellable_cancel (directory->details->filesystem_info_state->cancellable);
4214 		directory->details->filesystem_info_state->directory = NULL;
4215 		directory->details->filesystem_info_state = NULL;
4216 		async_job_end (directory, "filesystem info");
4217 	}
4218 }
4219 
4220 static void
4221 filesystem_info_stop (NautilusDirectory *directory)
4222 {
4223 	NautilusFile *file;
4224 
4225 	if (directory->details->filesystem_info_state != NULL) {
4226 		file = directory->details->filesystem_info_state->file;
4227 
4228 		if (file != NULL) {
4229 			g_assert (NAUTILUS_IS_FILE (file));
4230 			g_assert (file->details->directory == directory);
4231 			if (is_needy (file,
4232 				      lacks_filesystem_info,
4233 				      REQUEST_FILESYSTEM_INFO)) {
4234 				return;
4235 			}
4236 		}
4237 
4238 		/* The filesystem info is not wanted, so stop it. */
4239 		filesystem_info_cancel (directory);
4240 	}
4241 }
4242 
4243 static void
4244 filesystem_info_state_free (FilesystemInfoState *state)
4245 {
4246 	g_object_unref (state->cancellable);
4247 	g_free (state);
4248 }
4249 
4250 static void
4251 got_filesystem_info (FilesystemInfoState *state, GFileInfo *info)
4252 {
4253 	NautilusDirectory *directory;
4254 	NautilusFile *file;
4255 
4256 	/* careful here, info may be NULL */
4257 
4258 	directory = nautilus_directory_ref (state->directory);
4259 
4260 	state->directory->details->filesystem_info_state = NULL;
4261 	async_job_end (state->directory, "filesystem info");
4262 	
4263 	file = nautilus_file_ref (state->file);
4264 
4265 	file->details->filesystem_info_is_up_to_date = TRUE;
4266 	if (info != NULL) {
4267 		file->details->filesystem_use_preview = 
4268 			g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW);
4269 		file->details->filesystem_readonly = 
4270 			g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY);
4271 	}
4272 	
4273 	nautilus_directory_async_state_changed (directory);
4274 	nautilus_file_changed (file);
4275 	
4276 	nautilus_file_unref (file);
4277 	
4278 	nautilus_directory_unref (directory);
4279 	
4280 	filesystem_info_state_free (state);
4281 }
4282 
4283 static void
4284 query_filesystem_info_callback (GObject *source_object,
4285 				GAsyncResult *res,
4286 				gpointer user_data)
4287 {
4288 	GFileInfo *info;
4289 	FilesystemInfoState *state;
4290 
4291 	state = user_data;
4292 	if (state->directory == NULL) {
4293 		/* Operation was cancelled. Bail out */
4294 		filesystem_info_state_free (state);
4295 		return;
4296 	}
4297 
4298 	info = g_file_query_filesystem_info_finish (G_FILE (source_object), res, NULL);
4299 
4300 	got_filesystem_info (state, info);
4301 
4302 	if (info != NULL) {
4303 		g_object_unref (info);
4304 	}
4305 }
4306 
4307 static void
4308 filesystem_info_start (NautilusDirectory *directory,
4309 		       NautilusFile *file,
4310 		       gboolean *doing_io)
4311 {
4312 	GFile *location;
4313 	FilesystemInfoState *state;
4314 
4315 	if (directory->details->filesystem_info_state != NULL) {
4316 		*doing_io = TRUE;
4317 		return;
4318 	}
4319 
4320 	if (!is_needy (file,
4321 		       lacks_filesystem_info,
4322 		       REQUEST_FILESYSTEM_INFO)) {
4323 		return;
4324 	}
4325 	*doing_io = TRUE;
4326 
4327 	if (!async_job_start (directory, "filesystem info")) {
4328 		return;
4329 	}
4330 	
4331 	state = g_new0 (FilesystemInfoState, 1);
4332 	state->directory = directory;
4333 	state->file = file;
4334 	state->cancellable = g_cancellable_new ();
4335 
4336 	location = nautilus_file_get_location (file);
4337 	
4338 	directory->details->filesystem_info_state = state;
4339 
4340 	g_file_query_filesystem_info_async (location,
4341 					    G_FILE_ATTRIBUTE_FILESYSTEM_READONLY ","
4342 					    G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW,
4343 					    G_PRIORITY_DEFAULT,
4344 					    state->cancellable, 
4345 					    query_filesystem_info_callback, 
4346 					    state);
4347 	g_object_unref (location);
4348 }
4349 
4350 static void
4351 extension_info_cancel (NautilusDirectory *directory)
4352 {
4353 	if (directory->details->extension_info_in_progress != NULL) {
4354 		if (directory->details->extension_info_idle) {
4355 			g_source_remove (directory->details->extension_info_idle);
4356 		} else {
4357 			nautilus_info_provider_cancel_update 
4358 				(directory->details->extension_info_provider,
4359 				 directory->details->extension_info_in_progress);
4360 		}
4361 
4362 		directory->details->extension_info_in_progress = NULL;
4363 		directory->details->extension_info_file = NULL;
4364 		directory->details->extension_info_provider = NULL;
4365 		directory->details->extension_info_idle = 0;
4366 
4367 		async_job_end (directory, "extension info");
4368 	}
4369 }
4370 	
4371 static void
4372 extension_info_stop (NautilusDirectory *directory)
4373 {
4374 	if (directory->details->extension_info_in_progress != NULL) {
4375 		NautilusFile *file;
4376 
4377 		file = directory->details->extension_info_file;
4378 		if (file != NULL) {
4379 			g_assert (NAUTILUS_IS_FILE (file));
4380 			g_assert (file->details->directory == directory);
4381 			if (is_needy (file, lacks_extension_info, REQUEST_EXTENSION_INFO)) {
4382 				return;
4383 			}
4384 		}
4385 
4386 		/* The info is not wanted, so stop it. */
4387 		extension_info_cancel (directory);
4388 	}
4389 }
4390 
4391 static void
4392 finish_info_provider (NautilusDirectory *directory,
4393 		      NautilusFile *file,
4394 		      NautilusInfoProvider *provider)
4395 {
4396 	file->details->pending_info_providers = 
4397 		g_list_remove  (file->details->pending_info_providers,
4398 				provider);
4399 	g_object_unref (provider);
4400 
4401 	nautilus_directory_async_state_changed (directory);
4402 
4403 	if (file->details->pending_info_providers == NULL) {
4404 		nautilus_file_info_providers_done (file);
4405 	}
4406 }
4407 
4408 
4409 static gboolean
4410 info_provider_idle_callback (gpointer user_data)
4411 {
4412 	InfoProviderResponse *response;
4413 	NautilusDirectory *directory;
4414 
4415 	response = user_data;
4416 	directory = response->directory;
4417 
4418 	if (response->handle != directory->details->extension_info_in_progress
4419 	    || response->provider != directory->details->extension_info_provider) {
4420 		g_warning ("Unexpected plugin response.  This probably indicates a bug in a Nautilus extension: handle=%p", response->handle);
4421 	} else {
4422 		NautilusFile *file;
4423 		async_job_end (directory, "extension info");
4424 
4425 		file = directory->details->extension_info_file;
4426 
4427 		directory->details->extension_info_file = NULL;
4428 		directory->details->extension_info_provider = NULL;
4429 		directory->details->extension_info_in_progress = NULL;
4430 		directory->details->extension_info_idle = 0;
4431 		
4432 		finish_info_provider (directory, file, response->provider);
4433 	}
4434 
4435 	return FALSE;
4436 }
4437 
4438 static void
4439 info_provider_callback (NautilusInfoProvider *provider,
4440 			NautilusOperationHandle *handle,
4441 			NautilusOperationResult result,
4442 			gpointer user_data)
4443 {
4444 	InfoProviderResponse *response;
4445 	
4446 	response = g_new0 (InfoProviderResponse, 1);
4447 	response->provider = provider;
4448 	response->handle = handle;
4449 	response->result = result;
4450 	response->directory = NAUTILUS_DIRECTORY (user_data);
4451 
4452 	response->directory->details->extension_info_idle =
4453 		g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
4454 				 info_provider_idle_callback, response,
4455 				 g_free);
4456 }
4457 
4458 static void
4459 extension_info_start (NautilusDirectory *directory,
4460 		      NautilusFile *file,
4461 		      gboolean *doing_io)
4462 {
4463 	NautilusInfoProvider *provider;
4464 	NautilusOperationResult result;
4465 	NautilusOperationHandle *handle;
4466 	GClosure *update_complete;
4467 
4468 	if (directory->details->extension_info_in_progress != NULL) {
4469 		*doing_io = TRUE;
4470 		return;
4471 	}
4472 	
4473 	if (!is_needy (file, lacks_extension_info, REQUEST_EXTENSION_INFO)) {
4474 		return;
4475 	}
4476 	*doing_io = TRUE;
4477 
4478 	if (!async_job_start (directory, "extension info")) {
4479 		return;
4480 	}
4481 
4482 	provider = file->details->pending_info_providers->data;
4483 
4484 	update_complete = g_cclosure_new (G_CALLBACK (info_provider_callback),
4485 					  directory,
4486 					  NULL);
4487 	g_closure_set_marshal (update_complete,
4488 			       g_cclosure_marshal_generic);
4489 			       
4490 	result = nautilus_info_provider_update_file_info
4491 		(provider, 
4492 		 NAUTILUS_FILE_INFO (file), 
4493 		 update_complete, 
4494 		 &handle);
4495 
4496 	g_closure_unref (update_complete);
4497 
4498 	if (result == NAUTILUS_OPERATION_COMPLETE ||
4499 	    result == NAUTILUS_OPERATION_FAILED) {
4500 		finish_info_provider (directory, file, provider);
4501 		async_job_end (directory, "extension info");
4502 	} else {
4503 		directory->details->extension_info_in_progress = handle;
4504 		directory->details->extension_info_provider = provider;
4505 		directory->details->extension_info_file = file;
4506 	}
4507 }
4508 
4509 static void
4510 start_or_stop_io (NautilusDirectory *directory)
4511 {
4512 	NautilusFile *file;
4513 	gboolean doing_io;
4514 
4515 	/* Start or stop reading files. */
4516 	file_list_start_or_stop (directory);
4517 
4518 	/* Stop any no longer wanted attribute fetches. */
4519 	file_info_stop (directory);
4520 	directory_count_stop (directory);
4521 	deep_count_stop (directory);
4522 	mime_list_stop (directory);
4523 	top_left_stop (directory);
4524 	link_info_stop (directory);
4525 	extension_info_stop (directory);
4526 	mount_stop (directory);
4527 	thumbnail_stop (directory);
4528 	filesystem_info_stop (directory);
4529 
4530 	doing_io = FALSE;
4531 	/* Take files that are all done off the queue. */
4532 	while (!nautilus_file_queue_is_empty (directory->details->high_priority_queue)) {
4533 		file = nautilus_file_queue_head (directory->details->high_priority_queue);
4534 
4535 		/* Start getting attributes if possible */
4536 		file_info_start (directory, file, &doing_io);
4537 		link_info_start (directory, file, &doing_io);
4538 
4539 		if (doing_io) {
4540 			return;
4541 		}
4542 
4543 		move_file_to_low_priority_queue (directory, file);
4544 	}
4545 
4546 	/* High priority queue must be empty */
4547 	while (!nautilus_file_queue_is_empty (directory->details->low_priority_queue)) {
4548 		file = nautilus_file_queue_head (directory->details->low_priority_queue);
4549 
4550 		/* Start getting attributes if possible */
4551 		mount_start (directory, file, &doing_io);
4552 		directory_count_start (directory, file, &doing_io);
4553 		deep_count_start (directory, file, &doing_io);
4554 		mime_list_start (directory, file, &doing_io);
4555 		top_left_start (directory, file, &doing_io);
4556 		thumbnail_start (directory, file, &doing_io);
4557 		filesystem_info_start (directory, file, &doing_io);
4558 
4559 		if (doing_io) {
4560 			return;
4561 		}
4562 
4563 		move_file_to_extension_queue (directory, file);
4564 	}
4565 
4566 	/* Low priority queue must be empty */
4567 	while (!nautilus_file_queue_is_empty (directory->details->extension_queue)) {
4568 		file = nautilus_file_queue_head (directory->details->extension_queue);
4569 
4570 		/* Start getting attributes if possible */
4571 		extension_info_start (directory, file, &doing_io);
4572 		if (doing_io) {
4573 			return;
4574 		}
4575 
4576 		nautilus_directory_remove_file_from_work_queue (directory, file);
4577 	}
4578 }
4579 
4580 /* Call this when the monitor or call when ready list changes,
4581  * or when some I/O is completed.
4582  */
4583 void
4584 nautilus_directory_async_state_changed (NautilusDirectory *directory)
4585 {
4586 	/* Check if any callbacks are satisfied and call them if they
4587 	 * are. Do this last so that any changes done in start or stop
4588 	 * I/O functions immediately (not in callbacks) are taken into
4589 	 * consideration. If any callbacks are called, consider the
4590 	 * I/O state again so that we can release or cancel I/O that
4591 	 * is not longer needed once the callbacks are satisfied.
4592 	 */
4593 
4594 	if (directory->details->in_async_service_loop) {
4595 		directory->details->state_changed = TRUE;
4596 		return;
4597 	}
4598 	directory->details->in_async_service_loop = TRUE;
4599 	nautilus_directory_ref (directory);
4600 	do {
4601 		directory->details->state_changed = FALSE;
4602 		start_or_stop_io (directory);
4603 		if (call_ready_callbacks (directory)) {
4604 			directory->details->state_changed = TRUE;
4605 		}
4606 	} while (directory->details->state_changed);
4607 	directory->details->in_async_service_loop = FALSE;
4608 	nautilus_directory_unref (directory);
4609 
4610 	/* Check if any directories should wake up. */
4611 	async_job_wake_up ();
4612 }
4613 
4614 void
4615 nautilus_directory_cancel (NautilusDirectory *directory)
4616 {
4617 	/* Arbitrary order (kept alphabetical). */
4618 	deep_count_cancel (directory);
4619 	directory_count_cancel (directory);
4620 	file_info_cancel (directory);
4621 	file_list_cancel (directory);
4622 	link_info_cancel (directory);
4623 	mime_list_cancel (directory);
4624 	new_files_cancel (directory);
4625 	top_left_cancel (directory);
4626 	extension_info_cancel (directory);
4627 	thumbnail_cancel (directory);
4628 	mount_cancel (directory);
4629 	filesystem_info_cancel (directory);
4630 
4631 	/* We aren't waiting for anything any more. */
4632 	if (waiting_directories != NULL) {
4633 		g_hash_table_remove (waiting_directories, directory);
4634 	}
4635 
4636 	/* Check if any directories should wake up. */
4637 	async_job_wake_up ();
4638 }
4639 
4640 static void
4641 cancel_directory_count_for_file (NautilusDirectory *directory,
4642 				 NautilusFile      *file)
4643 {
4644 	if (directory->details->count_in_progress != NULL &&
4645 	    directory->details->count_in_progress->count_file == file) {
4646 		directory_count_cancel (directory);
4647 	}
4648 }
4649 
4650 static void
4651 cancel_deep_counts_for_file (NautilusDirectory *directory,
4652 			     NautilusFile      *file)
4653 {
4654 	if (directory->details->deep_count_file == file) {
4655 		deep_count_cancel (directory);
4656 	}
4657 }
4658 
4659 static void
4660 cancel_mime_list_for_file (NautilusDirectory *directory,
4661 			   NautilusFile      *file)
4662 {
4663 	if (directory->details->mime_list_in_progress != NULL &&
4664 	    directory->details->mime_list_in_progress->mime_list_file == file) {
4665 		mime_list_cancel (directory);
4666 	}
4667 }
4668 
4669 static void
4670 cancel_top_left_text_for_file (NautilusDirectory *directory,
4671 			       NautilusFile      *file)
4672 {
4673 	if (directory->details->top_left_read_state != NULL &&
4674 	    directory->details->top_left_read_state->file == file) {
4675 		top_left_cancel (directory);
4676 	}
4677 }
4678 
4679 static void
4680 cancel_file_info_for_file (NautilusDirectory *directory,
4681 			   NautilusFile      *file)
4682 {
4683 	if (directory->details->get_info_file == file) {
4684 		file_info_cancel (directory);
4685 	}
4686 }
4687 
4688 static void
4689 cancel_thumbnail_for_file (NautilusDirectory *directory,
4690 			   NautilusFile      *file)
4691 {
4692 	if (directory->details->thumbnail_state != NULL &&
4693 	    directory->details->thumbnail_state->file == file) {
4694 		thumbnail_cancel (directory);
4695 	}
4696 }
4697 
4698 static void
4699 cancel_mount_for_file (NautilusDirectory *directory,
4700 			   NautilusFile      *file)
4701 {
4702 	if (directory->details->mount_state != NULL &&
4703 	    directory->details->mount_state->file == file) {
4704 		mount_cancel (directory);
4705 	}
4706 }
4707 
4708 static void
4709 cancel_filesystem_info_for_file (NautilusDirectory *directory,
4710 				 NautilusFile      *file)
4711 {
4712 	if (directory->details->filesystem_info_state != NULL &&
4713 	    directory->details->filesystem_info_state->file == file) {
4714 		filesystem_info_cancel (directory);
4715 	}
4716 }
4717 
4718 static void
4719 cancel_link_info_for_file (NautilusDirectory *directory,
4720 			   NautilusFile      *file)
4721 {
4722 	if (directory->details->link_info_read_state != NULL &&
4723 	    directory->details->link_info_read_state->file == file) {
4724 		link_info_cancel (directory);
4725 	}
4726 }
4727 
4728 
4729 static void
4730 cancel_loading_attributes (NautilusDirectory *directory,
4731 			   NautilusFileAttributes file_attributes)
4732 {
4733 	Request request;
4734 	
4735 	request = nautilus_directory_set_up_request (file_attributes);
4736 
4737 	if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
4738 		directory_count_cancel (directory);
4739 	}
4740 	if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
4741 		deep_count_cancel (directory);
4742 	}
4743 	if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
4744 		mime_list_cancel (directory);
4745 	}
4746 	if (REQUEST_WANTS_TYPE (request, REQUEST_TOP_LEFT_TEXT)) {
4747 		top_left_cancel (directory);
4748 	}
4749 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
4750 		file_info_cancel (directory);
4751 	}
4752 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) {
4753 		filesystem_info_cancel (directory);
4754 	}
4755 	if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
4756 		link_info_cancel (directory);
4757 	}
4758 
4759 	if (REQUEST_WANTS_TYPE (request, REQUEST_EXTENSION_INFO)) {
4760 		extension_info_cancel (directory);
4761 	}
4762 	
4763 	if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
4764 		thumbnail_cancel (directory);
4765 	}
4766 
4767 	if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
4768 		mount_cancel (directory);
4769 	}
4770 	
4771 	nautilus_directory_async_state_changed (directory);
4772 }
4773 
4774 void
4775 nautilus_directory_cancel_loading_file_attributes (NautilusDirectory      *directory,
4776 						   NautilusFile           *file,
4777 						   NautilusFileAttributes  file_attributes)
4778 {
4779 	Request request;
4780 	
4781 	nautilus_directory_remove_file_from_work_queue (directory, file);
4782 
4783 	request = nautilus_directory_set_up_request (file_attributes);
4784 
4785 	if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
4786 		cancel_directory_count_for_file (directory, file);
4787 	}
4788 	if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
4789 		cancel_deep_counts_for_file (directory, file);
4790 	}
4791 	if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
4792 		cancel_mime_list_for_file (directory, file);
4793 	}
4794 	if (REQUEST_WANTS_TYPE (request, REQUEST_TOP_LEFT_TEXT)) {
4795 		cancel_top_left_text_for_file (directory, file);
4796 	}
4797 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
4798 		cancel_file_info_for_file (directory, file);
4799 	}
4800 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) {
4801 		cancel_filesystem_info_for_file (directory, file);
4802 	}
4803 	if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
4804 		cancel_link_info_for_file (directory, file);
4805 	}
4806 	if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
4807 		cancel_thumbnail_for_file (directory, file);
4808 	}
4809 	if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
4810 		cancel_mount_for_file (directory, file);
4811 	}
4812 
4813 	nautilus_directory_async_state_changed (directory);
4814 }
4815 
4816 void
4817 nautilus_directory_add_file_to_work_queue (NautilusDirectory *directory,
4818 					   NautilusFile *file)
4819 {
4820 	g_return_if_fail (file->details->directory == directory);
4821 
4822 	nautilus_file_queue_enqueue (directory->details->high_priority_queue,
4823 				     file);
4824 }
4825 
4826 
4827 static void
4828 add_all_files_to_work_queue (NautilusDirectory *directory)
4829 {
4830 	GList *node;
4831 	NautilusFile *file;
4832 	
4833 	for (node = directory->details->file_list; node != NULL; node = node->next) {
4834 		file = NAUTILUS_FILE (node->data);
4835 
4836 		nautilus_directory_add_file_to_work_queue (directory, file);
4837 	}
4838 }
4839 
4840 void
4841 nautilus_directory_remove_file_from_work_queue (NautilusDirectory *directory,
4842 						NautilusFile *file)
4843 {
4844 	nautilus_file_queue_remove (directory->details->high_priority_queue,
4845 				    file);
4846 	nautilus_file_queue_remove (directory->details->low_priority_queue,
4847 				    file);
4848 	nautilus_file_queue_remove (directory->details->extension_queue,
4849 				    file);
4850 }
4851 
4852 
4853 static void
4854 move_file_to_low_priority_queue (NautilusDirectory *directory,
4855 				 NautilusFile *file)
4856 {
4857 	/* Must add before removing to avoid ref underflow */
4858 	nautilus_file_queue_enqueue (directory->details->low_priority_queue,
4859 				     file);
4860 	nautilus_file_queue_remove (directory->details->high_priority_queue,
4861 				    file);
4862 }
4863 
4864 static void
4865 move_file_to_extension_queue (NautilusDirectory *directory,
4866 			      NautilusFile *file)
4867 {
4868 	/* Must add before removing to avoid ref underflow */
4869 	nautilus_file_queue_enqueue (directory->details->extension_queue,
4870 				     file);
4871 	nautilus_file_queue_remove (directory->details->low_priority_queue,
4872 				    file);
4873 }