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 }