1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
3 nautilus-directory-async.c: Nautilus directory model state machine.
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
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.
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.
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.
22 Author: Darin Adler <darin@bentspoon.com>
27 #include "nautilus-directory-metafile.h"
28 #include "nautilus-directory-notify.h"
29 #include "nautilus-directory-private.h"
30 #include "nautilus-file-attributes.h"
31 #include "nautilus-file-private.h"
32 #include "nautilus-file-utilities.h"
33 #include "nautilus-signaller.h"
34 #include "nautilus-global-preferences.h"
35 #include "nautilus-link.h"
36 #include "nautilus-marshal.h"
37 #include "nautilus-metafile.h"
38 #include <eel/eel-glib-extensions.h>
39 #include <eel/eel-string.h>
40 #include <gtk/gtkmain.h>
41 #include <libxml/parser.h>
45 /* turn this on to see messages about each load_directory call: */
47 #define DEBUG_LOAD_DIRECTORY
50 /* turn this on to check if async. job calls are balanced */
52 #define DEBUG_ASYNC_JOBS
55 /* turn this on to log things starting and stopping */
57 #define DEBUG_START_STOP
60 #define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100
62 /* Keep async. jobs down to this number for all directories. */
63 #define MAX_ASYNC_JOBS 10
65 struct TopLeftTextReadState
{
66 NautilusDirectory
*directory
;
69 GCancellable
*cancellable
;
72 struct LinkInfoReadState
{
73 NautilusDirectory
*directory
;
74 GCancellable
*cancellable
;
78 struct ThumbnailState
{
79 NautilusDirectory
*directory
;
80 GCancellable
*cancellable
;
82 gboolean trying_original
;
83 gboolean tried_original
;
87 NautilusDirectory
*directory
;
88 GCancellable
*cancellable
;
92 struct FilesystemInfoState
{
93 NautilusDirectory
*directory
;
94 GCancellable
*cancellable
;
98 struct DirectoryLoadState
{
99 NautilusDirectory
*directory
;
100 GCancellable
*cancellable
;
101 GFileEnumerator
*enumerator
;
102 GHashTable
*load_mime_list_hash
;
103 NautilusFile
*load_directory_file
;
107 struct MimeListState
{
108 NautilusDirectory
*directory
;
109 NautilusFile
*mime_list_file
;
110 GCancellable
*cancellable
;
111 GFileEnumerator
*enumerator
;
112 GHashTable
*mime_list_hash
;
115 struct GetInfoState
{
116 NautilusDirectory
*directory
;
117 GCancellable
*cancellable
;
120 struct NewFilesState
{
121 NautilusDirectory
*directory
;
122 GCancellable
*cancellable
;
126 struct DirectoryCountState
{
127 NautilusDirectory
*directory
;
128 NautilusFile
*count_file
;
129 GCancellable
*cancellable
;
130 GFileEnumerator
*enumerator
;
134 struct DeepCountState
{
135 NautilusDirectory
*directory
;
136 GCancellable
*cancellable
;
137 GFileEnumerator
*enumerator
;
138 GFile
*deep_count_location
;
139 GList
*deep_count_subdirectories
;
145 NautilusFile
*file
; /* Which file, NULL means all. */
147 NautilusDirectoryCallback directory
;
148 NautilusFileCallback file
;
150 gpointer callback_data
;
152 gboolean active
; /* Set to FALSE when the callback is triggered and
153 * scheduled to be called at idle, its still kept
154 * in the list so we can kill it when the file
160 NautilusFile
*file
; /* Which file, NULL means all. */
161 gboolean monitor_hidden_files
; /* defines whether "all" includes hidden files */
162 gboolean monitor_backup_files
; /* defines whether "all" includes backup files */
163 gconstpointer client
;
168 NautilusDirectory
*directory
;
169 NautilusInfoProvider
*provider
;
170 NautilusOperationHandle
*handle
;
171 NautilusOperationResult result
;
172 } InfoProviderResponse
;
174 typedef gboolean (* RequestCheck
) (const Request
*);
175 typedef gboolean (* FileCheck
) (NautilusFile
*);
177 /* Current number of async. jobs. */
178 static int async_job_count
;
179 static GHashTable
*waiting_directories
;
180 #ifdef DEBUG_ASYNC_JOBS
181 static GHashTable
*async_jobs
;
184 /* Hide kde trashcan directory */
185 static char *kde_trash_dir_name
= NULL
;
187 /* Forward declarations for functions that need them. */
188 static void deep_count_load (DeepCountState
*state
,
190 static gboolean
request_is_satisfied (NautilusDirectory
*directory
,
193 static void cancel_loading_attributes (NautilusDirectory
*directory
,
194 NautilusFileAttributes file_attributes
);
195 static void add_all_files_to_work_queue (NautilusDirectory
*directory
);
196 static void link_info_done (NautilusDirectory
*directory
,
201 gboolean is_launcher
);
202 static void move_file_to_low_priority_queue (NautilusDirectory
*directory
,
204 static void move_file_to_extension_queue (NautilusDirectory
*directory
,
206 static void nautilus_directory_invalidate_file_attributes (NautilusDirectory
*directory
,
207 NautilusFileAttributes file_attributes
);
210 nautilus_set_kde_trash_name (const char *trash_dir
)
212 g_free (kde_trash_dir_name
);
213 kde_trash_dir_name
= g_strdup (trash_dir
);
216 /* Some helpers for case-insensitive strings.
217 * Move to nautilus-glib-extensions?
221 istr_equal (gconstpointer v
, gconstpointer v2
)
223 return g_ascii_strcasecmp (v
, v2
) == 0;
227 istr_hash (gconstpointer key
)
233 for (p
= key
; *p
!= '\0'; p
++) {
234 h
= (h
<< 5) - h
+ g_ascii_tolower (*p
);
243 return g_hash_table_new_full (istr_hash
, istr_equal
, g_free
, NULL
);
247 istr_set_insert (GHashTable
*table
, const char *istr
)
251 key
= g_strdup (istr
);
252 g_hash_table_replace (table
, key
, key
);
256 add_istr_to_list (gpointer key
, gpointer value
, gpointer callback_data
)
260 list
= callback_data
;
261 *list
= g_list_prepend (*list
, g_strdup (key
));
265 istr_set_get_as_list (GHashTable
*table
)
270 g_hash_table_foreach (table
, add_istr_to_list
, &list
);
275 istr_set_destroy (GHashTable
*table
)
277 g_hash_table_destroy (table
);
280 /* Start a job. This is really just a way of limiting the number of
281 * async. requests that we issue at any given time. Without this, the
282 * number of requests is unbounded.
285 async_job_start (NautilusDirectory
*directory
,
288 #ifdef DEBUG_ASYNC_JOBS
292 #ifdef DEBUG_START_STOP
293 g_message ("starting %s in %p", job
, directory
->details
->location
);
296 g_assert (async_job_count
>= 0);
297 g_assert (async_job_count
<= MAX_ASYNC_JOBS
);
299 if (async_job_count
>= MAX_ASYNC_JOBS
) {
300 if (waiting_directories
== NULL
) {
301 waiting_directories
= eel_g_hash_table_new_free_at_exit
303 "nautilus-directory-async.c: waiting_directories");
306 g_hash_table_insert (waiting_directories
,
313 #ifdef DEBUG_ASYNC_JOBS
316 if (async_jobs
== NULL
) {
317 async_jobs
= eel_g_hash_table_new_free_at_exit
318 (g_str_hash
, g_str_equal
,
319 "nautilus-directory-async.c: async_jobs");
321 uri
= nautilus_directory_get_uri (directory
);
322 key
= g_strconcat (uri
, ": ", job
, NULL
);
323 if (g_hash_table_lookup (async_jobs
, key
) != NULL
) {
324 g_warning ("same job twice: %s in %s",
328 g_hash_table_insert (async_jobs
, key
, directory
);
332 async_job_count
+= 1;
338 async_job_end (NautilusDirectory
*directory
,
341 #ifdef DEBUG_ASYNC_JOBS
343 gpointer table_key
, value
;
346 #ifdef DEBUG_START_STOP
347 g_message ("stopping %s in %p", job
, directory
->details
->location
);
350 g_assert (async_job_count
> 0);
352 #ifdef DEBUG_ASYNC_JOBS
355 uri
= nautilus_directory_get_uri (directory
);
356 g_assert (async_jobs
!= NULL
);
357 key
= g_strconcat (uri
, ": ", job
, NULL
);
358 if (!g_hash_table_lookup_extended (async_jobs
, key
, &table_key
, &value
)) {
359 g_warning ("ending job we didn't start: %s in %s",
362 g_hash_table_remove (async_jobs
, key
);
370 async_job_count
-= 1;
373 /* Helper to get one value from a hash table. */
375 get_one_value_callback (gpointer key
, gpointer value
, gpointer callback_data
)
377 gpointer
*returned_value
;
379 returned_value
= callback_data
;
380 *returned_value
= value
;
383 /* return a single value from a hash table. */
385 get_one_value (GHashTable
*table
)
391 g_hash_table_foreach (table
, get_one_value_callback
, &value
);
396 /* Wake up directories that are "blocked" as long as there are job
400 async_job_wake_up (void)
402 static gboolean already_waking_up
= FALSE
;
405 g_assert (async_job_count
>= 0);
406 g_assert (async_job_count
<= MAX_ASYNC_JOBS
);
408 if (already_waking_up
) {
412 already_waking_up
= TRUE
;
413 while (async_job_count
< MAX_ASYNC_JOBS
) {
414 value
= get_one_value (waiting_directories
);
418 g_hash_table_remove (waiting_directories
, value
);
419 nautilus_directory_async_state_changed
420 (NAUTILUS_DIRECTORY (value
));
422 already_waking_up
= FALSE
;
426 directory_count_cancel (NautilusDirectory
*directory
)
428 if (directory
->details
->count_in_progress
!= NULL
) {
429 g_cancellable_cancel (directory
->details
->count_in_progress
->cancellable
);
434 deep_count_cancel (NautilusDirectory
*directory
)
436 if (directory
->details
->deep_count_in_progress
!= NULL
) {
437 g_assert (NAUTILUS_IS_FILE (directory
->details
->deep_count_file
));
439 g_cancellable_cancel (directory
->details
->deep_count_in_progress
->cancellable
);
441 directory
->details
->deep_count_file
->details
->deep_counts_status
= NAUTILUS_REQUEST_NOT_STARTED
;
443 directory
->details
->deep_count_in_progress
->directory
= NULL
;
444 directory
->details
->deep_count_in_progress
= NULL
;
445 directory
->details
->deep_count_file
= NULL
;
447 async_job_end (directory
, "deep count");
452 mime_list_cancel (NautilusDirectory
*directory
)
454 if (directory
->details
->mime_list_in_progress
!= NULL
) {
455 g_cancellable_cancel (directory
->details
->mime_list_in_progress
->cancellable
);
460 top_left_cancel (NautilusDirectory
*directory
)
462 if (directory
->details
->top_left_read_state
!= NULL
) {
463 g_cancellable_cancel (directory
->details
->top_left_read_state
->cancellable
);
464 directory
->details
->top_left_read_state
->directory
= NULL
;
465 directory
->details
->top_left_read_state
= NULL
;
467 async_job_end (directory
, "top left");
472 link_info_cancel (NautilusDirectory
*directory
)
474 if (directory
->details
->link_info_read_state
!= NULL
) {
475 g_cancellable_cancel (directory
->details
->link_info_read_state
->cancellable
);
476 directory
->details
->link_info_read_state
->directory
= NULL
;
477 directory
->details
->link_info_read_state
= NULL
;
478 async_job_end (directory
, "link info");
483 thumbnail_cancel (NautilusDirectory
*directory
)
485 if (directory
->details
->thumbnail_state
!= NULL
) {
486 g_cancellable_cancel (directory
->details
->thumbnail_state
->cancellable
);
487 directory
->details
->thumbnail_state
->directory
= NULL
;
488 directory
->details
->thumbnail_state
= NULL
;
489 async_job_end (directory
, "thumbnail");
494 mount_cancel (NautilusDirectory
*directory
)
496 if (directory
->details
->mount_state
!= NULL
) {
497 g_cancellable_cancel (directory
->details
->mount_state
->cancellable
);
498 directory
->details
->mount_state
->directory
= NULL
;
499 directory
->details
->mount_state
= NULL
;
500 async_job_end (directory
, "mount");
505 file_info_cancel (NautilusDirectory
*directory
)
507 if (directory
->details
->get_info_in_progress
!= NULL
) {
508 g_cancellable_cancel (directory
->details
->get_info_in_progress
->cancellable
);
509 directory
->details
->get_info_in_progress
->directory
= NULL
;
510 directory
->details
->get_info_in_progress
= NULL
;
511 directory
->details
->get_info_file
= NULL
;
513 async_job_end (directory
, "file info");
518 new_files_cancel (NautilusDirectory
*directory
)
521 NewFilesState
*state
;
523 if (directory
->details
->new_files_in_progress
!= NULL
) {
524 for (l
= directory
->details
->new_files_in_progress
; l
!= NULL
; l
= l
->next
) {
526 g_cancellable_cancel (state
->cancellable
);
527 state
->directory
= NULL
;
529 g_list_free (directory
->details
->new_files_in_progress
);
530 directory
->details
->new_files_in_progress
= NULL
;
535 monitor_key_compare (gconstpointer a
,
538 const Monitor
*monitor
;
539 const Monitor
*compare_monitor
;
542 compare_monitor
= data
;
544 if (monitor
->client
< compare_monitor
->client
) {
547 if (monitor
->client
> compare_monitor
->client
) {
551 if (monitor
->file
< compare_monitor
->file
) {
554 if (monitor
->file
> compare_monitor
->file
) {
562 find_monitor (NautilusDirectory
*directory
,
564 gconstpointer client
)
568 monitor
.client
= client
;
571 return g_list_find_custom (directory
->details
->monitor_list
,
573 monitor_key_compare
);
577 remove_monitor_link (NautilusDirectory
*directory
,
581 directory
->details
->monitor_list
=
582 g_list_remove_link (directory
->details
->monitor_list
, link
);
584 g_list_free_1 (link
);
589 remove_monitor (NautilusDirectory
*directory
,
591 gconstpointer client
)
593 remove_monitor_link (directory
, find_monitor (directory
, file
, client
));
597 nautilus_directory_set_up_request (Request
*request
,
598 NautilusFileAttributes file_attributes
)
600 memset (request
, 0, sizeof (*request
));
602 request
->directory_count
=
603 (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT
) != 0;
604 request
->deep_count
=
605 (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS
) != 0;
607 (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES
) != 0;
608 request
->file_info
= (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_INFO
) != 0;
610 if (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_LINK_INFO
) {
611 request
->file_info
= TRUE
;
612 request
->link_info
= TRUE
;
615 if (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT
) {
616 request
->top_left_text
= TRUE
;
617 request
->file_info
= TRUE
;
620 if (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT
) {
621 request
->large_top_left_text
= TRUE
;
622 request
->file_info
= TRUE
;
625 request
->metafile
|= (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_METADATA
) != 0;
626 request
->extension_info
= (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO
) != 0;
628 if (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL
) {
629 request
->thumbnail
= TRUE
;
630 request
->file_info
= TRUE
;
633 if (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_MOUNT
) {
634 request
->mount
= TRUE
;
635 request
->file_info
= TRUE
;
638 if (file_attributes
& NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO
) {
639 request
->filesystem_info
= TRUE
;
644 mime_db_changed_callback (GObject
*ignore
, NautilusDirectory
*dir
)
646 NautilusFileAttributes attrs
;
648 g_assert (dir
!= NULL
);
649 g_assert (dir
->details
!= NULL
);
651 attrs
= NAUTILUS_FILE_ATTRIBUTE_INFO
|
652 NAUTILUS_FILE_ATTRIBUTE_LINK_INFO
|
653 NAUTILUS_FILE_ATTRIBUTE_METADATA
|
654 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES
;
656 nautilus_directory_force_reload_internal (dir
, attrs
);
660 nautilus_directory_monitor_add_internal (NautilusDirectory
*directory
,
662 gconstpointer client
,
663 gboolean monitor_hidden_files
,
664 gboolean monitor_backup_files
,
665 NautilusFileAttributes file_attributes
,
666 NautilusDirectoryCallback callback
,
667 gpointer callback_data
)
672 g_assert (NAUTILUS_IS_DIRECTORY (directory
));
674 /* Replace any current monitor for this client/file pair. */
675 remove_monitor (directory
, file
, client
);
677 /* Add the new monitor. */
678 monitor
= g_new (Monitor
, 1);
679 monitor
->file
= file
;
680 monitor
->monitor_hidden_files
= monitor_hidden_files
;
681 monitor
->monitor_backup_files
= monitor_backup_files
;
682 monitor
->client
= client
;
683 nautilus_directory_set_up_request (&monitor
->request
, file_attributes
);
685 monitor
->request
.file_list
= file
== NULL
;
686 directory
->details
->monitor_list
=
687 g_list_prepend (directory
->details
->monitor_list
, monitor
);
689 if (callback
!= NULL
) {
690 file_list
= nautilus_directory_get_file_list (directory
);
691 (* callback
) (directory
, file_list
, callback_data
);
692 nautilus_file_list_free (file_list
);
695 /* Start the "real" monitoring (FAM or whatever). */
696 /* We always monitor the whole directory since in practice
697 * nautilus almost always shows the whole directory anyway, and
698 * it allows us to avoid one file monitor per file in a directory.
700 if (directory
->details
->monitor
== NULL
) {
701 directory
->details
->monitor
= nautilus_monitor_directory (directory
->details
->location
);
704 /* We could just call update_metadata_monitors here, but we can be smarter
705 * since we know what monitor was just added.
707 if (monitor
->request
.metafile
&& !directory
->details
->metafile_monitored
) {
708 nautilus_directory_register_metadata_monitor (directory
);
711 if (monitor
->request
.file_info
&& directory
->details
->mime_db_monitor
== 0) {
712 directory
->details
->mime_db_monitor
=
713 g_signal_connect_object (nautilus_signaller_get_current (),
715 G_CALLBACK (mime_db_changed_callback
), directory
, 0);
718 /* Put the monitor file or all the files on the work queue. */
720 nautilus_directory_add_file_to_work_queue (directory
, file
);
722 add_all_files_to_work_queue (directory
);
726 nautilus_directory_async_state_changed (directory
);
730 set_file_unconfirmed (NautilusFile
*file
, gboolean unconfirmed
)
732 NautilusDirectory
*directory
;
734 g_assert (NAUTILUS_IS_FILE (file
));
735 g_assert (unconfirmed
== FALSE
|| unconfirmed
== TRUE
);
737 if (file
->details
->unconfirmed
== unconfirmed
) {
740 file
->details
->unconfirmed
= unconfirmed
;
742 directory
= file
->details
->directory
;
744 directory
->details
->confirmed_file_count
--;
746 directory
->details
->confirmed_file_count
++;
750 static gboolean show_hidden_files
= TRUE
;
751 static gboolean show_backup_files
= TRUE
;
754 show_hidden_files_changed_callback (gpointer callback_data
)
756 show_hidden_files
= eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES
);
760 show_backup_files_changed_callback (gpointer callback_data
)
762 show_backup_files
= eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_BACKUP_FILES
);
766 should_skip_file (NautilusDirectory
*directory
, GFileInfo
*info
)
768 static gboolean show_hidden_files_changed_callback_installed
= FALSE
;
769 static gboolean show_backup_files_changed_callback_installed
= FALSE
;
771 /* Add the callback once for the life of our process */
772 if (!show_hidden_files_changed_callback_installed
) {
773 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES
,
774 show_hidden_files_changed_callback
,
776 show_hidden_files_changed_callback_installed
= TRUE
;
778 /* Peek for the first time */
779 show_hidden_files_changed_callback (NULL
);
782 /* Add the callback once for the life of our process */
783 if (!show_backup_files_changed_callback_installed
) {
784 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_BACKUP_FILES
,
785 show_backup_files_changed_callback
,
787 show_backup_files_changed_callback_installed
= TRUE
;
789 /* Peek for the first time */
790 show_backup_files_changed_callback (NULL
);
793 if (!show_hidden_files
&&
794 (g_file_info_get_is_hidden (info
) ||
795 (directory
!= NULL
&& directory
->details
->hidden_file_hash
!= NULL
&&
796 g_hash_table_lookup (directory
->details
->hidden_file_hash
,
797 g_file_info_get_name (info
)) != NULL
))) {
801 if (!show_backup_files
&& g_file_info_get_is_backup (info
)) {
809 dequeue_pending_idle_callback (gpointer callback_data
)
811 NautilusDirectory
*directory
;
812 GList
*pending_file_info
;
815 GList
*changed_files
, *added_files
;
816 GFileInfo
*file_info
;
817 const char *mimetype
, *name
;
818 DirectoryLoadState
*dir_load_state
;
820 directory
= NAUTILUS_DIRECTORY (callback_data
);
822 nautilus_directory_ref (directory
);
824 directory
->details
->dequeue_pending_idle_id
= 0;
826 /* Handle the files in the order we saw them. */
827 pending_file_info
= g_list_reverse (directory
->details
->pending_file_info
);
828 directory
->details
->pending_file_info
= NULL
;
830 /* If we are no longer monitoring, then throw away these. */
831 if (!nautilus_directory_is_file_list_monitored (directory
)) {
832 nautilus_directory_async_state_changed (directory
);
837 changed_files
= NULL
;
839 dir_load_state
= directory
->details
->directory_load_in_progress
;
841 /* Build a list of NautilusFile objects. */
842 for (node
= pending_file_info
; node
!= NULL
; node
= node
->next
) {
843 file_info
= node
->data
;
845 name
= g_file_info_get_name (file_info
);
847 /* Update the file count. */
848 /* FIXME bugzilla.gnome.org 45063: This could count a
849 * file twice if we get it from both load_directory
850 * and from new_files_callback. Not too hard to fix by
851 * moving this into the actual callback instead of
852 * waiting for the idle function.
854 if (dir_load_state
&&
855 !should_skip_file (directory
, file_info
)) {
856 dir_load_state
->load_file_count
+= 1;
858 /* Add the MIME type to the set. */
859 mimetype
= g_file_info_get_content_type (file_info
);
860 if (mimetype
!= NULL
) {
861 istr_set_insert (dir_load_state
->load_mime_list_hash
,
866 /* check if the file already exists */
867 file
= nautilus_directory_find_file_by_name (directory
, name
);
869 /* file already exists in dir, check if we still need to
870 * emit file_added or if it changed */
871 set_file_unconfirmed (file
, FALSE
);
872 if (!file
->details
->is_added
) {
873 /* We consider this newly added even if its in the list.
874 * This can happen if someone called nautilus_file_get_by_uri()
875 * on a file in the folder before the add signal was
877 nautilus_file_ref (file
);
878 file
->details
->is_added
= TRUE
;
879 added_files
= g_list_prepend (added_files
, file
);
880 } else if (nautilus_file_update_info (file
, file_info
)) {
881 /* File changed, notify about the change. */
882 nautilus_file_ref (file
);
883 changed_files
= g_list_prepend (changed_files
, file
);
886 /* new file, create a nautilus file object and add it to the list */
887 file
= nautilus_file_new_from_info (directory
, file_info
);
888 nautilus_directory_add_file (directory
, file
);
889 file
->details
->is_added
= TRUE
;
890 added_files
= g_list_prepend (added_files
, file
);
894 /* If we are done loading, then we assume that any unconfirmed
897 if (directory
->details
->directory_loaded
) {
898 for (node
= directory
->details
->file_list
;
899 node
!= NULL
; node
= next
) {
900 file
= NAUTILUS_FILE (node
->data
);
903 if (file
->details
->unconfirmed
) {
904 nautilus_file_ref (file
);
905 changed_files
= g_list_prepend (changed_files
, file
);
907 nautilus_file_mark_gone (file
);
912 /* Send the changed and added signals. */
913 nautilus_directory_emit_change_signals (directory
, changed_files
);
914 nautilus_file_list_free (changed_files
);
915 nautilus_directory_emit_files_added (directory
, added_files
);
916 nautilus_file_list_free (added_files
);
918 if (directory
->details
->directory_loaded
&&
919 !directory
->details
->directory_loaded_sent_notification
) {
920 /* Send the done_loading signal. */
921 nautilus_directory_emit_done_loading (directory
);
923 if (dir_load_state
) {
924 file
= dir_load_state
->load_directory_file
;
926 file
->details
->directory_count
= dir_load_state
->load_file_count
;
927 file
->details
->directory_count_is_up_to_date
= TRUE
;
928 file
->details
->got_directory_count
= TRUE
;
930 file
->details
->got_mime_list
= TRUE
;
931 file
->details
->mime_list_is_up_to_date
= TRUE
;
932 eel_g_list_free_deep (file
->details
->mime_list
);
933 file
->details
->mime_list
= istr_set_get_as_list
934 (dir_load_state
->load_mime_list_hash
);
936 nautilus_file_changed (file
);
939 nautilus_directory_async_state_changed (directory
);
941 directory
->details
->directory_loaded_sent_notification
= TRUE
;
945 eel_g_object_list_free (pending_file_info
);
947 /* Get the state machine running again. */
948 nautilus_directory_async_state_changed (directory
);
950 nautilus_directory_unref (directory
);
955 nautilus_directory_schedule_dequeue_pending (NautilusDirectory
*directory
)
957 if (directory
->details
->dequeue_pending_idle_id
== 0) {
958 directory
->details
->dequeue_pending_idle_id
959 = g_idle_add (dequeue_pending_idle_callback
, directory
);
964 directory_load_one (NautilusDirectory
*directory
,
971 if (g_file_info_get_name (info
) == NULL
) {
974 uri
= nautilus_directory_get_uri (directory
);
975 g_warning ("Got GFileInfo with NULL name in %s, ignoring. This shouldn't happen unless the gvfs backend is broken.\n", uri
);
981 /* Arrange for the "loading" part of the work. */
983 directory
->details
->pending_file_info
984 = g_list_prepend (directory
->details
->pending_file_info
, info
);
985 nautilus_directory_schedule_dequeue_pending (directory
);
989 directory_load_cancel (NautilusDirectory
*directory
)
992 DirectoryLoadState
*state
;
994 state
= directory
->details
->directory_load_in_progress
;
996 file
= state
->load_directory_file
;
997 file
->details
->loading_directory
= FALSE
;
998 if (file
->details
->directory
!= directory
) {
999 nautilus_directory_async_state_changed (file
->details
->directory
);
1002 g_cancellable_cancel (state
->cancellable
);
1003 state
->directory
= NULL
;
1004 directory
->details
->directory_load_in_progress
= NULL
;
1005 async_job_end (directory
, "file list");
1010 remove_callback (gpointer key
, gpointer value
, gpointer user_data
)
1016 file_list_cancel (NautilusDirectory
*directory
)
1018 directory_load_cancel (directory
);
1020 if (directory
->details
->dequeue_pending_idle_id
!= 0) {
1021 g_source_remove (directory
->details
->dequeue_pending_idle_id
);
1022 directory
->details
->dequeue_pending_idle_id
= 0;
1025 if (directory
->details
->pending_file_info
!= NULL
) {
1026 eel_g_object_list_free (directory
->details
->pending_file_info
);
1027 directory
->details
->pending_file_info
= NULL
;
1030 if (directory
->details
->hidden_file_hash
) {
1031 g_hash_table_foreach_remove (directory
->details
->hidden_file_hash
, remove_callback
, NULL
);
1036 directory_load_done (NautilusDirectory
*directory
,
1041 directory
->details
->directory_loaded
= TRUE
;
1042 directory
->details
->directory_loaded_sent_notification
= FALSE
;
1044 if (error
!= NULL
) {
1045 /* The load did not complete successfully. This means
1046 * we don't know the status of the files in this directory.
1047 * We clear the unconfirmed bit on each file here so that
1048 * they won't be marked "gone" later -- we don't know enough
1049 * about them to know whether they are really gone.
1051 for (node
= directory
->details
->file_list
;
1052 node
!= NULL
; node
= node
->next
) {
1053 set_file_unconfirmed (NAUTILUS_FILE (node
->data
), FALSE
);
1056 nautilus_directory_emit_load_error (directory
, error
);
1059 /* Call the idle function right away. */
1060 if (directory
->details
->dequeue_pending_idle_id
!= 0) {
1061 g_source_remove (directory
->details
->dequeue_pending_idle_id
);
1063 dequeue_pending_idle_callback (directory
);
1065 directory_load_cancel (directory
);
1068 /* This checks if there's a request for the metafile contents. */
1070 is_anyone_waiting_for_metafile (NautilusDirectory
*directory
)
1073 ReadyCallback
*callback
;
1076 for (node
= directory
->details
->call_when_ready_list
; node
!= NULL
; node
= node
->next
) {
1077 callback
= node
->data
;
1078 if (callback
->request
.metafile
) {
1083 for (node
= directory
->details
->monitor_list
; node
!= NULL
; node
= node
->next
) {
1084 monitor
= node
->data
;
1085 if (monitor
->request
.metafile
) {
1094 update_metadata_monitors (NautilusDirectory
*directory
)
1096 gboolean is_metadata_monitored
;
1098 is_metadata_monitored
= is_anyone_waiting_for_metafile (directory
);
1100 if (!directory
->details
->metafile_monitored
) {
1101 if (is_metadata_monitored
) {
1102 nautilus_directory_register_metadata_monitor (directory
);
1105 if (!is_metadata_monitored
) {
1106 nautilus_directory_unregister_metadata_monitor (directory
);
1112 nautilus_directory_monitor_remove_internal (NautilusDirectory
*directory
,
1114 gconstpointer client
)
1116 g_assert (NAUTILUS_IS_DIRECTORY (directory
));
1117 g_assert (file
== NULL
|| NAUTILUS_IS_FILE (file
));
1118 g_assert (client
!= NULL
);
1120 remove_monitor (directory
, file
, client
);
1122 if (directory
->details
->monitor
!= NULL
1123 && directory
->details
->monitor_list
== NULL
) {
1124 nautilus_monitor_cancel (directory
->details
->monitor
);
1125 directory
->details
->monitor
= NULL
;
1128 update_metadata_monitors (directory
);
1130 /* XXX - do we need to remove anything from the work queue? */
1132 nautilus_directory_async_state_changed (directory
);
1136 nautilus_directory_remove_file_monitors (NautilusDirectory
*directory
,
1139 GList
*result
, **list
, *node
, *next
;
1142 g_assert (NAUTILUS_IS_DIRECTORY (directory
));
1143 g_assert (NAUTILUS_IS_FILE (file
));
1144 g_assert (file
->details
->directory
== directory
);
1148 list
= &directory
->details
->monitor_list
;
1149 for (node
= directory
->details
->monitor_list
; node
!= NULL
; node
= next
) {
1151 monitor
= node
->data
;
1153 if (monitor
->file
== file
) {
1154 *list
= g_list_remove_link (*list
, node
);
1155 result
= g_list_concat (node
, result
);
1159 update_metadata_monitors (directory
);
1161 /* XXX - do we need to remove anything from the work queue? */
1163 nautilus_directory_async_state_changed (directory
);
1165 return (FileMonitors
*) result
;
1169 nautilus_directory_add_file_monitors (NautilusDirectory
*directory
,
1171 FileMonitors
*monitors
)
1175 g_assert (NAUTILUS_IS_DIRECTORY (directory
));
1176 g_assert (NAUTILUS_IS_FILE (file
));
1177 g_assert (file
->details
->directory
== directory
);
1179 if (monitors
== NULL
) {
1183 list
= &directory
->details
->monitor_list
;
1184 *list
= g_list_concat (*list
, (GList
*) monitors
);
1186 nautilus_directory_add_file_to_work_queue (directory
, file
);
1188 update_metadata_monitors (directory
);
1189 nautilus_directory_async_state_changed (directory
);
1193 ready_callback_key_compare (gconstpointer a
, gconstpointer b
)
1195 const ReadyCallback
*callback_a
, *callback_b
;
1200 if (callback_a
->file
< callback_b
->file
) {
1203 if (callback_a
->file
> callback_b
->file
) {
1206 if (callback_a
->file
== NULL
) {
1207 /* ANSI C doesn't allow ordered compares of function pointers, so we cast them to
1208 * normal pointers to make some overly pedantic compilers (*cough* HP-UX *cough*)
1209 * compile this. Of course, on any compiler where ordered function pointers actually
1210 * break this probably won't work, but at least it will compile on platforms where it
1211 * works, but stupid compilers won't let you use it.
1213 if ((void *)callback_a
->callback
.directory
< (void *)callback_b
->callback
.directory
) {
1216 if ((void *)callback_a
->callback
.directory
> (void *)callback_b
->callback
.directory
) {
1220 if ((void *)callback_a
->callback
.file
< (void *)callback_b
->callback
.file
) {
1223 if ((void *)callback_a
->callback
.file
> (void *)callback_b
->callback
.file
) {
1227 if (callback_a
->callback_data
< callback_b
->callback_data
) {
1230 if (callback_a
->callback_data
> callback_b
->callback_data
) {
1237 ready_callback_key_compare_only_active (gconstpointer a
, gconstpointer b
)
1239 const ReadyCallback
*callback_a
;
1243 /* Non active callbacks never match */
1244 if (!callback_a
->active
) {
1248 return ready_callback_key_compare (a
, b
);
1252 ready_callback_call (NautilusDirectory
*directory
,
1253 const ReadyCallback
*callback
)
1257 /* Call the callback. */
1258 if (callback
->file
!= NULL
) {
1259 if (callback
->callback
.file
) {
1260 (* callback
->callback
.file
) (callback
->file
,
1261 callback
->callback_data
);
1263 } else if (callback
->callback
.directory
!= NULL
) {
1264 if (directory
== NULL
|| !callback
->request
.file_list
) {
1267 file_list
= nautilus_directory_get_file_list (directory
);
1270 /* Pass back the file list if the user was waiting for it. */
1271 (* callback
->callback
.directory
) (directory
,
1273 callback
->callback_data
);
1275 nautilus_file_list_free (file_list
);
1280 nautilus_directory_call_when_ready_internal (NautilusDirectory
*directory
,
1282 NautilusFileAttributes file_attributes
,
1283 gboolean wait_for_file_list
,
1284 NautilusDirectoryCallback directory_callback
,
1285 NautilusFileCallback file_callback
,
1286 gpointer callback_data
)
1288 ReadyCallback callback
;
1290 g_assert (directory
== NULL
|| NAUTILUS_IS_DIRECTORY (directory
));
1291 g_assert (file
== NULL
|| NAUTILUS_IS_FILE (file
));
1292 g_assert (file
!= NULL
|| directory_callback
!= NULL
);
1294 /* Construct a callback object. */
1295 callback
.active
= TRUE
;
1296 callback
.file
= file
;
1298 callback
.callback
.directory
= directory_callback
;
1300 callback
.callback
.file
= file_callback
;
1302 callback
.callback_data
= callback_data
;
1303 nautilus_directory_set_up_request (&callback
.request
, file_attributes
);
1304 callback
.request
.file_list
= wait_for_file_list
;
1306 /* Handle the NULL case. */
1307 if (directory
== NULL
) {
1308 ready_callback_call (NULL
, &callback
);
1312 /* Check if the callback is already there. */
1313 if (g_list_find_custom (directory
->details
->call_when_ready_list
,
1315 ready_callback_key_compare_only_active
) != NULL
) {
1316 if (file_callback
!= NULL
&& directory_callback
!= NULL
) {
1317 g_warning ("tried to add a new callback while an old one was pending");
1319 /* NULL callback means, just read it. Conflicts are ok. */
1323 /* Add the new callback to the list. */
1324 directory
->details
->call_when_ready_list
= g_list_prepend
1325 (directory
->details
->call_when_ready_list
,
1326 g_memdup (&callback
, sizeof (callback
)));
1328 /* When we change the ready list we need to sync up metadata monitors.
1329 * We could just call update_metadata_monitors here, but we can be smarter
1330 * since we know what was just added.
1332 if (callback
.request
.metafile
&& !directory
->details
->metafile_monitored
) {
1333 nautilus_directory_register_metadata_monitor (directory
);
1336 /* Put the callback file or all the files on the work queue. */
1338 nautilus_directory_add_file_to_work_queue (directory
, file
);
1340 add_all_files_to_work_queue (directory
);
1343 nautilus_directory_async_state_changed (directory
);
1347 nautilus_directory_check_if_ready_internal (NautilusDirectory
*directory
,
1349 NautilusFileAttributes file_attributes
)
1353 g_assert (NAUTILUS_IS_DIRECTORY (directory
));
1355 nautilus_directory_set_up_request (&request
, file_attributes
);
1356 return request_is_satisfied (directory
, file
, &request
);
1360 remove_callback_link_keep_data (NautilusDirectory
*directory
,
1363 directory
->details
->call_when_ready_list
= g_list_remove_link
1364 (directory
->details
->call_when_ready_list
, link
);
1365 g_list_free_1 (link
);
1369 remove_callback_link (NautilusDirectory
*directory
,
1372 g_free (link
->data
);
1373 remove_callback_link_keep_data (directory
, link
);
1377 nautilus_directory_cancel_callback_internal (NautilusDirectory
*directory
,
1379 NautilusDirectoryCallback directory_callback
,
1380 NautilusFileCallback file_callback
,
1381 gpointer callback_data
)
1383 ReadyCallback callback
;
1386 if (directory
== NULL
) {
1390 g_assert (NAUTILUS_IS_DIRECTORY (directory
));
1391 g_assert (file
== NULL
|| NAUTILUS_IS_FILE (file
));
1392 g_assert (file
!= NULL
|| directory_callback
!= NULL
);
1393 g_assert (file
== NULL
|| file_callback
!= NULL
);
1395 /* Construct a callback object. */
1396 callback
.file
= file
;
1398 callback
.callback
.directory
= directory_callback
;
1400 callback
.callback
.file
= file_callback
;
1402 callback
.callback_data
= callback_data
;
1404 /* Remove all queued callback from the list (including non-active). */
1406 node
= g_list_find_custom (directory
->details
->call_when_ready_list
,
1408 ready_callback_key_compare
);
1410 remove_callback_link (directory
, node
);
1411 /* When we change the ready list we need to sync up metadata monitors. */
1412 update_metadata_monitors (directory
);
1414 nautilus_directory_async_state_changed (directory
);
1416 } while (node
!= NULL
);
1420 new_files_state_unref (NewFilesState
*state
)
1424 if (state
->count
== 0) {
1425 if (state
->directory
) {
1426 state
->directory
->details
->new_files_in_progress
=
1427 g_list_remove (state
->directory
->details
->new_files_in_progress
,
1431 g_object_unref (state
->cancellable
);
1437 new_files_callback (GObject
*source_object
,
1441 NautilusDirectory
*directory
;
1443 NewFilesState
*state
;
1447 if (state
->directory
== NULL
) {
1448 /* Operation was cancelled. Bail out */
1449 new_files_state_unref (state
);
1453 directory
= nautilus_directory_ref (state
->directory
);
1455 /* Queue up the new file. */
1456 info
= g_file_query_info_finish (G_FILE (source_object
), res
, NULL
);
1458 directory_load_one (directory
, info
);
1459 g_object_unref (info
);
1462 new_files_state_unref (state
);
1464 nautilus_directory_unref (directory
);
1468 nautilus_directory_get_info_for_new_files (NautilusDirectory
*directory
,
1469 GList
*location_list
)
1471 NewFilesState
*state
;
1475 if (location_list
== NULL
) {
1479 state
= g_new (NewFilesState
, 1);
1480 state
->directory
= directory
;
1481 state
->cancellable
= g_cancellable_new ();
1484 for (l
= location_list
; l
!= NULL
; l
= l
->next
) {
1489 g_file_query_info_async (location
,
1490 NAUTILUS_FILE_DEFAULT_ATTRIBUTES
,
1494 new_files_callback
, state
);
1497 directory
->details
->new_files_in_progress
1498 = g_list_prepend (directory
->details
->new_files_in_progress
,
1503 nautilus_async_destroying_file (NautilusFile
*file
)
1505 NautilusDirectory
*directory
;
1508 ReadyCallback
*callback
;
1511 directory
= file
->details
->directory
;
1514 /* Check for callbacks. */
1515 for (node
= directory
->details
->call_when_ready_list
; node
!= NULL
; node
= next
) {
1517 callback
= node
->data
;
1519 if (callback
->file
== file
) {
1520 /* Client should have cancelled callback. */
1521 if (callback
->active
) {
1522 g_warning ("destroyed file has call_when_ready pending");
1524 remove_callback_link (directory
, node
);
1529 /* Check for monitors. */
1530 for (node
= directory
->details
->monitor_list
; node
!= NULL
; node
= next
) {
1532 monitor
= node
->data
;
1534 if (monitor
->file
== file
) {
1535 /* Client should have removed monitor earlier. */
1536 g_warning ("destroyed file still being monitored");
1537 remove_monitor_link (directory
, node
);
1542 /* When we change the monitor or ready list we need to sync up metadata monitors */
1544 update_metadata_monitors (directory
);
1547 /* Check if it's a file that's currently being worked on.
1548 * If so, make that NULL so it gets canceled right away.
1550 if (directory
->details
->count_in_progress
!= NULL
&&
1551 directory
->details
->count_in_progress
->count_file
== file
) {
1552 directory
->details
->count_in_progress
->count_file
= NULL
;
1555 if (directory
->details
->deep_count_file
== file
) {
1556 directory
->details
->deep_count_file
= NULL
;
1559 if (directory
->details
->mime_list_in_progress
!= NULL
&&
1560 directory
->details
->mime_list_in_progress
->mime_list_file
== file
) {
1561 directory
->details
->mime_list_in_progress
->mime_list_file
= NULL
;
1564 if (directory
->details
->get_info_file
== file
) {
1565 directory
->details
->get_info_file
= NULL
;
1568 if (directory
->details
->top_left_read_state
!= NULL
1569 && directory
->details
->top_left_read_state
->file
== file
) {
1570 directory
->details
->top_left_read_state
->file
= NULL
;
1573 if (directory
->details
->link_info_read_state
!= NULL
&&
1574 directory
->details
->link_info_read_state
->file
== file
) {
1575 directory
->details
->link_info_read_state
->file
= NULL
;
1578 if (directory
->details
->extension_info_file
== file
) {
1579 directory
->details
->extension_info_file
= NULL
;
1583 if (directory
->details
->thumbnail_state
!= NULL
&&
1584 directory
->details
->thumbnail_state
->file
== file
) {
1585 directory
->details
->thumbnail_state
->file
= NULL
;
1589 if (directory
->details
->mount_state
!= NULL
&&
1590 directory
->details
->mount_state
->file
== file
) {
1591 directory
->details
->mount_state
->file
= NULL
;
1595 if (directory
->details
->filesystem_info_state
!= NULL
&&
1596 directory
->details
->filesystem_info_state
->file
== file
) {
1597 directory
->details
->filesystem_info_state
->file
= NULL
;
1601 /* Let the directory take care of the rest. */
1603 nautilus_directory_async_state_changed (directory
);
1608 lacks_directory_count (NautilusFile
*file
)
1610 return !file
->details
->directory_count_is_up_to_date
1611 && nautilus_file_should_show_directory_item_count (file
);
1615 should_get_directory_count_now (NautilusFile
*file
)
1617 return lacks_directory_count (file
)
1618 && !file
->details
->loading_directory
;
1622 wants_directory_count (const Request
*request
)
1624 return request
->directory_count
;
1628 lacks_top_left (NautilusFile
*file
)
1630 return file
->details
->file_info_is_up_to_date
&&
1631 !file
->details
->top_left_text_is_up_to_date
1632 && nautilus_file_should_get_top_left_text (file
);
1636 wants_top_left (const Request
*request
)
1638 return request
->top_left_text
;
1642 lacks_large_top_left (NautilusFile
*file
)
1644 return file
->details
->file_info_is_up_to_date
&&
1645 (!file
->details
->top_left_text_is_up_to_date
||
1646 file
->details
->got_large_top_left_text
!= file
->details
->got_top_left_text
)
1647 && nautilus_file_should_get_top_left_text (file
);
1651 wants_large_top_left (const Request
*request
)
1653 return request
->large_top_left_text
;
1657 lacks_info (NautilusFile
*file
)
1659 return !file
->details
->file_info_is_up_to_date
1660 && !file
->details
->is_gone
;
1664 lacks_filesystem_info (NautilusFile
*file
)
1666 return !file
->details
->filesystem_info_is_up_to_date
;
1670 wants_info (const Request
*request
)
1672 return request
->file_info
;
1676 wants_filesystem_info (const Request
*request
)
1678 return request
->filesystem_info
;
1682 lacks_deep_count (NautilusFile
*file
)
1684 return file
->details
->deep_counts_status
!= NAUTILUS_REQUEST_DONE
;
1688 wants_deep_count (const Request
*request
)
1690 return request
->deep_count
;
1694 lacks_mime_list (NautilusFile
*file
)
1696 return !file
->details
->mime_list_is_up_to_date
;
1700 should_get_mime_list (NautilusFile
*file
)
1702 return lacks_mime_list (file
)
1703 && !file
->details
->loading_directory
;
1707 wants_mime_list (const Request
*request
)
1709 return request
->mime_list
;
1712 lacks_link_info (NautilusFile
*file
)
1714 if (file
->details
->file_info_is_up_to_date
&&
1715 !file
->details
->link_info_is_up_to_date
) {
1716 if (nautilus_file_is_nautilus_link (file
)) {
1719 link_info_done (file
->details
->directory
, file
, NULL
, NULL
, NULL
, FALSE
);
1728 wants_link_info (const Request
*request
)
1730 return request
->link_info
;
1734 lacks_extension_info (NautilusFile
*file
)
1736 return file
->details
->pending_info_providers
!= NULL
;
1740 wants_extension_info (const Request
*request
)
1742 return request
->extension_info
;
1746 lacks_thumbnail (NautilusFile
*file
)
1748 return nautilus_file_should_show_thumbnail (file
) &&
1749 file
->details
->thumbnail_path
!= NULL
&&
1750 !file
->details
->thumbnail_is_up_to_date
;
1754 wants_thumbnail (const Request
*request
)
1756 return request
->thumbnail
;
1760 lacks_mount (NautilusFile
*file
)
1762 return (!file
->details
->mount_is_up_to_date
&&
1764 /* Unix mountpoint, could be a GMount */
1765 file
->details
->is_mountpoint
||
1767 /* The toplevel directory of something */
1768 (file
->details
->type
== G_FILE_TYPE_DIRECTORY
&&
1769 nautilus_file_is_self_owned (file
)) ||
1771 /* Mountable with a target_uri, could be a mountpoint */
1772 (file
->details
->type
== G_FILE_TYPE_MOUNTABLE
&&
1773 file
->details
->activation_location
!= NULL
)
1780 wants_mount (const Request
*request
)
1782 return request
->mount
;
1786 has_problem (NautilusDirectory
*directory
, NautilusFile
*file
, FileCheck problem
)
1791 return (* problem
) (file
);
1794 for (node
= directory
->details
->file_list
; node
!= NULL
; node
= node
->next
) {
1795 if ((* problem
) (node
->data
)) {
1804 request_is_satisfied (NautilusDirectory
*directory
,
1808 if (request
->metafile
&& !nautilus_directory_is_metadata_read (directory
)) {
1812 if (request
->file_list
&& !(directory
->details
->directory_loaded
&&
1813 directory
->details
->directory_loaded_sent_notification
)) {
1817 if (request
->directory_count
) {
1818 if (has_problem (directory
, file
, lacks_directory_count
)) {
1823 if (request
->file_info
) {
1824 if (has_problem (directory
, file
, lacks_info
)) {
1829 if (request
->filesystem_info
) {
1830 if (has_problem (directory
, file
, lacks_filesystem_info
)) {
1835 if (request
->top_left_text
) {
1836 if (has_problem (directory
, file
, lacks_top_left
)) {
1841 if (request
->large_top_left_text
) {
1842 if (has_problem (directory
, file
, lacks_large_top_left
)) {
1847 if (request
->deep_count
) {
1848 if (has_problem (directory
, file
, lacks_deep_count
)) {
1853 if (request
->thumbnail
) {
1854 if (has_problem (directory
, file
, lacks_thumbnail
)) {
1859 if (request
->mount
) {
1860 if (has_problem (directory
, file
, lacks_mount
)) {
1865 if (request
->mime_list
) {
1866 if (has_problem (directory
, file
, lacks_mime_list
)) {
1871 if (request
->link_info
) {
1872 if (has_problem (directory
, file
, lacks_link_info
)) {
1881 call_ready_callbacks_at_idle (gpointer callback_data
)
1883 NautilusDirectory
*directory
;
1885 ReadyCallback
*callback
;
1887 directory
= NAUTILUS_DIRECTORY (callback_data
);
1888 directory
->details
->call_ready_idle_id
= 0;
1890 nautilus_directory_ref (directory
);
1894 /* Check if any callbacks are non-active and call them if they are. */
1895 for (node
= directory
->details
->call_when_ready_list
;
1896 node
!= NULL
; node
= next
) {
1898 callback
= node
->data
;
1899 if (!callback
->active
) {
1900 /* Non-active, remove and call */
1908 /* Callbacks are one-shots, so remove it now. */
1909 remove_callback_link_keep_data (directory
, node
);
1911 /* Call the callback. */
1912 ready_callback_call (directory
, callback
);
1916 /* When we change the ready list we need to sync up metadata monitors. */
1917 update_metadata_monitors (directory
);
1919 nautilus_directory_async_state_changed (directory
);
1921 nautilus_directory_unref (directory
);
1927 schedule_call_ready_callbacks (NautilusDirectory
*directory
)
1929 if (directory
->details
->call_ready_idle_id
== 0) {
1930 directory
->details
->call_ready_idle_id
1931 = g_idle_add (call_ready_callbacks_at_idle
, directory
);
1935 /* Marks all callbacks that are ready as non-active and
1936 * calls them at idle time, unless they are removed
1939 call_ready_callbacks (NautilusDirectory
*directory
)
1943 ReadyCallback
*callback
;
1947 /* Check if any callbacks are satisifed and mark them for call them if they are. */
1948 for (node
= directory
->details
->call_when_ready_list
;
1949 node
!= NULL
; node
= next
) {
1951 callback
= node
->data
;
1952 if (callback
->active
&&
1953 request_is_satisfied (directory
, callback
->file
, &callback
->request
)) {
1954 callback
->active
= FALSE
;
1960 schedule_call_ready_callbacks (directory
);
1966 /* This checks if there's a request for monitoring the file list. */
1968 nautilus_directory_is_anyone_monitoring_file_list (NautilusDirectory
*directory
)
1971 ReadyCallback
*callback
;
1974 for (node
= directory
->details
->call_when_ready_list
;
1975 node
!= NULL
; node
= node
->next
) {
1976 callback
= node
->data
;
1977 if (callback
->request
.file_list
) {
1982 for (node
= directory
->details
->monitor_list
;
1983 node
!= NULL
; node
= node
->next
) {
1984 monitor
= node
->data
;
1985 if (monitor
->request
.file_list
) {
1993 /* This checks if the file list being monitored. */
1995 nautilus_directory_is_file_list_monitored (NautilusDirectory
*directory
)
1997 return directory
->details
->file_list_monitored
;
2001 mark_all_files_unconfirmed (NautilusDirectory
*directory
)
2006 for (node
= directory
->details
->file_list
; node
!= NULL
; node
= node
->next
) {
2008 set_file_unconfirmed (file
, TRUE
);
2013 read_dot_hidden_file (NautilusDirectory
*directory
)
2016 char *file_contents
;
2023 /* FIXME: We only support .hidden on file: uri's for the moment.
2024 * Need to figure out if we should do this async or sync to extend
2025 * it to all types of uris.
2027 if (directory
->details
->location
== NULL
||
2028 !g_file_is_native (directory
->details
->location
)) {
2032 child
= g_file_get_child (directory
->details
->location
, ".hidden");
2034 type
= G_FILE_TYPE_UNKNOWN
;
2036 info
= g_file_query_info (child
, G_FILE_ATTRIBUTE_STANDARD_TYPE
, 0, NULL
, NULL
);
2038 type
= g_file_info_get_file_type (info
);
2039 g_object_unref (info
);
2042 if (type
!= G_FILE_TYPE_REGULAR
) {
2043 g_object_unref (child
);
2047 if (!g_file_load_contents (child
, NULL
, &file_contents
, &file_size
, NULL
, NULL
)) {
2048 g_object_unref (child
);
2052 g_object_unref (child
);
2054 if (directory
->details
->hidden_file_hash
== NULL
) {
2055 directory
->details
->hidden_file_hash
=
2056 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
2059 /* Now parse the data */
2061 while (i
< file_size
) {
2065 while (i
< file_size
&& file_contents
[i
] != '\n') {
2070 char *hidden_filename
;
2072 hidden_filename
= g_strndup (file_contents
+ start
, i
- start
);
2073 g_hash_table_insert (directory
->details
->hidden_file_hash
,
2074 hidden_filename
, hidden_filename
);
2081 g_free (file_contents
);
2085 directory_load_state_free (DirectoryLoadState
*state
)
2087 if (state
->enumerator
) {
2088 if (!g_file_enumerator_is_closed (state
->enumerator
)) {
2089 g_file_enumerator_close_async (state
->enumerator
,
2090 0, NULL
, NULL
, NULL
);
2092 g_object_unref (state
->enumerator
);
2095 if (state
->load_mime_list_hash
!= NULL
) {
2096 istr_set_destroy (state
->load_mime_list_hash
);
2098 nautilus_file_unref (state
->load_directory_file
);
2099 g_object_unref (state
->cancellable
);
2104 more_files_callback (GObject
*source_object
,
2108 DirectoryLoadState
*state
;
2109 NautilusDirectory
*directory
;
2116 if (state
->directory
== NULL
) {
2117 /* Operation was cancelled. Bail out */
2118 directory_load_state_free (state
);
2122 directory
= nautilus_directory_ref (state
->directory
);
2124 g_assert (directory
->details
->directory_load_in_progress
!= NULL
);
2125 g_assert (directory
->details
->directory_load_in_progress
== state
);
2128 files
= g_file_enumerator_next_files_finish (state
->enumerator
,
2131 for (l
= files
; l
!= NULL
; l
= l
->next
) {
2133 directory_load_one (directory
, info
);
2134 g_object_unref (info
);
2137 if (nautilus_directory_file_list_length_reached (directory
) ||
2139 directory_load_done (directory
, error
);
2140 directory_load_state_free (state
);
2142 g_file_enumerator_next_files_async (state
->enumerator
,
2143 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
2146 more_files_callback
,
2150 nautilus_directory_unref (directory
);
2153 g_error_free (error
);
2156 g_list_free (files
);
2160 enumerate_children_callback (GObject
*source_object
,
2164 DirectoryLoadState
*state
;
2165 GFileEnumerator
*enumerator
;
2170 if (state
->directory
== NULL
) {
2171 /* Operation was cancelled. Bail out */
2172 directory_load_state_free (state
);
2177 enumerator
= g_file_enumerate_children_finish (G_FILE (source_object
),
2180 if (enumerator
== NULL
) {
2181 directory_load_done (state
->directory
, error
);
2182 g_error_free (error
);
2183 directory_load_state_free (state
);
2186 state
->enumerator
= enumerator
;
2187 g_file_enumerator_next_files_async (state
->enumerator
,
2188 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
2191 more_files_callback
,
2197 /* Start monitoring the file list if it isn't already. */
2199 start_monitoring_file_list (NautilusDirectory
*directory
)
2201 DirectoryLoadState
*state
;
2203 if (!directory
->details
->file_list_monitored
) {
2204 g_assert (!directory
->details
->directory_load_in_progress
);
2205 directory
->details
->file_list_monitored
= TRUE
;
2206 nautilus_file_list_ref (directory
->details
->file_list
);
2209 if (directory
->details
->directory_loaded
||
2210 directory
->details
->directory_load_in_progress
!= NULL
) {
2214 if (!async_job_start (directory
, "file list")) {
2218 mark_all_files_unconfirmed (directory
);
2220 state
= g_new0 (DirectoryLoadState
, 1);
2221 state
->directory
= directory
;
2222 state
->cancellable
= g_cancellable_new ();
2223 state
->load_mime_list_hash
= istr_set_new ();
2224 state
->load_file_count
= 0;
2226 g_assert (directory
->details
->location
!= NULL
);
2227 state
->load_directory_file
=
2228 nautilus_directory_get_corresponding_file (directory
);
2229 state
->load_directory_file
->details
->loading_directory
= TRUE
;
2231 read_dot_hidden_file (directory
);
2233 /* Hack to work around kde trash dir */
2234 if (kde_trash_dir_name
!= NULL
&& nautilus_directory_is_desktop_directory (directory
)) {
2237 if (directory
->details
->hidden_file_hash
== NULL
) {
2238 directory
->details
->hidden_file_hash
=
2239 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
2242 fn
= g_strdup (kde_trash_dir_name
);
2243 g_hash_table_insert (directory
->details
->hidden_file_hash
,
2248 #ifdef DEBUG_LOAD_DIRECTORY
2249 g_message ("load_directory called to monitor file list of %p", directory
->details
->location
);
2252 directory
->details
->directory_load_in_progress
= state
;
2254 g_file_enumerate_children_async (directory
->details
->location
,
2255 NAUTILUS_FILE_DEFAULT_ATTRIBUTES
,
2257 G_PRIORITY_DEFAULT
, /* prio */
2259 enumerate_children_callback
,
2263 /* Stop monitoring the file list if it is being monitored. */
2265 nautilus_directory_stop_monitoring_file_list (NautilusDirectory
*directory
)
2267 if (!directory
->details
->file_list_monitored
) {
2268 g_assert (directory
->details
->directory_load_in_progress
== NULL
);
2272 directory
->details
->file_list_monitored
= FALSE
;
2273 file_list_cancel (directory
);
2274 nautilus_file_list_unref (directory
->details
->file_list
);
2275 directory
->details
->directory_loaded
= FALSE
;
2279 file_list_start_or_stop (NautilusDirectory
*directory
)
2281 if (nautilus_directory_is_anyone_monitoring_file_list (directory
)) {
2282 start_monitoring_file_list (directory
);
2284 nautilus_directory_stop_monitoring_file_list (directory
);
2289 nautilus_file_invalidate_count_and_mime_list (NautilusFile
*file
)
2291 NautilusFileAttributes attributes
;
2293 attributes
= NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT
|
2294 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES
;
2296 nautilus_file_invalidate_attributes (file
, attributes
);
2300 /* Reset count and mime list. Invalidating deep counts is handled by
2301 * itself elsewhere because it's a relatively heavyweight and
2302 * special-purpose operation (see bug 5863). Also, the shallow count
2303 * needs to be refreshed when filtering changes, but the deep count
2304 * deliberately does not take filtering into account.
2307 nautilus_directory_invalidate_count_and_mime_list (NautilusDirectory
*directory
)
2311 file
= nautilus_directory_get_existing_corresponding_file (directory
);
2313 nautilus_file_invalidate_count_and_mime_list (file
);
2316 nautilus_file_unref (file
);
2320 nautilus_directory_invalidate_file_attributes (NautilusDirectory
*directory
,
2321 NautilusFileAttributes file_attributes
)
2325 cancel_loading_attributes (directory
, file_attributes
);
2327 for (node
= directory
->details
->file_list
; node
!= NULL
; node
= node
->next
) {
2328 nautilus_file_invalidate_attributes_internal (NAUTILUS_FILE (node
->data
),
2332 if (directory
->details
->as_file
!= NULL
) {
2333 nautilus_file_invalidate_attributes_internal (directory
->details
->as_file
,
2339 nautilus_directory_force_reload_internal (NautilusDirectory
*directory
,
2340 NautilusFileAttributes file_attributes
)
2342 /* invalidate attributes that are getting reloaded for all files */
2343 nautilus_directory_invalidate_file_attributes (directory
, file_attributes
);
2345 /* Start a new directory load. */
2346 file_list_cancel (directory
);
2347 directory
->details
->directory_loaded
= FALSE
;
2349 /* Start a new directory count. */
2350 nautilus_directory_invalidate_count_and_mime_list (directory
);
2352 add_all_files_to_work_queue (directory
);
2353 nautilus_directory_async_state_changed (directory
);
2357 monitor_includes_file (const Monitor
*monitor
,
2360 if (monitor
->file
== file
) {
2363 if (monitor
->file
!= NULL
) {
2366 if (file
== file
->details
->directory
->details
->as_file
) {
2369 return nautilus_file_should_show (file
,
2370 monitor
->monitor_hidden_files
,
2371 monitor
->monitor_backup_files
);
2375 is_needy (NautilusFile
*file
,
2376 FileCheck check_missing
,
2377 RequestCheck check_wanted
)
2379 NautilusDirectory
*directory
;
2381 ReadyCallback
*callback
;
2384 if (!(* check_missing
) (file
)) {
2388 directory
= file
->details
->directory
;
2389 for (node
= directory
->details
->call_when_ready_list
;
2390 node
!= NULL
; node
= node
->next
) {
2391 callback
= node
->data
;
2392 if (callback
->active
&&
2393 (* check_wanted
) (&callback
->request
)) {
2394 if (callback
->file
== file
) {
2397 if (callback
->file
== NULL
2398 && file
!= directory
->details
->as_file
) {
2403 for (node
= directory
->details
->monitor_list
;
2404 node
!= NULL
; node
= node
->next
) {
2405 monitor
= node
->data
;
2406 if ((* check_wanted
) (&monitor
->request
)) {
2407 if (monitor_includes_file (monitor
, file
)) {
2416 directory_count_stop (NautilusDirectory
*directory
)
2420 if (directory
->details
->count_in_progress
!= NULL
) {
2421 file
= directory
->details
->count_in_progress
->count_file
;
2423 g_assert (NAUTILUS_IS_FILE (file
));
2424 g_assert (file
->details
->directory
== directory
);
2426 should_get_directory_count_now
,
2427 wants_directory_count
)) {
2432 /* The count is not wanted, so stop it. */
2433 directory_count_cancel (directory
);
2438 count_non_skipped_files (GList
*list
)
2445 for (node
= list
; node
!= NULL
; node
= node
->next
) {
2447 if (!should_skip_file (NULL
, info
)) {
2455 count_children_done (NautilusDirectory
*directory
,
2456 NautilusFile
*count_file
,
2460 g_assert (NAUTILUS_IS_FILE (count_file
));
2462 count_file
->details
->directory_count_is_up_to_date
= TRUE
;
2464 /* Record either a failure or success. */
2466 count_file
->details
->directory_count_failed
= TRUE
;
2467 count_file
->details
->got_directory_count
= FALSE
;
2468 count_file
->details
->directory_count
= 0;
2470 count_file
->details
->directory_count_failed
= FALSE
;
2471 count_file
->details
->got_directory_count
= TRUE
;
2472 count_file
->details
->directory_count
= count
;
2474 directory
->details
->count_in_progress
= NULL
;
2476 /* Send file-changed even if count failed, so interested parties can
2477 * distinguish between unknowable and not-yet-known cases.
2479 nautilus_file_changed (count_file
);
2481 /* Start up the next one. */
2482 async_job_end (directory
, "directory count");
2483 nautilus_directory_async_state_changed (directory
);
2487 directory_count_state_free (DirectoryCountState
*state
)
2489 if (state
->enumerator
) {
2490 if (!g_file_enumerator_is_closed (state
->enumerator
)) {
2491 g_file_enumerator_close_async (state
->enumerator
,
2492 0, NULL
, NULL
, NULL
);
2494 g_object_unref (state
->enumerator
);
2496 g_object_unref (state
->cancellable
);
2497 nautilus_directory_unref (state
->directory
);
2502 count_more_files_callback (GObject
*source_object
,
2506 DirectoryCountState
*state
;
2507 NautilusDirectory
*directory
;
2512 directory
= state
->directory
;
2514 if (g_cancellable_is_cancelled (state
->cancellable
)) {
2515 /* Operation was cancelled. Bail out */
2516 directory
->details
->count_in_progress
= NULL
;
2518 async_job_end (directory
, "directory count");
2519 nautilus_directory_async_state_changed (directory
);
2521 directory_count_state_free (state
);
2526 g_assert (directory
->details
->count_in_progress
!= NULL
);
2527 g_assert (directory
->details
->count_in_progress
== state
);
2530 files
= g_file_enumerator_next_files_finish (state
->enumerator
,
2533 state
->file_count
+= count_non_skipped_files (files
);
2535 if (files
== NULL
) {
2536 count_children_done (directory
, state
->count_file
,
2537 TRUE
, state
->file_count
);
2538 directory_count_state_free (state
);
2540 g_file_enumerator_next_files_async (state
->enumerator
,
2541 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
2544 count_more_files_callback
,
2548 eel_g_object_list_free (files
);
2551 g_error_free (error
);
2556 count_children_callback (GObject
*source_object
,
2560 DirectoryCountState
*state
;
2561 GFileEnumerator
*enumerator
;
2562 NautilusDirectory
*directory
;
2567 if (g_cancellable_is_cancelled (state
->cancellable
)) {
2568 /* Operation was cancelled. Bail out */
2569 directory
= state
->directory
;
2570 directory
->details
->count_in_progress
= NULL
;
2572 async_job_end (directory
, "directory count");
2573 nautilus_directory_async_state_changed (directory
);
2575 directory_count_state_free (state
);
2581 enumerator
= g_file_enumerate_children_finish (G_FILE (source_object
),
2584 if (enumerator
== NULL
) {
2585 count_children_done (state
->directory
,
2588 g_error_free (error
);
2589 directory_count_state_free (state
);
2592 state
->enumerator
= enumerator
;
2593 g_file_enumerator_next_files_async (state
->enumerator
,
2594 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
2597 count_more_files_callback
,
2603 directory_count_start (NautilusDirectory
*directory
,
2607 DirectoryCountState
*state
;
2610 if (directory
->details
->count_in_progress
!= NULL
) {
2615 if (!is_needy (file
,
2616 should_get_directory_count_now
,
2617 wants_directory_count
)) {
2622 if (!nautilus_file_is_directory (file
)) {
2623 file
->details
->directory_count_is_up_to_date
= TRUE
;
2624 file
->details
->directory_count_failed
= FALSE
;
2625 file
->details
->got_directory_count
= FALSE
;
2627 nautilus_directory_async_state_changed (directory
);
2631 if (!async_job_start (directory
, "directory count")) {
2635 /* Start counting. */
2636 state
= g_new0 (DirectoryCountState
, 1);
2637 state
->count_file
= file
;
2638 state
->directory
= nautilus_directory_ref (directory
);
2639 state
->cancellable
= g_cancellable_new ();
2641 directory
->details
->count_in_progress
= state
;
2643 location
= nautilus_file_get_location (file
);
2644 #ifdef DEBUG_LOAD_DIRECTORY
2647 uri
= g_file_get_uri (location
);
2648 g_message ("load_directory called to get shallow file count for %s", uri
);
2653 g_file_enumerate_children_async (location
,
2654 G_FILE_ATTRIBUTE_STANDARD_NAME
","
2655 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN
","
2656 G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP
,
2657 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS
, /* flags */
2658 G_PRIORITY_DEFAULT
, /* prio */
2660 count_children_callback
,
2662 g_object_unref (location
);
2666 deep_count_one (DeepCountState
*state
,
2672 if (should_skip_file (NULL
, info
)) {
2676 file
= state
->directory
->details
->deep_count_file
;
2678 if (g_file_info_get_file_type (info
) == G_FILE_TYPE_DIRECTORY
) {
2679 /* Count the directory. */
2680 file
->details
->deep_directory_count
+= 1;
2682 /* Record the fact that we have to descend into this directory. */
2684 subdir
= g_file_get_child (state
->deep_count_location
, g_file_info_get_name (info
));
2685 state
->deep_count_subdirectories
= g_list_prepend
2686 (state
->deep_count_subdirectories
, subdir
);
2688 /* Even non-regular files count as files. */
2689 file
->details
->deep_file_count
+= 1;
2692 /* Count the size. */
2693 if (g_file_info_has_attribute (info
, G_FILE_ATTRIBUTE_STANDARD_SIZE
)) {
2694 file
->details
->deep_size
+= g_file_info_get_size (info
);
2699 deep_count_state_free (DeepCountState
*state
)
2701 if (state
->enumerator
) {
2702 if (!g_file_enumerator_is_closed (state
->enumerator
)) {
2703 g_file_enumerator_close_async (state
->enumerator
,
2704 0, NULL
, NULL
, NULL
);
2706 g_object_unref (state
->enumerator
);
2708 g_object_unref (state
->cancellable
);
2709 if (state
->deep_count_location
) {
2710 g_object_unref (state
->deep_count_location
);
2712 eel_g_object_list_free (state
->deep_count_subdirectories
);
2717 deep_count_next_dir (DeepCountState
*state
)
2721 NautilusDirectory
*directory
;
2724 directory
= state
->directory
;
2726 g_object_unref (state
->deep_count_location
);
2727 state
->deep_count_location
= NULL
;
2730 file
= directory
->details
->deep_count_file
;
2732 if (state
->deep_count_subdirectories
!= NULL
) {
2733 /* Work on a new directory. */
2734 location
= state
->deep_count_subdirectories
->data
;
2735 state
->deep_count_subdirectories
= g_list_remove
2736 (state
->deep_count_subdirectories
, location
);
2737 deep_count_load (state
, location
);
2738 g_object_unref (location
);
2740 file
->details
->deep_counts_status
= NAUTILUS_REQUEST_DONE
;
2741 directory
->details
->deep_count_file
= NULL
;
2742 directory
->details
->deep_count_in_progress
= NULL
;
2743 deep_count_state_free (state
);
2747 nautilus_file_updated_deep_count_in_progress (file
);
2750 nautilus_file_changed (file
);
2751 async_job_end (directory
, "deep count");
2752 nautilus_directory_async_state_changed (directory
);
2757 deep_count_more_files_callback (GObject
*source_object
,
2761 DeepCountState
*state
;
2762 NautilusDirectory
*directory
;
2768 if (state
->directory
== NULL
) {
2769 /* Operation was cancelled. Bail out */
2770 deep_count_state_free (state
);
2774 directory
= nautilus_directory_ref (state
->directory
);
2776 g_assert (directory
->details
->deep_count_in_progress
!= NULL
);
2777 g_assert (directory
->details
->deep_count_in_progress
== state
);
2779 files
= g_file_enumerator_next_files_finish (state
->enumerator
,
2782 for (l
= files
; l
!= NULL
; l
= l
->next
) {
2784 deep_count_one (state
, info
);
2785 g_object_unref (info
);
2788 if (files
== NULL
) {
2789 g_file_enumerator_close_async (state
->enumerator
, 0, NULL
, NULL
, NULL
);
2790 g_object_unref (state
->enumerator
);
2791 state
->enumerator
= NULL
;
2793 deep_count_next_dir (state
);
2795 g_file_enumerator_next_files_async (state
->enumerator
,
2796 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
2799 deep_count_more_files_callback
,
2803 g_list_free (files
);
2805 nautilus_directory_unref (directory
);
2809 deep_count_callback (GObject
*source_object
,
2813 DeepCountState
*state
;
2814 GFileEnumerator
*enumerator
;
2819 if (state
->directory
== NULL
) {
2820 /* Operation was cancelled. Bail out */
2821 deep_count_state_free (state
);
2825 file
= state
->directory
->details
->deep_count_file
;
2827 enumerator
= g_file_enumerate_children_finish (G_FILE (source_object
), res
, NULL
);
2829 if (enumerator
== NULL
) {
2830 file
->details
->deep_unreadable_count
+= 1;
2832 deep_count_next_dir (state
);
2834 state
->enumerator
= enumerator
;
2835 g_file_enumerator_next_files_async (state
->enumerator
,
2836 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
2839 deep_count_more_files_callback
,
2846 deep_count_load (DeepCountState
*state
, GFile
*location
)
2848 NautilusDirectory
*directory
;
2850 directory
= state
->directory
;
2851 state
->deep_count_location
= g_object_ref (location
);
2853 #ifdef DEBUG_LOAD_DIRECTORY
2854 g_message ("load_directory called to get deep file count for %p", location
);
2856 g_file_enumerate_children_async (state
->deep_count_location
,
2857 G_FILE_ATTRIBUTE_STANDARD_NAME
","
2858 G_FILE_ATTRIBUTE_STANDARD_TYPE
","
2859 G_FILE_ATTRIBUTE_STANDARD_SIZE
","
2860 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN
","
2861 G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP
,
2862 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS
, /* flags */
2863 G_PRIORITY_LOW
, /* prio */
2865 deep_count_callback
,
2870 deep_count_stop (NautilusDirectory
*directory
)
2874 if (directory
->details
->deep_count_in_progress
!= NULL
) {
2875 file
= directory
->details
->deep_count_file
;
2877 g_assert (NAUTILUS_IS_FILE (file
));
2878 g_assert (file
->details
->directory
== directory
);
2881 wants_deep_count
)) {
2886 /* The count is not wanted, so stop it. */
2887 deep_count_cancel (directory
);
2892 deep_count_start (NautilusDirectory
*directory
,
2897 DeepCountState
*state
;
2899 if (directory
->details
->deep_count_in_progress
!= NULL
) {
2904 if (!is_needy (file
,
2906 wants_deep_count
)) {
2911 if (!nautilus_file_is_directory (file
)) {
2912 file
->details
->deep_counts_status
= NAUTILUS_REQUEST_DONE
;
2914 nautilus_directory_async_state_changed (directory
);
2918 if (!async_job_start (directory
, "deep count")) {
2922 /* Start counting. */
2923 file
->details
->deep_counts_status
= NAUTILUS_REQUEST_IN_PROGRESS
;
2924 file
->details
->deep_directory_count
= 0;
2925 file
->details
->deep_file_count
= 0;
2926 file
->details
->deep_unreadable_count
= 0;
2927 file
->details
->deep_size
= 0;
2928 directory
->details
->deep_count_file
= file
;
2930 state
= g_new0 (DeepCountState
, 1);
2931 state
->directory
= directory
;
2932 state
->cancellable
= g_cancellable_new ();
2934 directory
->details
->deep_count_in_progress
= state
;
2936 location
= nautilus_file_get_location (file
);
2937 deep_count_load (state
, location
);
2938 g_object_unref (location
);
2942 mime_list_stop (NautilusDirectory
*directory
)
2946 if (directory
->details
->mime_list_in_progress
!= NULL
) {
2947 file
= directory
->details
->mime_list_in_progress
->mime_list_file
;
2949 g_assert (NAUTILUS_IS_FILE (file
));
2950 g_assert (file
->details
->directory
== directory
);
2952 should_get_mime_list
,
2958 /* The count is not wanted, so stop it. */
2959 mime_list_cancel (directory
);
2964 mime_list_state_free (MimeListState
*state
)
2966 if (state
->enumerator
) {
2967 if (!g_file_enumerator_is_closed (state
->enumerator
)) {
2968 g_file_enumerator_close_async (state
->enumerator
,
2969 0, NULL
, NULL
, NULL
);
2971 g_object_unref (state
->enumerator
);
2973 g_object_unref (state
->cancellable
);
2974 istr_set_destroy (state
->mime_list_hash
);
2975 nautilus_directory_unref (state
->directory
);
2981 mime_list_done (MimeListState
*state
, gboolean success
)
2984 NautilusDirectory
*directory
;
2986 directory
= state
->directory
;
2987 g_assert (directory
!= NULL
);
2989 file
= state
->mime_list_file
;
2991 file
->details
->mime_list_is_up_to_date
= TRUE
;
2992 eel_g_list_free_deep (file
->details
->mime_list
);
2994 file
->details
->mime_list_failed
= TRUE
;
2995 file
->details
->mime_list
= NULL
;
2997 file
->details
->got_mime_list
= TRUE
;
2998 file
->details
->mime_list
= istr_set_get_as_list (state
->mime_list_hash
);
3000 directory
->details
->mime_list_in_progress
= NULL
;
3002 /* Send file-changed even if getting the item type list
3003 * failed, so interested parties can distinguish between
3004 * unknowable and not-yet-known cases.
3006 nautilus_file_changed (file
);
3008 /* Start up the next one. */
3009 async_job_end (directory
, "MIME list");
3010 nautilus_directory_async_state_changed (directory
);
3014 mime_list_one (MimeListState
*state
,
3017 const char *mime_type
;
3019 if (should_skip_file (NULL
, info
)) {
3020 g_object_unref (info
);
3024 mime_type
= g_file_info_get_content_type (info
);
3025 if (mime_type
!= NULL
) {
3026 istr_set_insert (state
->mime_list_hash
, mime_type
);
3031 mime_list_callback (GObject
*source_object
,
3035 MimeListState
*state
;
3036 NautilusDirectory
*directory
;
3042 directory
= state
->directory
;
3044 if (g_cancellable_is_cancelled (state
->cancellable
)) {
3045 /* Operation was cancelled. Bail out */
3046 directory
->details
->mime_list_in_progress
= NULL
;
3048 async_job_end (directory
, "MIME list");
3049 nautilus_directory_async_state_changed (directory
);
3051 mime_list_state_free (state
);
3056 g_assert (directory
->details
->mime_list_in_progress
!= NULL
);
3057 g_assert (directory
->details
->mime_list_in_progress
== state
);
3060 files
= g_file_enumerator_next_files_finish (state
->enumerator
,
3063 for (l
= files
; l
!= NULL
; l
= l
->next
) {
3065 mime_list_one (state
, info
);
3066 g_object_unref (info
);
3069 if (files
== NULL
) {
3070 mime_list_done (state
, error
!= NULL
);
3071 mime_list_state_free (state
);
3073 g_file_enumerator_next_files_async (state
->enumerator
,
3074 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
3081 g_list_free (files
);
3084 g_error_free (error
);
3089 list_mime_enum_callback (GObject
*source_object
,
3093 MimeListState
*state
;
3094 GFileEnumerator
*enumerator
;
3095 NautilusDirectory
*directory
;
3100 if (g_cancellable_is_cancelled (state
->cancellable
)) {
3101 /* Operation was cancelled. Bail out */
3102 directory
= state
->directory
;
3103 directory
->details
->mime_list_in_progress
= NULL
;
3105 async_job_end (directory
, "MIME list");
3106 nautilus_directory_async_state_changed (directory
);
3108 mime_list_state_free (state
);
3114 enumerator
= g_file_enumerate_children_finish (G_FILE (source_object
),
3117 if (enumerator
== NULL
) {
3118 mime_list_done (state
, FALSE
);
3119 g_error_free (error
);
3120 mime_list_state_free (state
);
3123 state
->enumerator
= enumerator
;
3124 g_file_enumerator_next_files_async (state
->enumerator
,
3125 DIRECTORY_LOAD_ITEMS_PER_CALLBACK
,
3134 mime_list_start (NautilusDirectory
*directory
,
3138 MimeListState
*state
;
3141 mime_list_stop (directory
);
3143 if (directory
->details
->mime_list_in_progress
!= NULL
) {
3148 /* Figure out which file to get a mime list for. */
3149 if (!is_needy (file
,
3150 should_get_mime_list
,
3156 if (!nautilus_file_is_directory (file
)) {
3157 g_list_free (file
->details
->mime_list
);
3158 file
->details
->mime_list_failed
= FALSE
;
3159 file
->details
->got_mime_list
= FALSE
;
3160 file
->details
->mime_list_is_up_to_date
= TRUE
;
3162 nautilus_directory_async_state_changed (directory
);
3166 if (!async_job_start (directory
, "MIME list")) {
3171 state
= g_new0 (MimeListState
, 1);
3172 state
->mime_list_file
= file
;
3173 state
->directory
= nautilus_directory_ref (directory
);
3174 state
->cancellable
= g_cancellable_new ();
3175 state
->mime_list_hash
= istr_set_new ();
3177 directory
->details
->mime_list_in_progress
= state
;
3179 location
= nautilus_file_get_location (file
);
3180 #ifdef DEBUG_LOAD_DIRECTORY
3183 uri
= g_file_get_uri (location
);
3184 g_message ("load_directory called to get MIME list of %s", uri
);
3189 g_file_enumerate_children_async (location
,
3190 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE
,
3192 G_PRIORITY_LOW
, /* prio */
3194 list_mime_enum_callback
,
3196 g_object_unref (location
);
3200 top_left_stop (NautilusDirectory
*directory
)
3204 if (directory
->details
->top_left_read_state
!= NULL
) {
3205 file
= directory
->details
->top_left_read_state
->file
;
3207 g_assert (NAUTILUS_IS_FILE (file
));
3208 g_assert (file
->details
->directory
== directory
);
3213 lacks_large_top_left
,
3214 wants_large_top_left
)) {
3219 /* The top left is not wanted, so stop it. */
3220 top_left_cancel (directory
);
3225 top_left_read_state_free (TopLeftTextReadState
*state
)
3227 g_object_unref (state
->cancellable
);
3232 top_left_read_callback (GObject
*source_object
,
3234 gpointer callback_data
)
3236 TopLeftTextReadState
*state
;
3237 NautilusDirectory
*directory
;
3238 NautilusFileDetails
*file_details
;
3240 char *file_contents
;
3242 state
= callback_data
;
3244 if (state
->directory
== NULL
) {
3245 /* Operation was cancelled. Bail out */
3246 top_left_read_state_free (state
);
3250 directory
= nautilus_directory_ref (state
->directory
);
3252 file_details
= state
->file
->details
;
3254 file_details
->top_left_text_is_up_to_date
= TRUE
;
3255 g_free (file_details
->top_left_text
);
3257 if (g_file_load_partial_contents_finish (G_FILE (source_object
),
3259 &file_contents
, &file_size
,
3261 file_details
->top_left_text
= nautilus_extract_top_left_text (file_contents
, state
->large
, file_size
);
3262 file_details
->got_top_left_text
= TRUE
;
3263 file_details
->got_large_top_left_text
= state
->large
;
3264 g_free (file_contents
);
3266 file_details
->top_left_text
= NULL
;
3267 file_details
->got_top_left_text
= FALSE
;
3268 file_details
->got_large_top_left_text
= FALSE
;
3271 nautilus_file_changed (state
->file
);
3273 directory
->details
->top_left_read_state
= NULL
;
3274 async_job_end (directory
, "top left");
3276 top_left_read_state_free (state
);
3278 nautilus_directory_async_state_changed (directory
);
3280 nautilus_directory_unref (directory
);
3284 count_lines (const char *text
, int length
)
3289 for (i
= 0; i
< length
; i
++) {
3290 count
+= *text
++ == '\n';
3296 top_left_read_more_callback (const char *file_contents
,
3298 gpointer callback_data
)
3300 TopLeftTextReadState
*state
;
3302 state
= callback_data
;
3304 /* Stop reading when we have enough. */
3306 return bytes_read
< NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_BYTES
&&
3307 count_lines (file_contents
, bytes_read
) <= NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_LINES
;
3309 return bytes_read
< NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_BYTES
&&
3310 count_lines (file_contents
, bytes_read
) <= NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_LINES
;
3315 top_left_start (NautilusDirectory
*directory
,
3320 gboolean needs_large
;
3321 TopLeftTextReadState
*state
;
3323 if (directory
->details
->top_left_read_state
!= NULL
) {
3328 needs_large
= FALSE
;
3331 lacks_large_top_left
,
3332 wants_large_top_left
)) {
3336 /* Figure out which file to read the top left for. */
3337 if (!(needs_large
||
3345 if (!nautilus_file_contains_text (file
)) {
3346 g_free (file
->details
->top_left_text
);
3347 file
->details
->top_left_text
= NULL
;
3348 file
->details
->got_top_left_text
= FALSE
;
3349 file
->details
->got_large_top_left_text
= FALSE
;
3350 file
->details
->top_left_text_is_up_to_date
= TRUE
;
3352 nautilus_directory_async_state_changed (directory
);
3356 if (!async_job_start (directory
, "top left")) {
3360 /* Start reading. */
3361 state
= g_new0 (TopLeftTextReadState
, 1);
3362 state
->directory
= directory
;
3363 state
->cancellable
= g_cancellable_new ();
3364 state
->large
= needs_large
;
3367 directory
->details
->top_left_read_state
= state
;
3369 location
= nautilus_file_get_location (file
);
3370 g_file_load_partial_contents_async (location
,
3372 top_left_read_more_callback
,
3373 top_left_read_callback
,
3375 g_object_unref (location
);
3379 get_info_state_free (GetInfoState
*state
)
3381 g_object_unref (state
->cancellable
);
3386 query_info_callback (GObject
*source_object
,
3390 NautilusDirectory
*directory
;
3391 NautilusFile
*get_info_file
;
3393 GetInfoState
*state
;
3398 if (state
->directory
== NULL
) {
3399 /* Operation was cancelled. Bail out */
3400 get_info_state_free (state
);
3404 directory
= nautilus_directory_ref (state
->directory
);
3406 get_info_file
= directory
->details
->get_info_file
;
3407 g_assert (NAUTILUS_IS_FILE (get_info_file
));
3409 directory
->details
->get_info_file
= NULL
;
3410 directory
->details
->get_info_in_progress
= NULL
;
3412 /* ref here because we might be removing the last ref when we
3413 * mark the file gone below, but we need to keep a ref at
3414 * least long enough to send the change notification.
3416 nautilus_file_ref (get_info_file
);
3419 info
= g_file_query_info_finish (G_FILE (source_object
), res
, &error
);
3422 if (error
->domain
== G_IO_ERROR
&& error
->code
== G_IO_ERROR_NOT_FOUND
) {
3423 /* mark file as gone */
3424 nautilus_file_mark_gone (get_info_file
);
3426 get_info_file
->details
->file_info_is_up_to_date
= TRUE
;
3427 nautilus_file_clear_info (get_info_file
);
3428 get_info_file
->details
->get_info_failed
= TRUE
;
3429 get_info_file
->details
->get_info_error
= error
;
3431 nautilus_file_update_info (get_info_file
, info
);
3432 g_object_unref (info
);
3435 nautilus_file_changed (get_info_file
);
3436 nautilus_file_unref (get_info_file
);
3438 async_job_end (directory
, "file info");
3439 nautilus_directory_async_state_changed (directory
);
3441 nautilus_directory_unref (directory
);
3443 get_info_state_free (state
);
3447 file_info_stop (NautilusDirectory
*directory
)
3451 if (directory
->details
->get_info_in_progress
!= NULL
) {
3452 file
= directory
->details
->get_info_file
;
3454 g_assert (NAUTILUS_IS_FILE (file
));
3455 g_assert (file
->details
->directory
== directory
);
3456 if (is_needy (file
, lacks_info
, wants_info
)) {
3461 /* The info is not wanted, so stop it. */
3462 file_info_cancel (directory
);
3467 file_info_start (NautilusDirectory
*directory
,
3472 GetInfoState
*state
;
3474 file_info_stop (directory
);
3476 if (directory
->details
->get_info_in_progress
!= NULL
) {
3481 if (!is_needy (file
, lacks_info
, wants_info
)) {
3486 if (!async_job_start (directory
, "file info")) {
3490 directory
->details
->get_info_file
= file
;
3491 file
->details
->get_info_failed
= FALSE
;
3492 if (file
->details
->get_info_error
) {
3493 g_error_free (file
->details
->get_info_error
);
3494 file
->details
->get_info_error
= NULL
;
3497 state
= g_new (GetInfoState
, 1);
3498 state
->directory
= directory
;
3499 state
->cancellable
= g_cancellable_new ();
3501 directory
->details
->get_info_in_progress
= state
;
3503 location
= nautilus_file_get_location (file
);
3504 g_file_query_info_async (location
,
3505 NAUTILUS_FILE_DEFAULT_ATTRIBUTES
,
3508 state
->cancellable
, query_info_callback
, state
);
3509 g_object_unref (location
);
3513 link_info_done (NautilusDirectory
*directory
,
3518 gboolean is_launcher
)
3520 file
->details
->link_info_is_up_to_date
= TRUE
;
3522 nautilus_file_set_display_name (file
, name
, name
, TRUE
);
3524 file
->details
->got_link_info
= TRUE
;
3525 g_free (file
->details
->custom_icon
);
3527 if (file
->details
->activation_location
) {
3528 g_object_unref (file
->details
->activation_location
);
3529 file
->details
->activation_location
= NULL
;
3531 file
->details
->got_custom_activation_location
= TRUE
;
3532 file
->details
->activation_location
= g_file_new_for_uri (uri
);
3534 file
->details
->custom_icon
= g_strdup (icon
);
3535 file
->details
->is_launcher
= is_launcher
;
3537 nautilus_directory_async_state_changed (directory
);
3541 should_read_link_info_sync (NautilusFile
*file
)
3543 #ifdef READ_LOCAL_LINKS_SYNC
3544 return (nautilus_file_is_local (file
) && !nautilus_file_is_directory (file
));
3551 link_info_stop (NautilusDirectory
*directory
)
3555 if (directory
->details
->link_info_read_state
!= NULL
) {
3556 file
= directory
->details
->link_info_read_state
->file
;
3559 g_assert (NAUTILUS_IS_FILE (file
));
3560 g_assert (file
->details
->directory
== directory
);
3568 /* The link info is not wanted, so stop it. */
3569 link_info_cancel (directory
);
3574 link_info_got_data (NautilusDirectory
*directory
,
3578 char *file_contents
)
3580 char *uri
, *name
, *icon
;
3581 gboolean is_launcher
;
3583 nautilus_directory_ref (directory
);
3588 is_launcher
= FALSE
;
3590 /* Handle the case where we read the Nautilus link. */
3592 nautilus_link_get_link_info_given_file_contents (file_contents
, bytes_read
,
3593 &uri
, &name
, &icon
, &is_launcher
);
3595 /* FIXME bugzilla.gnome.org 42433: We should report this error to the user. */
3598 nautilus_file_ref (file
);
3599 link_info_done (directory
, file
, uri
, name
, icon
, is_launcher
);
3600 nautilus_file_changed (file
);
3601 nautilus_file_unref (file
);
3607 nautilus_directory_unref (directory
);
3611 link_info_read_state_free (LinkInfoReadState
*state
)
3613 g_object_unref (state
->cancellable
);
3618 link_info_nautilus_link_read_callback (GObject
*source_object
,
3622 LinkInfoReadState
*state
;
3624 char *file_contents
;
3626 NautilusDirectory
*directory
;
3630 if (state
->directory
== NULL
) {
3631 /* Operation was cancelled. Bail out */
3632 link_info_read_state_free (state
);
3636 directory
= nautilus_directory_ref (state
->directory
);
3638 result
= g_file_load_contents_finish (G_FILE (source_object
),
3640 &file_contents
, &file_size
,
3643 state
->directory
->details
->link_info_read_state
= NULL
;
3644 async_job_end (state
->directory
, "link info");
3646 link_info_got_data (state
->directory
, state
->file
, result
, file_size
, file_contents
);
3649 g_free (file_contents
);
3652 link_info_read_state_free (state
);
3654 nautilus_directory_unref (directory
);
3658 link_info_start (NautilusDirectory
*directory
,
3663 gboolean nautilus_style_link
;
3665 char *file_contents
;
3667 LinkInfoReadState
*state
;
3669 if (directory
->details
->link_info_read_state
!= NULL
) {
3674 if (!is_needy (file
,
3681 /* Figure out if it is a link. */
3682 nautilus_style_link
= nautilus_file_is_nautilus_link (file
);
3683 location
= nautilus_file_get_location (file
);
3685 /* If it's not a link we are done. If it is, we need to read it. */
3686 if (!nautilus_style_link
) {
3687 link_info_done (directory
, file
, NULL
, NULL
, NULL
, FALSE
);
3688 } else if (should_read_link_info_sync (file
)) {
3689 result
= g_file_load_contents (location
, NULL
, &file_contents
, &file_size
, NULL
, NULL
);
3690 link_info_got_data (directory
, file
, result
, file_size
, file_contents
);
3691 g_free (file_contents
);
3693 if (!async_job_start (directory
, "link info")) {
3694 g_object_unref (location
);
3698 state
= g_new0 (LinkInfoReadState
, 1);
3699 state
->directory
= directory
;
3701 state
->cancellable
= g_cancellable_new ();
3703 directory
->details
->link_info_read_state
= state
;
3705 g_file_load_contents_async (location
,
3707 link_info_nautilus_link_read_callback
,
3710 g_object_unref (location
);
3714 thumbnail_done (NautilusDirectory
*directory
,
3717 gboolean tried_original
)
3719 const char *thumb_mtime_str
;
3720 time_t thumb_mtime
= 0;
3722 file
->details
->thumbnail_is_up_to_date
= TRUE
;
3723 file
->details
->thumbnail_tried_original
= tried_original
;
3724 if (file
->details
->thumbnail
) {
3725 g_object_unref (file
->details
->thumbnail
);
3726 file
->details
->thumbnail
= NULL
;
3728 file
->details
->thumbnail_size
= 0;
3730 thumb_mtime_str
= gdk_pixbuf_get_option (pixbuf
, "tEXt::Thumb::MTime");
3731 if (thumb_mtime_str
) {
3732 thumb_mtime
= atol (thumb_mtime_str
);
3735 if (thumb_mtime
== 0 ||
3736 thumb_mtime
== file
->details
->mtime
) {
3737 file
->details
->thumbnail
= g_object_ref (pixbuf
);
3738 file
->details
->thumbnail_mtime
= thumb_mtime
;
3740 g_free (file
->details
->thumbnail_path
);
3741 file
->details
->thumbnail_path
= NULL
;
3745 nautilus_directory_async_state_changed (directory
);
3749 thumbnail_stop (NautilusDirectory
*directory
)
3753 if (directory
->details
->thumbnail_state
!= NULL
) {
3754 file
= directory
->details
->thumbnail_state
->file
;
3757 g_assert (NAUTILUS_IS_FILE (file
));
3758 g_assert (file
->details
->directory
== directory
);
3766 /* The link info is not wanted, so stop it. */
3767 thumbnail_cancel (directory
);
3772 thumbnail_got_pixbuf (NautilusDirectory
*directory
,
3775 gboolean tried_original
)
3777 nautilus_directory_ref (directory
);
3779 nautilus_file_ref (file
);
3780 thumbnail_done (directory
, file
, pixbuf
, tried_original
);
3781 nautilus_file_changed (file
);
3782 nautilus_file_unref (file
);
3785 g_object_unref (pixbuf
);
3788 nautilus_directory_unref (directory
);
3792 thumbnail_state_free (ThumbnailState
*state
)
3794 g_object_unref (state
->cancellable
);
3799 get_pixbuf_for_content (goffset file_len
,
3800 char *file_contents
)
3803 GdkPixbuf
*pixbuf
, *pixbuf2
;
3804 GdkPixbufLoader
*loader
;
3808 loader
= gdk_pixbuf_loader_new ();
3810 /* For some reason we have to write in chunks, or gdk-pixbuf fails */
3812 while (res
&& file_len
> 0) {
3813 chunk_len
= MIN (32*1024, file_len
);
3814 res
= gdk_pixbuf_loader_write (loader
, file_contents
, chunk_len
, NULL
);
3815 file_contents
+= chunk_len
;
3816 file_len
-= chunk_len
;
3819 res
= gdk_pixbuf_loader_close (loader
, NULL
);
3822 pixbuf
= g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader
));
3824 g_object_unref (G_OBJECT (loader
));
3827 pixbuf2
= gdk_pixbuf_apply_embedded_orientation (pixbuf
);
3828 g_object_unref (pixbuf
);
3836 thumbnail_read_callback (GObject
*source_object
,
3840 ThumbnailState
*state
;
3842 char *file_contents
;
3844 NautilusDirectory
*directory
;
3850 if (state
->directory
== NULL
) {
3851 /* Operation was cancelled. Bail out */
3852 thumbnail_state_free (state
);
3856 directory
= nautilus_directory_ref (state
->directory
);
3858 result
= g_file_load_contents_finish (G_FILE (source_object
),
3860 &file_contents
, &file_size
,
3865 pixbuf
= get_pixbuf_for_content (file_size
, file_contents
);
3866 g_free (file_contents
);
3869 if (pixbuf
== NULL
&& state
->trying_original
) {
3870 state
->trying_original
= FALSE
;
3872 location
= g_file_new_for_path (state
->file
->details
->thumbnail_path
);
3873 g_file_load_contents_async (location
,
3875 thumbnail_read_callback
,
3877 g_object_unref (location
);
3879 state
->directory
->details
->thumbnail_state
= NULL
;
3880 async_job_end (state
->directory
, "thumbnail");
3882 thumbnail_got_pixbuf (state
->directory
, state
->file
, pixbuf
, state
->tried_original
);
3884 thumbnail_state_free (state
);
3887 nautilus_directory_unref (directory
);
3891 thumbnail_start (NautilusDirectory
*directory
,
3896 ThumbnailState
*state
;
3898 if (directory
->details
->thumbnail_state
!= NULL
) {
3903 if (!is_needy (file
,
3910 if (!async_job_start (directory
, "thumbnail")) {
3914 state
= g_new0 (ThumbnailState
, 1);
3915 state
->directory
= directory
;
3917 state
->cancellable
= g_cancellable_new ();
3919 if (file
->details
->thumbnail_size
> 128) {
3920 state
->tried_original
= TRUE
;
3921 state
->trying_original
= TRUE
;
3922 location
= nautilus_file_get_location (file
);
3924 location
= g_file_new_for_path (file
->details
->thumbnail_path
);
3927 directory
->details
->thumbnail_state
= state
;
3929 g_file_load_contents_async (location
,
3931 thumbnail_read_callback
,
3933 g_object_unref (location
);
3937 mount_stop (NautilusDirectory
*directory
)
3941 if (directory
->details
->mount_state
!= NULL
) {
3942 file
= directory
->details
->mount_state
->file
;
3945 g_assert (NAUTILUS_IS_FILE (file
));
3946 g_assert (file
->details
->directory
== directory
);
3954 /* The link info is not wanted, so stop it. */
3955 mount_cancel (directory
);
3960 mount_state_free (MountState
*state
)
3962 g_object_unref (state
->cancellable
);
3967 got_mount (MountState
*state
, GMount
*mount
)
3969 NautilusDirectory
*directory
;
3972 directory
= nautilus_directory_ref (state
->directory
);
3974 state
->directory
->details
->mount_state
= NULL
;
3975 async_job_end (state
->directory
, "mount");
3977 file
= nautilus_file_ref (state
->file
);
3979 if (file
->details
->mount
) {
3980 g_object_unref (file
->details
->mount
);
3981 file
->details
->mount
= NULL
;
3984 file
->details
->mount_is_up_to_date
= TRUE
;
3986 file
->details
->mount
= g_object_ref (mount
);
3989 nautilus_directory_async_state_changed (directory
);
3990 nautilus_file_changed (file
);
3992 nautilus_file_unref (file
);
3994 nautilus_directory_unref (directory
);
3996 mount_state_free (state
);
4001 find_enclosing_mount_callback (GObject
*source_object
,
4007 GFile
*location
, *root
;
4010 if (state
->directory
== NULL
) {
4011 /* Operation was cancelled. Bail out */
4012 mount_state_free (state
);
4016 mount
= g_file_find_enclosing_mount_finish (G_FILE (source_object
),
4020 root
= g_mount_get_root (mount
);
4021 location
= nautilus_file_get_location (state
->file
);
4022 if (!g_file_equal (location
, root
)) {
4023 g_object_unref (mount
);
4026 g_object_unref (root
);
4027 g_object_unref (location
);
4030 got_mount (state
, mount
);
4033 g_object_unref (mount
);
4038 get_mount_at (GFile
*target
)
4040 GVolumeMonitor
*monitor
;
4045 monitor
= g_volume_monitor_get ();
4046 mounts
= g_volume_monitor_get_mounts (monitor
);
4049 for (l
= mounts
; l
!= NULL
; l
= l
->next
) {
4050 root
= g_mount_get_root (l
->data
);
4052 if (g_file_equal (target
, root
)) {
4053 found
= g_object_ref (l
->data
);
4057 g_object_unref (root
);
4060 eel_g_object_list_free (mounts
);
4062 g_object_unref (monitor
);
4068 mount_start (NautilusDirectory
*directory
,
4075 if (directory
->details
->mount_state
!= NULL
) {
4080 if (!is_needy (file
,
4087 if (!async_job_start (directory
, "mount")) {
4091 state
= g_new0 (MountState
, 1);
4092 state
->directory
= directory
;
4094 state
->cancellable
= g_cancellable_new ();
4096 location
= nautilus_file_get_location (file
);
4098 directory
->details
->mount_state
= state
;
4100 if (file
->details
->type
== G_FILE_TYPE_MOUNTABLE
) {
4105 target
= nautilus_file_get_activation_location (file
);
4106 if (target
!= NULL
) {
4107 mount
= get_mount_at (target
);
4108 g_object_unref (target
);
4111 got_mount (state
, mount
);
4114 g_object_unref (mount
);
4117 g_file_find_enclosing_mount_async (location
,
4120 find_enclosing_mount_callback
,
4123 g_object_unref (location
);
4127 filesystem_info_cancel (NautilusDirectory
*directory
)
4129 if (directory
->details
->filesystem_info_state
!= NULL
) {
4130 g_cancellable_cancel (directory
->details
->filesystem_info_state
->cancellable
);
4131 directory
->details
->filesystem_info_state
->directory
= NULL
;
4132 directory
->details
->filesystem_info_state
= NULL
;
4133 async_job_end (directory
, "filesystem info");
4138 filesystem_info_stop (NautilusDirectory
*directory
)
4142 if (directory
->details
->filesystem_info_state
!= NULL
) {
4143 file
= directory
->details
->filesystem_info_state
->file
;
4146 g_assert (NAUTILUS_IS_FILE (file
));
4147 g_assert (file
->details
->directory
== directory
);
4149 lacks_filesystem_info
,
4150 wants_filesystem_info
)) {
4155 /* The filesystem info is not wanted, so stop it. */
4156 filesystem_info_cancel (directory
);
4161 filesystem_info_state_free (FilesystemInfoState
*state
)
4163 g_object_unref (state
->cancellable
);
4168 got_filesystem_info (FilesystemInfoState
*state
, GFileInfo
*info
)
4170 NautilusDirectory
*directory
;
4173 /* careful here, info may be NULL */
4175 directory
= nautilus_directory_ref (state
->directory
);
4177 state
->directory
->details
->filesystem_info_state
= NULL
;
4178 async_job_end (state
->directory
, "filesystem info");
4180 file
= nautilus_file_ref (state
->file
);
4182 file
->details
->filesystem_info_is_up_to_date
= TRUE
;
4184 file
->details
->filesystem_use_preview
=
4185 g_file_info_get_attribute_uint32 (info
, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW
);
4186 file
->details
->filesystem_readonly
=
4187 g_file_info_get_attribute_boolean (info
, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY
);
4190 nautilus_directory_async_state_changed (directory
);
4191 nautilus_file_changed (file
);
4193 nautilus_file_unref (file
);
4195 nautilus_directory_unref (directory
);
4197 filesystem_info_state_free (state
);
4201 query_filesystem_info_callback (GObject
*source_object
,
4206 FilesystemInfoState
*state
;
4209 if (state
->directory
== NULL
) {
4210 /* Operation was cancelled. Bail out */
4211 filesystem_info_state_free (state
);
4215 info
= g_file_query_filesystem_info_finish (G_FILE (source_object
), res
, NULL
);
4217 got_filesystem_info (state
, info
);
4220 g_object_unref (info
);
4225 filesystem_info_start (NautilusDirectory
*directory
,
4230 FilesystemInfoState
*state
;
4232 if (directory
->details
->filesystem_info_state
!= NULL
) {
4237 if (!is_needy (file
,
4238 lacks_filesystem_info
,
4239 wants_filesystem_info
)) {
4244 if (!async_job_start (directory
, "filesystem info")) {
4248 state
= g_new0 (FilesystemInfoState
, 1);
4249 state
->directory
= directory
;
4251 state
->cancellable
= g_cancellable_new ();
4253 location
= nautilus_file_get_location (file
);
4255 directory
->details
->filesystem_info_state
= state
;
4257 g_file_query_filesystem_info_async (location
,
4258 G_FILE_ATTRIBUTE_FILESYSTEM_READONLY
","
4259 G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW
,
4262 query_filesystem_info_callback
,
4264 g_object_unref (location
);
4268 extension_info_cancel (NautilusDirectory
*directory
)
4270 if (directory
->details
->extension_info_in_progress
!= NULL
) {
4271 if (directory
->details
->extension_info_idle
) {
4272 g_source_remove (directory
->details
->extension_info_idle
);
4274 nautilus_info_provider_cancel_update
4275 (directory
->details
->extension_info_provider
,
4276 directory
->details
->extension_info_in_progress
);
4279 directory
->details
->extension_info_in_progress
= NULL
;
4280 directory
->details
->extension_info_file
= NULL
;
4281 directory
->details
->extension_info_provider
= NULL
;
4282 directory
->details
->extension_info_idle
= 0;
4284 async_job_end (directory
, "extension info");
4289 extension_info_stop (NautilusDirectory
*directory
)
4291 if (directory
->details
->extension_info_in_progress
!= NULL
) {
4294 file
= directory
->details
->extension_info_file
;
4296 g_assert (NAUTILUS_IS_FILE (file
));
4297 g_assert (file
->details
->directory
== directory
);
4298 if (is_needy (file
, lacks_extension_info
, wants_extension_info
)) {
4303 /* The info is not wanted, so stop it. */
4304 extension_info_cancel (directory
);
4309 finish_info_provider (NautilusDirectory
*directory
,
4311 NautilusInfoProvider
*provider
)
4313 file
->details
->pending_info_providers
=
4314 g_list_remove (file
->details
->pending_info_providers
,
4316 g_object_unref (provider
);
4318 nautilus_directory_async_state_changed (directory
);
4320 if (file
->details
->pending_info_providers
== NULL
) {
4321 nautilus_file_info_providers_done (file
);
4327 info_provider_idle_callback (gpointer user_data
)
4329 InfoProviderResponse
*response
;
4330 NautilusDirectory
*directory
;
4332 response
= user_data
;
4333 directory
= response
->directory
;
4335 if (response
->handle
!= directory
->details
->extension_info_in_progress
4336 || response
->provider
!= directory
->details
->extension_info_provider
) {
4337 g_warning ("Unexpected plugin response. This probably indicates a bug in a Nautilus extension: handle=%p", response
->handle
);
4340 async_job_end (directory
, "extension info");
4342 file
= directory
->details
->extension_info_file
;
4344 directory
->details
->extension_info_file
= NULL
;
4345 directory
->details
->extension_info_provider
= NULL
;
4346 directory
->details
->extension_info_in_progress
= NULL
;
4347 directory
->details
->extension_info_idle
= 0;
4349 finish_info_provider (directory
, file
, response
->provider
);
4356 info_provider_callback (NautilusInfoProvider
*provider
,
4357 NautilusOperationHandle
*handle
,
4358 NautilusOperationResult result
,
4361 InfoProviderResponse
*response
;
4363 response
= g_new0 (InfoProviderResponse
, 1);
4364 response
->provider
= provider
;
4365 response
->handle
= handle
;
4366 response
->result
= result
;
4367 response
->directory
= NAUTILUS_DIRECTORY (user_data
);
4369 response
->directory
->details
->extension_info_idle
=
4370 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE
,
4371 info_provider_idle_callback
, response
,
4376 extension_info_start (NautilusDirectory
*directory
,
4380 NautilusInfoProvider
*provider
;
4381 NautilusOperationResult result
;
4382 NautilusOperationHandle
*handle
;
4383 GClosure
*update_complete
;
4385 if (directory
->details
->extension_info_in_progress
!= NULL
) {
4390 if (!is_needy (file
, lacks_extension_info
, wants_extension_info
)) {
4395 if (!async_job_start (directory
, "extension info")) {
4399 provider
= file
->details
->pending_info_providers
->data
;
4401 update_complete
= g_cclosure_new (G_CALLBACK (info_provider_callback
),
4404 g_closure_set_marshal (update_complete
,
4405 nautilus_marshal_VOID__POINTER_ENUM
);
4407 result
= nautilus_info_provider_update_file_info
4409 NAUTILUS_FILE_INFO (file
),
4413 g_closure_unref (update_complete
);
4415 if (result
== NAUTILUS_OPERATION_COMPLETE
||
4416 result
== NAUTILUS_OPERATION_FAILED
) {
4417 finish_info_provider (directory
, file
, provider
);
4418 async_job_end (directory
, "extension info");
4420 directory
->details
->extension_info_in_progress
= handle
;
4421 directory
->details
->extension_info_provider
= provider
;
4422 directory
->details
->extension_info_file
= file
;
4427 start_or_stop_io (NautilusDirectory
*directory
)
4432 /* Start or stop reading files. */
4433 file_list_start_or_stop (directory
);
4435 /* Stop any no longer wanted attribute fetches. */
4436 file_info_stop (directory
);
4437 directory_count_stop (directory
);
4438 deep_count_stop (directory
);
4439 mime_list_stop (directory
);
4440 top_left_stop (directory
);
4441 link_info_stop (directory
);
4442 extension_info_stop (directory
);
4443 mount_stop (directory
);
4444 thumbnail_stop (directory
);
4445 filesystem_info_stop (directory
);
4448 /* Take files that are all done off the queue. */
4449 while (!nautilus_file_queue_is_empty (directory
->details
->high_priority_queue
)) {
4450 file
= nautilus_file_queue_head (directory
->details
->high_priority_queue
);
4452 /* Start getting attributes if possible */
4453 file_info_start (directory
, file
, &doing_io
);
4454 link_info_start (directory
, file
, &doing_io
);
4460 move_file_to_low_priority_queue (directory
, file
);
4463 /* High priority queue must be empty */
4464 while (!nautilus_file_queue_is_empty (directory
->details
->low_priority_queue
)) {
4465 file
= nautilus_file_queue_head (directory
->details
->low_priority_queue
);
4467 /* Start getting attributes if possible */
4468 mount_start (directory
, file
, &doing_io
);
4469 directory_count_start (directory
, file
, &doing_io
);
4470 deep_count_start (directory
, file
, &doing_io
);
4471 mime_list_start (directory
, file
, &doing_io
);
4472 top_left_start (directory
, file
, &doing_io
);
4473 thumbnail_start (directory
, file
, &doing_io
);
4474 filesystem_info_start (directory
, file
, &doing_io
);
4480 move_file_to_extension_queue (directory
, file
);
4483 /* Low priority queue must be empty */
4484 while (!nautilus_file_queue_is_empty (directory
->details
->extension_queue
)) {
4485 file
= nautilus_file_queue_head (directory
->details
->extension_queue
);
4487 /* Start getting attributes if possible */
4488 extension_info_start (directory
, file
, &doing_io
);
4493 nautilus_directory_remove_file_from_work_queue (directory
, file
);
4497 /* Call this when the monitor or call when ready list changes,
4498 * or when some I/O is completed.
4501 nautilus_directory_async_state_changed (NautilusDirectory
*directory
)
4503 /* Check if any callbacks are satisfied and call them if they
4504 * are. Do this last so that any changes done in start or stop
4505 * I/O functions immediately (not in callbacks) are taken into
4506 * consideration. If any callbacks are called, consider the
4507 * I/O state again so that we can release or cancel I/O that
4508 * is not longer needed once the callbacks are satisfied.
4511 if (directory
->details
->in_async_service_loop
) {
4512 directory
->details
->state_changed
= TRUE
;
4515 directory
->details
->in_async_service_loop
= TRUE
;
4516 nautilus_directory_ref (directory
);
4518 directory
->details
->state_changed
= FALSE
;
4519 start_or_stop_io (directory
);
4520 if (call_ready_callbacks (directory
)) {
4521 directory
->details
->state_changed
= TRUE
;
4523 } while (directory
->details
->state_changed
);
4524 directory
->details
->in_async_service_loop
= FALSE
;
4525 nautilus_directory_unref (directory
);
4527 /* Check if any directories should wake up. */
4528 async_job_wake_up ();
4532 nautilus_directory_cancel (NautilusDirectory
*directory
)
4534 /* Arbitrary order (kept alphabetical). */
4535 deep_count_cancel (directory
);
4536 directory_count_cancel (directory
);
4537 file_info_cancel (directory
);
4538 file_list_cancel (directory
);
4539 link_info_cancel (directory
);
4540 mime_list_cancel (directory
);
4541 new_files_cancel (directory
);
4542 top_left_cancel (directory
);
4543 extension_info_cancel (directory
);
4544 thumbnail_cancel (directory
);
4545 mount_cancel (directory
);
4546 filesystem_info_cancel (directory
);
4548 /* We aren't waiting for anything any more. */
4549 if (waiting_directories
!= NULL
) {
4550 g_hash_table_remove (waiting_directories
, directory
);
4553 /* Check if any directories should wake up. */
4554 async_job_wake_up ();
4558 cancel_directory_count_for_file (NautilusDirectory
*directory
,
4561 if (directory
->details
->count_in_progress
!= NULL
&&
4562 directory
->details
->count_in_progress
->count_file
== file
) {
4563 directory_count_cancel (directory
);
4568 cancel_deep_counts_for_file (NautilusDirectory
*directory
,
4571 if (directory
->details
->deep_count_file
== file
) {
4572 deep_count_cancel (directory
);
4577 cancel_mime_list_for_file (NautilusDirectory
*directory
,
4580 if (directory
->details
->mime_list_in_progress
!= NULL
&&
4581 directory
->details
->mime_list_in_progress
->mime_list_file
== file
) {
4582 mime_list_cancel (directory
);
4587 cancel_top_left_text_for_file (NautilusDirectory
*directory
,
4590 if (directory
->details
->top_left_read_state
!= NULL
&&
4591 directory
->details
->top_left_read_state
->file
== file
) {
4592 top_left_cancel (directory
);
4597 cancel_file_info_for_file (NautilusDirectory
*directory
,
4600 if (directory
->details
->get_info_file
== file
) {
4601 file_info_cancel (directory
);
4606 cancel_thumbnail_for_file (NautilusDirectory
*directory
,
4609 if (directory
->details
->thumbnail_state
!= NULL
&&
4610 directory
->details
->thumbnail_state
->file
== file
) {
4611 thumbnail_cancel (directory
);
4616 cancel_mount_for_file (NautilusDirectory
*directory
,
4619 if (directory
->details
->mount_state
!= NULL
&&
4620 directory
->details
->mount_state
->file
== file
) {
4621 mount_cancel (directory
);
4626 cancel_filesystem_info_for_file (NautilusDirectory
*directory
,
4629 if (directory
->details
->filesystem_info_state
!= NULL
&&
4630 directory
->details
->filesystem_info_state
->file
== file
) {
4631 filesystem_info_cancel (directory
);
4636 cancel_link_info_for_file (NautilusDirectory
*directory
,
4639 if (directory
->details
->link_info_read_state
!= NULL
&&
4640 directory
->details
->link_info_read_state
->file
== file
) {
4641 link_info_cancel (directory
);
4647 cancel_loading_attributes (NautilusDirectory
*directory
,
4648 NautilusFileAttributes file_attributes
)
4652 nautilus_directory_set_up_request (&request
,
4655 if (request
.directory_count
) {
4656 directory_count_cancel (directory
);
4658 if (request
.deep_count
) {
4659 deep_count_cancel (directory
);
4661 if (request
.mime_list
) {
4662 mime_list_cancel (directory
);
4664 if (request
.top_left_text
) {
4665 top_left_cancel (directory
);
4667 if (request
.file_info
) {
4668 file_info_cancel (directory
);
4670 if (request
.filesystem_info
) {
4671 filesystem_info_cancel (directory
);
4673 if (request
.link_info
) {
4674 link_info_cancel (directory
);
4677 if (request
.extension_info
) {
4678 extension_info_cancel (directory
);
4681 if (request
.thumbnail
) {
4682 thumbnail_cancel (directory
);
4685 if (request
.mount
) {
4686 mount_cancel (directory
);
4689 /* FIXME bugzilla.gnome.org 45064: implement cancelling metadata when we
4690 implement invalidating metadata */
4692 nautilus_directory_async_state_changed (directory
);
4696 nautilus_directory_cancel_loading_file_attributes (NautilusDirectory
*directory
,
4698 NautilusFileAttributes file_attributes
)
4702 nautilus_directory_remove_file_from_work_queue (directory
, file
);
4704 nautilus_directory_set_up_request (&request
,
4707 if (request
.directory_count
) {
4708 cancel_directory_count_for_file (directory
, file
);
4710 if (request
.deep_count
) {
4711 cancel_deep_counts_for_file (directory
, file
);
4713 if (request
.mime_list
) {
4714 cancel_mime_list_for_file (directory
, file
);
4716 if (request
.top_left_text
) {
4717 cancel_top_left_text_for_file (directory
, file
);
4719 if (request
.file_info
) {
4720 cancel_file_info_for_file (directory
, file
);
4722 if (request
.filesystem_info
) {
4723 cancel_filesystem_info_for_file (directory
, file
);
4725 if (request
.link_info
) {
4726 cancel_link_info_for_file (directory
, file
);
4728 if (request
.thumbnail
) {
4729 cancel_thumbnail_for_file (directory
, file
);
4731 if (request
.mount
) {
4732 cancel_mount_for_file (directory
, file
);
4735 /* FIXME bugzilla.gnome.org 45064: implement cancelling metadata when we
4736 implement invalidating metadata */
4738 nautilus_directory_async_state_changed (directory
);
4742 nautilus_directory_add_file_to_work_queue (NautilusDirectory
*directory
,
4745 g_return_if_fail (file
->details
->directory
== directory
);
4747 nautilus_file_queue_enqueue (directory
->details
->high_priority_queue
,
4753 add_all_files_to_work_queue (NautilusDirectory
*directory
)
4758 for (node
= directory
->details
->file_list
; node
!= NULL
; node
= node
->next
) {
4759 file
= NAUTILUS_FILE (node
->data
);
4761 nautilus_directory_add_file_to_work_queue (directory
, file
);
4766 nautilus_directory_remove_file_from_work_queue (NautilusDirectory
*directory
,
4769 nautilus_file_queue_remove (directory
->details
->high_priority_queue
,
4771 nautilus_file_queue_remove (directory
->details
->low_priority_queue
,
4773 nautilus_file_queue_remove (directory
->details
->extension_queue
,
4779 move_file_to_low_priority_queue (NautilusDirectory
*directory
,
4782 /* Must add before removing to avoid ref underflow */
4783 nautilus_file_queue_enqueue (directory
->details
->low_priority_queue
,
4785 nautilus_file_queue_remove (directory
->details
->high_priority_queue
,
4790 move_file_to_extension_queue (NautilusDirectory
*directory
,
4793 /* Must add before removing to avoid ref underflow */
4794 nautilus_file_queue_enqueue (directory
->details
->extension_queue
,
4796 nautilus_file_queue_remove (directory
->details
->low_priority_queue
,