Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
DISCONTINUED:openSUSE:11.2:Update
nautilus
nautilus-sysadmin-desktop-items.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File nautilus-sysadmin-desktop-items.diff of Package nautilus
Support desktop items defined by the sysadmin This adds a GConf key /apps/nautilus/desktop/predefined_items_dir which points to a directory which holds .desktop files. These files will be shown in the user's desktop. Git repository at http://gitorious.org/projects/nautilus/repos/mainline - branch sysadmin-desktop-items diff --git a/libnautilus-private/apps_nautilus_preferences.schemas.in b/libnautilus-private/apps_nautilus_preferences.schemas.in index ca45081..c180132 100644 --- a/libnautilus-private/apps_nautilus_preferences.schemas.in +++ b/libnautilus-private/apps_nautilus_preferences.schemas.in @@ -1072,5 +1072,21 @@ most cases, this should be left alone. -->Sans 10</default> </locale> </schema> + <schema> + <key>/schemas/apps/nautilus/desktop/predefined_items_dir</key> + <applyto>/apps/nautilus/desktop/predefined_items_dir</applyto> + <owner>nautilus</owner> + <type>string</type> + <locale name="C"> + <short>Directory for storing predefined desktop items</short> + <long> + Desktop files (*.desktop) which appear in this directory + will be shown on the user's desktop. System administrators + can use this feature to define desktop shortcuts which + appear for users. + </long> + </locale> + </schema> + </schemalist> </gconfschemafile> diff --git a/libnautilus-private/nautilus-debug-log.c b/libnautilus-private/nautilus-debug-log.c index f4ce320..ad84b4b 100644 --- a/libnautilus-private/nautilus-debug-log.c +++ b/libnautilus-private/nautilus-debug-log.c @@ -222,6 +222,14 @@ nautilus_debug_log_with_uri_list (gboolean is_milestone, const char *domain, con const char *format, ...) { va_list args; + GList node; + + if (!uris) { + node.data = "[no files]"; + node.prev = NULL; + node.next = NULL; + uris = &node; + } va_start (args, format); nautilus_debug_logv (is_milestone, domain, uris, format, args); @@ -235,6 +243,7 @@ nautilus_debug_log_with_file_list (gboolean is_milestone, const char *domain, GL va_list args; GList *uris; GList *l; + GList node; uris = NULL; @@ -260,11 +269,20 @@ nautilus_debug_log_with_file_list (gboolean is_milestone, const char *domain, GL uris = g_list_reverse (uris); + if (!uris) { + node.data = "[no files]"; + node.prev = NULL; + node.next = NULL; + uris = &node; + } + va_start (args, format); nautilus_debug_logv (is_milestone, domain, uris, format, args); va_end (args); - eel_g_list_free_deep (uris); + if (uris != &node) { + eel_g_list_free_deep (uris); + } } gboolean diff --git a/libnautilus-private/nautilus-debug-log.h b/libnautilus-private/nautilus-debug-log.h index ad0152e..2976a1f 100644 --- a/libnautilus-private/nautilus-debug-log.h +++ b/libnautilus-private/nautilus-debug-log.h @@ -27,10 +27,13 @@ #include <glib.h> -#define NAUTILUS_DEBUG_LOG_DOMAIN_USER "USER" /* always enabled */ -#define NAUTILUS_DEBUG_LOG_DOMAIN_ASYNC "async" /* when asynchronous notifications come in */ -#define NAUTILUS_DEBUG_LOG_DOMAIN_GLOG "GLog" /* used for GLog messages; don't use it yourself */ -#define NAUTILUS_DEBUG_LOG_DOMAIN_LOCKDOWN "lockdown" /* when things get *not* done due to lockdown */ +#define NAUTILUS_DEBUG_LOG_DOMAIN_USER "USER" /* always enabled */ +#define NAUTILUS_DEBUG_LOG_DOMAIN_ASYNC "async" /* when asynchronous notifications come in */ +#define NAUTILUS_DEBUG_LOG_DOMAIN_GLOG "GLog" /* used for GLog messages; don't use it yourself */ +#define NAUTILUS_DEBUG_LOG_DOMAIN_LOCKDOWN "lockdown" /* when things get *not* done due to lockdown */ +#define NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS "desktop-items" /* used for predefined desktop items (this is useful for sysadmins) */ +#define NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS "debug-desktop-items" /* debugging the machinery for predefined desktop items */ +#define NAUTILUS_DEBUG_LOG_DOMAIN_ICON_POSITIONS "icon-positions" /* debugging where icon positions get loaded/saved */ void nautilus_debug_log (gboolean is_milestone, const char *domain, const char *format, ...); diff --git a/libnautilus-private/nautilus-desktop-directory.c b/libnautilus-private/nautilus-desktop-directory.c index 0c5333e..f8970ef 100644 --- a/libnautilus-private/nautilus-desktop-directory.c +++ b/libnautilus-private/nautilus-desktop-directory.c @@ -24,34 +24,83 @@ Author: Alexander Larsson <alexl@redhat.com> */ +/* Note that we use two debug domains here: + * NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS - "desktop-items" + * NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS - "debug-desktop-items" + * + * The first one is logged as a milestone during initialization, and is actually useful to the sysadmin if he wants to + * debug his predefined desktop items: the log will contain info on which items are defined to be mandatory or not. + * + * The second one is internal to Nautilus, and is used for debugging purposes only (it traces the code flow among the + * interesting parts of this source file). + */ + #include <config.h> #include "nautilus-desktop-directory.h" +#include "nautilus-debug-log.h" #include "nautilus-directory-private.h" #include "nautilus-file.h" #include "nautilus-file-private.h" #include "nautilus-file-utilities.h" #include "nautilus-global-preferences.h" #include <eel/eel-glib-extensions.h> +#include <glib/gi18n.h> #include <gtk/gtk.h> +#include <libgnome/gnome-desktop-item.h> #include <libgnome/gnome-macros.h> struct NautilusDesktopDirectoryDetails { NautilusDirectory *real_directory; + NautilusDirectory *predefined_items_dir; GHashTable *callbacks; GHashTable *monitors; + + /* We store the "combined" files from the real_directory and the + * predefined_items_dir in the name_to_pairs_hash table. + * + * The hash table maps strings (file names) to FilePair structs. The + * strings live in the "name" field of those structs, to make memory + * management easier (i.e. the keys in the hash table need not to be + * memory-managed separately). + * + * We use the hash to answer the question, "do we already have a file + * with this name?", as the predefined items override the user's items + * (or vice-versa) based on matching filenames. + * + * The file_to_pairs_hash answers the question, "do we have a pair + * (which one?) for the specified file?". + * + * Within a FilePair in name_to_pairs_hash, both files are ref'ed. + * + * Within file_to_pairs_hash, the "key" file is *NOT* ref'ed, since it + * is already ref'ed by a corresponding FilePair. + */ + GHashTable *name_to_pairs_hash; + GHashTable *file_to_pairs_hash; + + eel_boolean_bit files_are_combined : 1; + eel_boolean_bit initializing : 1; + eel_boolean_bit real_directory_pending : 1; + eel_boolean_bit predefined_items_dir_pending : 1; }; +/* Structs of this type are stored in NautilusDesktopDirectory->name_to_pairs_hash */ +typedef struct { + char *name; + + NautilusFile *user_file; + NautilusFile *predefined_file; + + gboolean predefined_overrides_user; +} FilePair; + typedef struct { NautilusDesktopDirectory *desktop_dir; NautilusDirectoryCallback callback; gpointer callback_data; - NautilusFileAttributes wait_for_attributes; - gboolean wait_for_file_list; - GList *non_ready_directories; - GList *merged_file_list; } MergedCallback; @@ -64,24 +113,50 @@ typedef struct { } MergedMonitor; static void desktop_directory_changed_callback (gpointer data); +static GList *desktop_get_file_list (NautilusDirectory *directory); + +static gboolean directories_are_done_loading (NautilusDesktopDirectory *directory); +static void predefined_items_dir_changed_callback (gpointer data); + +static void forward_files_changed_cover (NautilusDirectory *directory, GList *files, gpointer callback_data); GNOME_CLASS_BOILERPLATE (NautilusDesktopDirectory, nautilus_desktop_directory, NautilusDirectory, NAUTILUS_TYPE_DIRECTORY) +static gboolean +pair_shows_file (FilePair *pair, NautilusFile *file) +{ + return ((file == pair->user_file && !pair->predefined_overrides_user) + || (file == pair->predefined_file && pair->predefined_overrides_user)); +} static gboolean desktop_contains_file (NautilusDirectory *directory, NautilusFile *file) { NautilusDesktopDirectory *desktop; + FilePair *pair; + gboolean result; + char *uri; desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); - if (nautilus_directory_contains_file (desktop->details->real_directory, file)) { - return TRUE; + pair = g_hash_table_lookup (desktop->details->file_to_pairs_hash, file); + + if (pair != NULL) { + result = pair_shows_file (pair, file); + } else { + result = file->details->directory == directory; /* this is just for desktop links from NautilusDesktopLinkMonitor */ } - return file->details->directory == directory; + uri = nautilus_file_get_uri (file); + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_contains_file (%s): %d", + uri, + result); + g_free (uri); + + return result; } static guint @@ -114,15 +189,72 @@ merged_callback_destroy (MergedCallback *merged_callback) g_assert (NAUTILUS_IS_DESKTOP_DIRECTORY (merged_callback->desktop_dir)); g_list_free (merged_callback->non_ready_directories); - nautilus_file_list_free (merged_callback->merged_file_list); g_free (merged_callback); } static void +add_file_from_pair_to_list_cb (gpointer key, gpointer value, gpointer data) +{ + FilePair *pair; + GList **list_ptr; + NautilusFile *file; + + pair = value; + list_ptr = data; + + file = pair->predefined_overrides_user ? pair->predefined_file : pair->user_file; + nautilus_file_ref (file); + + *list_ptr = g_list_prepend (*list_ptr, file); +} + +static GList * +get_combined_files (NautilusDesktopDirectory *desktop) +{ + GList *combined; + + combined = NULL; + g_hash_table_foreach (desktop->details->name_to_pairs_hash, add_file_from_pair_to_list_cb, &combined); + return combined; +} + +static GList * +get_desktop_links (NautilusDesktopDirectory *desktop, gboolean include_tentative_files) +{ + if (include_tentative_files) { + return nautilus_file_list_copy (NAUTILUS_DIRECTORY (desktop)->details->file_list); + } else { + /* This is because nautilus-directory.c:real_get_file_list() stripts out the tentative files */ + return GNOME_CALL_PARENT_WITH_DEFAULT (NAUTILUS_DIRECTORY_CLASS, get_file_list, (NAUTILUS_DIRECTORY (desktop)), NULL); + } +} + +static GList * +get_file_list (NautilusDesktopDirectory *desktop, gboolean include_tentative_files) +{ + GList *combined_file_list; + GList *file_list_from_desktop_links; + + combined_file_list = get_combined_files (desktop); + + file_list_from_desktop_links = get_desktop_links (desktop, include_tentative_files); + + combined_file_list = g_list_concat (combined_file_list, file_list_from_desktop_links); + + return combined_file_list; + +} + +static void merged_callback_check_done (MergedCallback *merged_callback) { + NautilusDesktopDirectory *desktop; + GList *files; + + desktop = merged_callback->desktop_dir; + /* Check if we are ready. */ - if (merged_callback->non_ready_directories != NULL) { + if (merged_callback->non_ready_directories != NULL || !desktop->details->files_are_combined) { return; } @@ -130,10 +262,18 @@ merged_callback_check_done (MergedCallback *merged_callback) g_hash_table_steal (merged_callback->desktop_dir->details->callbacks, merged_callback); /* We are ready, so do the real callback. */ - (* merged_callback->callback) (NAUTILUS_DIRECTORY (merged_callback->desktop_dir), - merged_callback->merged_file_list, + + files = get_file_list (desktop, TRUE); + + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, files, + "merged_callback_check_done: we are done; calling callback with files"); + + (* merged_callback->callback) (NAUTILUS_DIRECTORY (desktop), + files, merged_callback->callback_data); + nautilus_file_list_free (files); + /* And we are done. */ merged_callback_destroy (merged_callback); } @@ -144,7 +284,330 @@ merged_callback_remove_directory (MergedCallback *merged_callback, { merged_callback->non_ready_directories = g_list_remove (merged_callback->non_ready_directories, directory); - merged_callback_check_done (merged_callback); +} + +static FilePair * +create_file_pair (NautilusDesktopDirectory *desktop, NautilusFile *file, gboolean is_predefined, gboolean *is_new_pair) +{ + char *name; + FilePair *pair; + + /* Sanity check */ + + pair = g_hash_table_lookup (desktop->details->file_to_pairs_hash, file); + g_assert (pair == NULL); + + /* Create the pair or add to it */ + + name = nautilus_file_get_name (file); + + pair = g_hash_table_lookup (desktop->details->name_to_pairs_hash, name); + + nautilus_file_ref (file); + + if (pair == NULL) { + if (is_new_pair) { + *is_new_pair = TRUE; + } + + pair = g_slice_new (FilePair); + + pair->name = name; + pair->user_file = is_predefined ? NULL : file; + pair->predefined_file = is_predefined ? file : NULL; + + pair->predefined_overrides_user = FALSE; /* we don't know yet */ + + g_hash_table_insert (desktop->details->name_to_pairs_hash, name, pair); + } else { + if (is_new_pair) { + *is_new_pair = FALSE; + } + + g_free (name); + + if (is_predefined) { + g_assert (pair->predefined_file == NULL); + pair->predefined_file = file; + } else { + g_assert (pair->user_file == NULL); + pair->user_file = file; + } + } + + g_hash_table_insert (desktop->details->file_to_pairs_hash, file, pair); + + return pair; +} + +static void +log_pair (FilePair *pair, gboolean is_new_pair) +{ + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "%s pair %p: %s - predefined=%p user=%p predefined_overrides_user=%d", + is_new_pair ? "New" : "Existing", + pair, + pair->name, + pair->predefined_file, + pair->user_file, + pair->predefined_overrides_user); +} + +static void +create_file_pairs_for_directory (NautilusDesktopDirectory *desktop, NautilusDirectory *directory, gboolean is_predefined) +{ + GList *list; + GList *l; + + if (directory == NULL) { + return; + } + + list = nautilus_directory_get_file_list (directory); + + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, list, + "create_file_pairs_for_directory(): Creating pairs for files"); + + for (l = list; l; l = l->next) { + FilePair *pair; + gboolean is_new_pair; + + pair = create_file_pair (desktop, NAUTILUS_FILE (l->data), is_predefined, &is_new_pair); + log_pair (pair, is_new_pair); + } + + nautilus_file_list_free (list); +} + +static char * +get_file_contents (NautilusFile *file, gsize *length, GError **error) +{ + GFile *location; + char *path; + char *contents; + + location = nautilus_file_get_location (file); + path = g_file_get_path (location); + contents = NULL; + + if (path == NULL) { + char *uri; + + uri = g_file_get_uri (location); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Cannot read remote item: %s"), + uri); + g_free (uri); + + goto out; + } + + if (!g_file_get_contents (path, &contents, length, error)) { + contents = NULL; + } + +out: + return contents; +} + +static gboolean +predefined_desktop_item_is_mandatory (GnomeDesktopItem *item) +{ + /* If the desktop item does not have X-XDG-Is-Mandatory defined, then we + * assume it to be mandatory. This is so that the sysadmin can just + * copy existing .desktop files into the directory for predefined items, + * and assume that they will override anything the user tries to use. + */ + return (!gnome_desktop_item_attr_exists (item, "X-XDG-Is-Mandatory") + || gnome_desktop_item_get_boolean (item, "X-XDG-Is-Mandatory")); +} + +static gboolean +predefined_file_should_override_user_file (NautilusDesktopDirectory *desktop, NautilusFile *predefined, NautilusFile *user) +{ + gsize predefined_length; + char *predefined_contents; + char *predefined_uri; + char *user_uri; + GnomeDesktopItem *predefined_item; + GError *error; + gboolean should_override; + time_t predefined_mtime, user_mtime; + const char *reason; + + should_override = FALSE; + reason = "the predefined item is not mandatory"; + + predefined_uri = nautilus_file_get_uri (predefined); + user_uri = nautilus_file_get_uri (user); + predefined_item = NULL; + + /* Can we discard either file trivially? */ + + if (!nautilus_file_is_mime_type (predefined, "application/x-desktop")) { + reason = "predefined items which are not .desktop files always override user items"; + should_override = TRUE; + goto out; + } + + if (!nautilus_file_is_mime_type (user, "application/x-desktop")) { + reason = "predefined items always override user items that are not .desktop files"; + should_override = TRUE; + goto out; + } + + /* Read the predefined .desktop file */ + + /* FIXME: reading the file asynchronously is left as an exercise for the reader */ + + error = NULL; + predefined_contents = get_file_contents (predefined, &predefined_length, &error); + if (predefined_contents == NULL) { + /* can't determine contents trivially? let it override the user's stuff, anyway */ + nautilus_directory_emit_load_error (NAUTILUS_DIRECTORY (desktop), error); + nautilus_debug_log (desktop->details->initializing, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Error reading predefined item %s: %s", + predefined_uri, + error->message); + g_error_free (error); + + reason = "user items will not override predefined items that have with errors"; + should_override = TRUE; + goto out; + } + + predefined_item = gnome_desktop_item_new_from_string (predefined_uri, + predefined_contents, + predefined_length, + GNOME_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS, + &error); + + if (predefined_item == NULL) { + /* can't read desktop file? let it override the user's stuff, anyway */ + nautilus_directory_emit_load_error (NAUTILUS_DIRECTORY (desktop), error); + nautilus_debug_log (desktop->details->initializing, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Error parsing predefined item %s: %s", + predefined_uri, + error->message); + g_error_free (error); + + reason = "user items will not override predefined items that have with errors"; + should_override = TRUE; + goto out; + } + + /* Mandatory? */ + + if (predefined_desktop_item_is_mandatory (predefined_item)) { + reason = "the predefined item is mandatory (include \"X-XDG-Is-Mandatory=false\" to make it non-mandatory)"; + should_override = TRUE; + goto out; + } + + /* Not mandatory. But if the predefined item is newer than the user's, then it overrides the user's. */ + + predefined_mtime = nautilus_file_get_mtime (predefined); + user_mtime = nautilus_file_get_mtime (user); + + if (predefined_mtime > user_mtime) { + reason = "the predefined item is newer than the user item"; + should_override = TRUE; + goto out; + } + +out: + + if (predefined_item != NULL) { + gnome_desktop_item_unref (predefined_item); + } + + nautilus_debug_log (desktop->details->initializing, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Predefined item %s %s override user item %s because %s", + predefined_uri, + should_override ? "will" : "will not", + user_uri, + reason); + + g_free (predefined_uri); + g_free (user_uri); + + return should_override; +} + +static void +resolve_overrides_in_file_pair (NautilusDesktopDirectory *desktop, FilePair *pair) +{ + if (pair->user_file != NULL && pair->predefined_file != NULL) { + pair->predefined_overrides_user = predefined_file_should_override_user_file (desktop, pair->predefined_file, pair->user_file); + } else { + char *predefined_uri, *user_uri; + + pair->predefined_overrides_user = pair->predefined_file != NULL; + g_assert (pair->predefined_overrides_user || pair->user_file != NULL); + + predefined_uri = pair->predefined_file ? nautilus_file_get_uri (pair->predefined_file) : NULL; + user_uri = pair->user_file ? nautilus_file_get_uri (pair->user_file) : NULL; + + nautilus_debug_log (desktop->details->initializing, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "%s %s is used as it has no counterpart", + pair->predefined_overrides_user ? "Predefined item" : "User item", + predefined_uri ? predefined_uri : user_uri); + + g_free (predefined_uri); + g_free (user_uri); + } +} + +static void +find_overriden_files_cb (gpointer key, gpointer value, gpointer data) +{ + NautilusDesktopDirectory *desktop; + FilePair *pair; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (data); + pair = value; + + resolve_overrides_in_file_pair (desktop, pair); +} + +static void +combine_real_and_predefined_directories (NautilusDesktopDirectory *desktop) +{ + g_assert (directories_are_done_loading (desktop)); + + if (desktop->details->files_are_combined) { + return; + } + + desktop->details->files_are_combined = TRUE; + + /* 1. Create pairs for the files */ + + create_file_pairs_for_directory (desktop, desktop->details->real_directory, FALSE); + create_file_pairs_for_directory (desktop, desktop->details->predefined_items_dir, TRUE); + + /* 2. Figure out which files get overriden */ + + g_hash_table_foreach (desktop->details->name_to_pairs_hash, find_overriden_files_cb, desktop); + + desktop->details->initializing = FALSE; +} + +static const char * +get_debug_dirname (NautilusDesktopDirectory *desktop, NautilusDirectory *directory) +{ + if (directory == NAUTILUS_DIRECTORY (desktop)) { + return "desktop directory"; + } else if (directory == desktop->details->real_directory) { + return "real directory"; + } else if (directory == desktop->details->predefined_items_dir) { + return "predefined items directory"; + } else { + g_assert_not_reached (); + return NULL; + } } static void @@ -153,6 +616,8 @@ directory_ready_callback (NautilusDirectory *directory, gpointer callback_data) { MergedCallback *merged_callback; + NautilusDesktopDirectory *desktop; + const char *dirname; g_assert (NAUTILUS_IS_DIRECTORY (directory)); g_assert (callback_data != NULL); @@ -160,13 +625,13 @@ directory_ready_callback (NautilusDirectory *directory, merged_callback = callback_data; g_assert (g_list_find (merged_callback->non_ready_directories, directory) != NULL); - /* Update based on this call. */ - merged_callback->merged_file_list = g_list_concat - (merged_callback->merged_file_list, - nautilus_file_list_copy (files)); + desktop = merged_callback->desktop_dir; + + dirname = get_debug_dirname (desktop, directory); /* Check if we are ready. */ merged_callback_remove_directory (merged_callback, directory); + merged_callback_check_done (merged_callback); } static void @@ -179,6 +644,12 @@ desktop_call_when_ready (NautilusDirectory *directory, NautilusDesktopDirectory *desktop; MergedCallback search_key, *merged_callback; + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_call_when_ready (file_attributes=0x%x, wait_for_file_list=%d, callback=%p)", + (int) file_attributes, + (int) wait_for_file_list, + callback); + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); /* Check to be sure we aren't overwriting. */ @@ -194,36 +665,49 @@ desktop_call_when_ready (NautilusDirectory *directory, merged_callback->desktop_dir = desktop; merged_callback->callback = callback; merged_callback->callback_data = callback_data; - merged_callback->wait_for_attributes = file_attributes; - merged_callback->wait_for_file_list = wait_for_file_list; + + /* The three non-ready directories are ourselves, the real_directory and the predefined_items_dir */ + merged_callback->non_ready_directories = g_list_prepend (merged_callback->non_ready_directories, directory); merged_callback->non_ready_directories = g_list_prepend (merged_callback->non_ready_directories, desktop->details->real_directory); - - merged_callback->merged_file_list = g_list_concat (NULL, - nautilus_file_list_copy (directory->details->file_list)); + if (desktop->details->predefined_items_dir != NULL) { + merged_callback->non_ready_directories = g_list_prepend + (merged_callback->non_ready_directories, desktop->details->predefined_items_dir); + } /* Put it in the hash table. */ g_hash_table_insert (desktop->details->callbacks, merged_callback, merged_callback); - /* Now tell all the directories about it. */ + /* Now tell all the directories about it. We always pass TRUE for + * wait_for_file_list since *we* can't know which files to proxy until + * we have all the ones from the child directories. + */ nautilus_directory_call_when_ready (desktop->details->real_directory, - merged_callback->wait_for_attributes, - merged_callback->wait_for_file_list, + file_attributes, + TRUE, directory_ready_callback, merged_callback); + + if (desktop->details->predefined_items_dir != NULL) { + nautilus_directory_call_when_ready + (desktop->details->predefined_items_dir, + file_attributes, + TRUE, + directory_ready_callback, merged_callback); + } + nautilus_directory_call_when_ready_internal (directory, NULL, - merged_callback->wait_for_attributes, - merged_callback->wait_for_file_list, + file_attributes, + FALSE, /* ... but the desktop directory doesn't support wait_for_file_list = TRUE */ directory_ready_callback, NULL, merged_callback); - } static void @@ -235,6 +719,10 @@ desktop_cancel_callback (NautilusDirectory *directory, MergedCallback search_key, *merged_callback; GList *node; + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_cancel_callback (callback=%p)", + callback); + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); /* Find the entry in the table. */ @@ -267,15 +755,19 @@ merged_monitor_destroy (MergedMonitor *monitor) /* Call through to the real directory remove calls. */ nautilus_directory_file_monitor_remove (desktop->details->real_directory, monitor); + if (desktop->details->predefined_items_dir != NULL) { + nautilus_directory_file_monitor_remove (desktop->details->predefined_items_dir, monitor); + } + nautilus_directory_monitor_remove_internal (NAUTILUS_DIRECTORY (desktop), NULL, monitor); g_free (monitor); } static void -build_merged_callback_list (NautilusDirectory *directory, - GList *file_list, - gpointer callback_data) +build_file_list_cb (NautilusDirectory *directory, + GList *file_list, + gpointer callback_data) { GList **merged_list; @@ -285,6 +777,66 @@ build_merged_callback_list (NautilusDirectory *directory, } static void +add_file_monitor_and_emit_paired_files (NautilusDesktopDirectory *desktop, + NautilusDirectory *directory, + MergedMonitor *monitor, + gboolean monitor_hidden_files, + gboolean monitor_backup_files, + NautilusFileAttributes file_attributes, + NautilusDirectoryCallback callback, + gpointer callback_data) +{ + GList *unpaired_files; + GList *l; + GList *paired_files; + + if (directory == NULL) { + return; + } + + unpaired_files = NULL; + + nautilus_directory_file_monitor_add (directory, + monitor, + monitor_hidden_files, + monitor_backup_files, + file_attributes, + build_file_list_cb, &unpaired_files); + + /* For each of those files from the directory, pick the ones that are being used in one of our pairs */ + + paired_files = NULL; + + for (l = unpaired_files; l; l = l->next) { + NautilusFile *file; + FilePair *pair; + + file = NAUTILUS_FILE (l->data); + pair = g_hash_table_lookup (desktop->details->file_to_pairs_hash, file); + + if (pair == NULL) { + continue; /* maybe we haven't been notified yet about that file; we'll handle it later anyway */ + } + + if (pair_shows_file (pair, file)) { + paired_files = g_list_prepend (paired_files, file); + } + } + + if (callback != NULL) { + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, paired_files, + "add_file_monitor_and_emit_paired_files: calling callback %p on directory files", + callback); + + (* callback) (NAUTILUS_DIRECTORY (desktop), paired_files, callback_data); + } + + nautilus_file_list_free (unpaired_files); + g_list_free (paired_files); + +} + +static void desktop_monitor_add (NautilusDirectory *directory, gconstpointer client, gboolean monitor_hidden_files, @@ -295,7 +847,14 @@ desktop_monitor_add (NautilusDirectory *directory, { NautilusDesktopDirectory *desktop; MergedMonitor *monitor; - GList *merged_callback_list; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_monitor_add (client=%p, monitor_hidden_files=%d, monitor_backup_files=%d, file_attributes=0x%x, callback=%p)", + client, + (int) monitor_hidden_files, + (int) monitor_backup_files, + (int) file_attributes, + callback); desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); @@ -315,25 +874,40 @@ desktop_monitor_add (NautilusDirectory *directory, monitor->monitor_backup_files = monitor_backup_files; monitor->monitor_attributes = file_attributes; - /* Call through to the real directory add calls. */ - merged_callback_list = NULL; - - /* Call up to real dir */ - nautilus_directory_file_monitor_add - (desktop->details->real_directory, monitor, - monitor_hidden_files, monitor_backup_files, - file_attributes, - build_merged_callback_list, &merged_callback_list); - - /* Handle the desktop part */ - merged_callback_list = g_list_concat (merged_callback_list, - nautilus_file_list_copy (directory->details->file_list)); + /* Call through to the real directories' add calls. */ + + add_file_monitor_and_emit_paired_files (desktop, + desktop->details->real_directory, + monitor, + monitor_hidden_files, + monitor_backup_files, + file_attributes, + callback, + callback_data); + + add_file_monitor_and_emit_paired_files (desktop, + desktop->details->predefined_items_dir, + monitor, + monitor_hidden_files, + monitor_backup_files, + file_attributes, + callback, + callback_data); + + /* Call the callback on our desktop links */ - if (callback != NULL) { - (* callback) (directory, merged_callback_list, callback_data); + GList *desktop_link_files; + + desktop_link_files = get_desktop_links (desktop, TRUE); + + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, desktop_link_files, + "desktop_monitor_add: calling callback %p on desktop link files", + callback); + + (* callback) (NAUTILUS_DIRECTORY (desktop), desktop_link_files, callback_data); + nautilus_file_list_free (desktop_link_files); } - nautilus_file_list_free (merged_callback_list); } static void @@ -342,6 +916,10 @@ desktop_monitor_remove (NautilusDirectory *directory, { NautilusDesktopDirectory *desktop; MergedMonitor *monitor; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_monitor_remove (client=%p)", + client); desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); @@ -354,55 +932,143 @@ desktop_monitor_remove (NautilusDirectory *directory, } static void +free_file_pair (FilePair *pair) +{ + g_free (pair->name); + pair->name = NULL; + + nautilus_file_unref (pair->user_file); + nautilus_file_unref (pair->predefined_file); + + pair->user_file = NULL; + pair->predefined_file = NULL; + + g_slice_free (FilePair, pair); +} + +static void +free_file_pair_cb (gpointer key, gpointer value, gpointer data) +{ + FilePair *pair; + + pair = value; + g_assert ((char *) key == pair->name); + + free_file_pair (pair); +} + +static void +destroy_pair_hashes (NautilusDesktopDirectory *desktop) +{ + g_hash_table_foreach (desktop->details->name_to_pairs_hash, free_file_pair_cb, NULL); + g_hash_table_destroy (desktop->details->name_to_pairs_hash); + + g_hash_table_destroy (desktop->details->file_to_pairs_hash); /* its keys/values were already freed by the call above */ + + desktop->details->name_to_pairs_hash = NULL; + desktop->details->file_to_pairs_hash = NULL; +} + +static void +create_pair_hashes (NautilusDesktopDirectory *desktop) +{ + g_assert (desktop->details->name_to_pairs_hash == NULL); + g_assert (desktop->details->file_to_pairs_hash == NULL); + + desktop->details->name_to_pairs_hash = g_hash_table_new (g_str_hash, g_str_equal); + desktop->details->file_to_pairs_hash = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +static void +invalidate_combined_files (NautilusDesktopDirectory *desktop) +{ + destroy_pair_hashes (desktop); + create_pair_hashes (desktop); + + desktop->details->files_are_combined = FALSE; +} + +static void desktop_force_reload (NautilusDirectory *directory) { NautilusDesktopDirectory *desktop; + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_force_reload(): invalidating files"); + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + invalidate_combined_files (desktop); + + /* Set the pending flags before we start reloading any of the directories */ + + desktop->details->real_directory_pending = TRUE; + + if (desktop->details->predefined_items_dir != NULL) { + desktop->details->predefined_items_dir_pending = TRUE; + } + + /* Reload! */ + nautilus_directory_force_reload (desktop->details->real_directory); - /* We don't invalidate the files in desktop, since they are always - up to date. (And we don't ever want to mark them invalid.) */ + if (desktop->details->predefined_items_dir != NULL) { + nautilus_directory_force_reload (desktop->details->predefined_items_dir); + } + + /* We don't invalidate the "fake" files in desktop (for Home, Computer, + volumes, etc.), since they are always up to date. (And we don't ever + want to mark them invalid.) */ } static gboolean desktop_are_all_files_seen (NautilusDirectory *directory) { NautilusDesktopDirectory *desktop; + gboolean result; desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); - if (!nautilus_directory_are_all_files_seen (desktop->details->real_directory)) { - return FALSE; - } + result = desktop->details->files_are_combined; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_are_all_files_seen(): %d", + result); - return TRUE; + return result; } static gboolean desktop_is_not_empty (NautilusDirectory *directory) { NautilusDesktopDirectory *desktop; + gboolean result; desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); - if (nautilus_directory_is_not_empty (desktop->details->real_directory)) { - return TRUE; + if (g_hash_table_size (desktop->details->name_to_pairs_hash) != 0) { + result = TRUE; + } else { + result = directory->details->file_list != NULL; /* this is just for desktop links from NautilusDesktopLinkMonitor */ } - return directory->details->file_list != NULL; + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "desktop_is_not_empty(): %d", + result); + + return result; } static GList * desktop_get_file_list (NautilusDirectory *directory) { - GList *real_dir_file_list, *desktop_dir_file_list; - real_dir_file_list = nautilus_directory_get_file_list - (NAUTILUS_DESKTOP_DIRECTORY (directory)->details->real_directory); - desktop_dir_file_list = GNOME_CALL_PARENT_WITH_DEFAULT - (NAUTILUS_DIRECTORY_CLASS, get_file_list, (directory), NULL); - return g_list_concat (real_dir_file_list, desktop_dir_file_list); + GList *result; + + result = get_file_list (NAUTILUS_DESKTOP_DIRECTORY (directory), FALSE); + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, result, + "desktop_get_file_list(): returning list of files"); + + return result; } NautilusDirectory * @@ -412,7 +1078,6 @@ nautilus_desktop_directory_get_real_directory (NautilusDesktopDirectory *desktop return desktop->details->real_directory; } - static void desktop_finalize (GObject *object) { @@ -422,39 +1087,455 @@ desktop_finalize (GObject *object) nautilus_directory_unref (desktop->details->real_directory); + if (desktop->details->predefined_items_dir != NULL) { + nautilus_directory_unref (desktop->details->predefined_items_dir); + } + g_hash_table_destroy (desktop->details->callbacks); g_hash_table_destroy (desktop->details->monitors); + + destroy_pair_hashes (desktop); + g_free (desktop->details); eel_preferences_remove_callback (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR, desktop_directory_changed_callback, desktop); + eel_preferences_remove_callback (NAUTILUS_PREFERENCES_DESKTOP_PREDEFINED_ITEMS_DIR, + predefined_items_dir_changed_callback, + desktop); G_OBJECT_CLASS (parent_class)->finalize (object); } static void -done_loading_callback (NautilusDirectory *real_directory, - NautilusDesktopDirectory *desktop) +load_error_callback (NautilusDirectory *directory, GError *error, NautilusDesktopDirectory *desktop) +{ + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Error while loading %s: %s", + get_debug_dirname (desktop, directory), + error->message); + + nautilus_directory_emit_load_error (NAUTILUS_DIRECTORY (desktop), error); +} + +static gboolean +directories_are_done_loading (NautilusDesktopDirectory *desktop) { - nautilus_directory_emit_done_loading (NAUTILUS_DIRECTORY (desktop)); + gboolean real_is_done; + gboolean predefined_is_done; + + real_is_done = !desktop->details->real_directory_pending; + + predefined_is_done = (desktop->details->predefined_items_dir == NULL || !desktop->details->predefined_items_dir_pending); + + return real_is_done && predefined_is_done; } +static void +emit_pending_callback_cb (gpointer key, gpointer value, gpointer data) +{ + MergedCallback *merged_callback; + + merged_callback = key; + merged_callback_check_done (merged_callback); +} static void -forward_files_added_cover (NautilusDirectory *real_directory, +emit_pending_callbacks (NautilusDesktopDirectory *desktop) +{ + g_hash_table_foreach (desktop->details->callbacks, emit_pending_callback_cb, desktop); +} + +static void +done_loading_callback (NautilusDirectory *directory, + NautilusDesktopDirectory *desktop) +{ + if (directory == desktop->details->real_directory) { + desktop->details->real_directory_pending = FALSE; + } else if (directory == desktop->details->predefined_items_dir) { + desktop->details->predefined_items_dir_pending = FALSE; + } else { + g_assert_not_reached (); + } + + if (directories_are_done_loading (desktop)) { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "done_loading_callback(): %s and all directories are done; will combine files, emit callbacks, and emit done_loading", + get_debug_dirname (desktop, directory)); + + combine_real_and_predefined_directories (desktop); + emit_pending_callbacks (desktop); + nautilus_directory_emit_done_loading (NAUTILUS_DIRECTORY (desktop)); + } else { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "done_loading_callback(): %s is done loading, but not all dirs are ready yet", + get_debug_dirname (desktop, directory)); + } +} + +static void +forward_files_added_cover (NautilusDirectory *directory, GList *files, gpointer callback_data) { - nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (callback_data), files); + NautilusDesktopDirectory *desktop; + gboolean is_predefined_dir; + GList *l; + GList *files_removed; + GList *files_added; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (callback_data); + + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, files, + "forward_files_added_cover(): files got added to %s. files_are_combined=%d", + get_debug_dirname (desktop, directory), + desktop->details->files_are_combined); + + if (!desktop->details->files_are_combined) { + return; + } + + if (directory == desktop->details->real_directory) { + is_predefined_dir = FALSE; + } else if (directory == desktop->details->predefined_items_dir) { + is_predefined_dir = TRUE; + } else { + g_assert_not_reached (); + } + + files_removed = NULL; + files_added = NULL; + + for (l = files; l; l = l->next) { + NautilusFile *file; + FilePair *pair; + gboolean is_new_pair; + gboolean predefined_was_being_used; + char *uri; + + file = NAUTILUS_FILE (l->data); + + uri = nautilus_file_get_uri (file); + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "File added to %s: %s -- determining if it gets overriden", + is_predefined_dir ? "predefined items" : "user items", + uri); + + pair = g_hash_table_lookup (desktop->details->file_to_pairs_hash, file); + if (pair != NULL) { + GList node; + + /* Sometimes we get a files-added signal from one of the + * child directories, even though the file in question + * *has* already been emitted by a files-changed signal. + * In that case, we already know about the file and + * should not create a new pair for it. We'll handle + * that case as if the file had just been changed. + */ + + node.data = file; + node.prev = NULL; + node.next = NULL; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "Got 'added' for %s but we already knew about it; will consider it as a file that changed", + uri); + forward_files_changed_cover (directory, &node, desktop); + g_free (uri); + continue; + } + + pair = create_file_pair (desktop, NAUTILUS_FILE (l->data), is_predefined_dir, &is_new_pair); + log_pair (pair, is_new_pair); + predefined_was_being_used = pair->predefined_overrides_user; + + resolve_overrides_in_file_pair (desktop, pair); + + if (is_new_pair) { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "%s will appear in the user's desktop (it has no %s counterpart)", + uri, + is_predefined_dir ? "user" : "predefined"); + + files_added = g_list_prepend (files_added, file); + } else { + gboolean log_replacement; + + log_replacement = FALSE; + if (predefined_was_being_used) { + g_assert (!is_predefined_dir && file == pair->user_file); + + if (!pair->predefined_overrides_user) { + log_replacement = TRUE; + files_removed = g_list_prepend (files_removed, pair->predefined_file); + files_added = g_list_prepend (files_added, pair->user_file); + } + } else { + g_assert (is_predefined_dir && file == pair->predefined_file); + + if (pair->predefined_overrides_user) { + log_replacement = TRUE; + files_removed = g_list_prepend (files_removed, pair->user_file); + files_added = g_list_prepend (files_added, pair->predefined_file); + } + } + + if (log_replacement) { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "%s replaces what was in the user's desktop", + uri); + } + } + + g_free (uri); + } + + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, files_removed, + "forward_files_added_cover: emitting removed files"); + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, files_added, + "forward_files_added_cover: emitting added files"); + + nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (desktop), files_removed); + nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (desktop), files_added); + + g_list_free (files_removed); + g_list_free (files_added); } static void -forward_files_changed_cover (NautilusDirectory *real_directory, +forward_files_changed_cover (NautilusDirectory *directory, GList *files, gpointer callback_data) { - nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (callback_data), files); + NautilusDesktopDirectory *desktop; + gboolean is_predefined_dir; + GList *l; + GList *files_changed; + GList *files_added; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (callback_data); + + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, files, + "forward_files_changed_cover(): files got changed in %s. files_are_combined=%d", + get_debug_dirname (desktop, directory), + desktop->details->files_are_combined); + + if (!desktop->details->files_are_combined) { + return; + } + + if (directory == desktop->details->real_directory) { + is_predefined_dir = FALSE; + } else if (directory == desktop->details->predefined_items_dir) { + is_predefined_dir = TRUE; + } else { + g_assert_not_reached (); + } + + files_changed = NULL; + files_added = NULL; + + for (l = files; l; l = l->next) { + NautilusFile *file; + FilePair *pair; + char *uri; + + file = NAUTILUS_FILE (l->data); + uri = nautilus_file_get_uri (file); + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "File changed in %s: %s -- determining if it gets overriden", + is_predefined_dir ? "predefined items" : "user items", + uri); + + pair = g_hash_table_lookup (desktop->details->file_to_pairs_hash, file); + + if (pair == NULL) { + GList node; + + /* Huh, we didn't know about that file? Act as if it had been added. */ + + node.data = file; + node.prev = NULL; + node.next = NULL; + + if (nautilus_directory_contains_file (directory, file)) { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Trying to add %s as a new file", + uri); + forward_files_added_cover (directory, &node, callback_data); + } else { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Ignoring %s - it no longer exists in its directory", + uri); + } + } else { + gboolean predefined_was_being_used; + + predefined_was_being_used = pair->predefined_overrides_user; + + if (nautilus_directory_contains_file (directory, file)) { + char *name; + gboolean same_name; + + name = nautilus_file_get_name (file); + same_name = strcmp (name, pair->name) == 0; + g_free (name); + + if (same_name) { + /* The file still belongs within its pair */ + resolve_overrides_in_file_pair (desktop, pair); + + if (predefined_was_being_used == pair->predefined_overrides_user) { + if (pair_shows_file (pair, file)) { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "%s is still shown; will emit changed for it", + uri); + files_changed = g_list_prepend (files_changed, file); + } else { + /* Otherwise we weren't exposing the file anyway, so the caller + * doesn't need to know that it changed. + */ + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "%s changed but wasn't being shown anyway; will ignore it", + uri); + } + } else { + NautilusFile *changed; + NautilusFile *added; + char *added_uri; + + if (predefined_was_being_used) { + changed = pair->user_file; /* "got removed from our view" */ + added = pair->predefined_file; + } else { + changed = pair->predefined_file; /* as above */ + added = pair->user_file; + } + + added_uri = nautilus_file_get_uri (added); + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "%s is no longer shown; will emit it as changed and emit its pair %s as added", + uri, + added_uri); + g_free (added_uri); + + files_changed = g_list_prepend (files_changed, changed); + files_added = g_list_prepend (files_added, added); + } + } else { + GList node; + NautilusFile *remaining_file; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "%s changed name from %s; will emit changed for it, and call files_added to move it to a new pair", + uri, + pair->name); + + /* The file no longer belongs in this pair */ + + g_hash_table_remove (desktop->details->file_to_pairs_hash, file); + + if (file == pair->predefined_file) { + pair->predefined_file = NULL; + pair->predefined_overrides_user = FALSE; + remaining_file = pair->user_file; + } else { + g_assert (file == pair->user_file); + pair->user_file = NULL; + pair->predefined_overrides_user = TRUE; + remaining_file = pair->predefined_file; + } + + if (remaining_file == NULL) { + g_hash_table_remove (desktop->details->name_to_pairs_hash, pair->name); + free_file_pair (pair); + } else { + files_added = g_list_prepend (files_added, remaining_file); + } + + node.data = file; + node.prev = NULL; + node.next = NULL; + nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (desktop), &node); + + /* Re-insert the file in a new pair */ + + node.data = file; + node.prev = NULL; + node.next = NULL; + forward_files_added_cover (directory, &node, callback_data); + + nautilus_file_unref (file); /* as it was referenced in the old pair */ + } + } else { + NautilusFile *remaining_file; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, + "%s no longer exists in the %s directory; will emit changed for it", + uri, + get_debug_dirname (desktop, directory)); + + /* The file no longer exists in its directory + * (it got deleted or something), so we'll + * remove it from our pair. + */ + + files_changed = g_list_prepend (files_changed, file); + g_hash_table_remove (desktop->details->file_to_pairs_hash, file); + + if (file == pair->predefined_file) { + pair->predefined_file = NULL; + pair->predefined_overrides_user = FALSE; + remaining_file = pair->user_file; + } else { + g_assert (file == pair->user_file); + pair->user_file = NULL; + pair->predefined_overrides_user = TRUE; + remaining_file = pair->predefined_file; + } + + nautilus_file_unref (file); + + if (remaining_file == NULL) { + g_hash_table_remove (desktop->details->name_to_pairs_hash, pair->name); + free_file_pair (pair); + } + } + } + + g_free (uri); + } + + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, files_changed, + "forward_files_changed_cover: emitting changed files"); + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, files_added, + "forward_files_changed_cover: emitting added files"); + + nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (desktop), files_changed); + nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (desktop), files_added); + + g_list_free (files_changed); + g_list_free (files_added); +} + +static void +discard_directory (NautilusDesktopDirectory *desktop, NautilusDirectory *dir) +{ + if (dir == NULL) { + return; + } + + g_hash_table_foreach_remove (desktop->details->callbacks, (GHRFunc) gtk_true, NULL); + g_hash_table_foreach_remove (desktop->details->monitors, (GHRFunc) gtk_true, NULL); + + g_signal_handlers_disconnect_by_func (dir, done_loading_callback, desktop); + g_signal_handlers_disconnect_by_func (dir, forward_files_added_cover, desktop); + g_signal_handlers_disconnect_by_func (dir, forward_files_changed_cover, desktop); + + nautilus_directory_unref (dir); } static void @@ -464,17 +1545,10 @@ update_desktop_directory (NautilusDesktopDirectory *desktop) char *desktop_uri; NautilusDirectory *real_directory; - real_directory = desktop->details->real_directory; - if (real_directory != NULL) { - g_hash_table_foreach_remove (desktop->details->callbacks, (GHRFunc) gtk_true, NULL); - g_hash_table_foreach_remove (desktop->details->monitors, (GHRFunc) gtk_true, NULL); + invalidate_combined_files (desktop); - g_signal_handlers_disconnect_by_func (real_directory, done_loading_callback, desktop); - g_signal_handlers_disconnect_by_func (real_directory, forward_files_added_cover, desktop); - g_signal_handlers_disconnect_by_func (real_directory, forward_files_changed_cover, desktop); - - nautilus_directory_unref (real_directory); - } + discard_directory (desktop, desktop->details->real_directory); + desktop->details->real_directory = NULL; desktop_path = nautilus_get_desktop_directory (); desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL); @@ -482,6 +1556,8 @@ update_desktop_directory (NautilusDesktopDirectory *desktop) g_free (desktop_uri); g_free (desktop_path); + g_signal_connect_object (real_directory, "load_error", + G_CALLBACK (load_error_callback), desktop, 0); g_signal_connect_object (real_directory, "done_loading", G_CALLBACK (done_loading_callback), desktop, 0); g_signal_connect_object (real_directory, "files_added", @@ -490,6 +1566,7 @@ update_desktop_directory (NautilusDesktopDirectory *desktop) G_CALLBACK (forward_files_changed_cover), desktop, 0); desktop->details->real_directory = real_directory; + desktop->details->real_directory_pending = TRUE; } static void @@ -500,8 +1577,64 @@ desktop_directory_changed_callback (gpointer data) } static void +update_predefined_items_dir (NautilusDesktopDirectory *desktop) +{ + NautilusDirectory *predefined_items_dir; + char *dirname; + char *uri; + + invalidate_combined_files (desktop); + + discard_directory (desktop, desktop->details->predefined_items_dir); + desktop->details->predefined_items_dir = NULL; + + dirname = eel_preferences_get (NAUTILUS_PREFERENCES_DESKTOP_PREDEFINED_ITEMS_DIR); + if (dirname == NULL || *dirname == 0) { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "The predefined_items_dir key is not set; will not have predefined desktop items"); + g_free (dirname); + return; + } + + nautilus_debug_log (desktop->details->initializing, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Using predefined_items_dir = %s", dirname); + + uri = g_filename_to_uri (dirname, NULL, NULL); + predefined_items_dir = nautilus_directory_get_by_uri (uri); + g_free (uri); + g_free (dirname); + + g_signal_connect_object (predefined_items_dir, "load_error", + G_CALLBACK (load_error_callback), desktop, 0); + g_signal_connect_object (predefined_items_dir, "done_loading", + G_CALLBACK (done_loading_callback), desktop, 0); + g_signal_connect_object (predefined_items_dir, "files_added", + G_CALLBACK (forward_files_added_cover), desktop, 0); + g_signal_connect_object (predefined_items_dir, "files_changed", + G_CALLBACK (forward_files_changed_cover), desktop, 0); + + desktop->details->predefined_items_dir = predefined_items_dir; + desktop->details->predefined_items_dir_pending = TRUE; +} + +static void +predefined_items_dir_changed_callback (gpointer data) +{ + NautilusDesktopDirectory *desktop = NAUTILUS_DESKTOP_DIRECTORY (data); + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "GConf key for the path for predefined desktop items changed; refreshing..."); + + update_predefined_items_dir (desktop); + nautilus_directory_force_reload (NAUTILUS_DIRECTORY (desktop)); +} + +static void nautilus_desktop_directory_instance_init (NautilusDesktopDirectory *desktop) { + nautilus_debug_log (TRUE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Creating the NautilusDesktopDirectory"); + desktop->details = g_new0 (NautilusDesktopDirectoryDetails, 1); desktop->details->callbacks = g_hash_table_new_full @@ -510,11 +1643,19 @@ nautilus_desktop_directory_instance_init (NautilusDesktopDirectory *desktop) desktop->details->monitors = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)merged_monitor_destroy); + create_pair_hashes (desktop); + + desktop->details->initializing = TRUE; + update_desktop_directory (NAUTILUS_DESKTOP_DIRECTORY (desktop)); + update_predefined_items_dir (desktop); eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR, desktop_directory_changed_callback, desktop); + eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_PREDEFINED_ITEMS_DIR, + predefined_items_dir_changed_callback, + desktop); } static void diff --git a/libnautilus-private/nautilus-desktop-icon-file.c b/libnautilus-private/nautilus-desktop-icon-file.c index 3802dd9..120df10 100644 --- a/libnautilus-private/nautilus-desktop-icon-file.c +++ b/libnautilus-private/nautilus-desktop-icon-file.c @@ -26,6 +26,7 @@ #include <config.h> #include "nautilus-desktop-icon-file.h" +#include "nautilus-debug-log.h" #include "nautilus-directory-notify.h" #include "nautilus-directory-private.h" #include "nautilus-file-attributes.h" @@ -291,6 +292,9 @@ nautilus_desktop_icon_file_new (NautilusDesktopLink *link) list.prev = NULL; nautilus_directory_emit_files_added (directory, &list); + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DEBUG_DESKTOP_ITEMS, &list, + "Created desktop icon file and notified directory:"); + return icon_file; } diff --git a/libnautilus-private/nautilus-desktop-link-monitor.c b/libnautilus-private/nautilus-desktop-link-monitor.c index 9abdd64..976ccd8 100644 --- a/libnautilus-private/nautilus-desktop-link-monitor.c +++ b/libnautilus-private/nautilus-desktop-link-monitor.c @@ -23,6 +23,7 @@ */ #include <config.h> +#include "nautilus-debug-log.h" #include "nautilus-desktop-link-monitor.h" #include "nautilus-desktop-link.h" #include "nautilus-desktop-icon-file.h" @@ -356,6 +357,9 @@ nautilus_desktop_link_monitor_init (gpointer object, gpointer klass) GList *l, *mounts; GMount *mount; + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Initializing desktop link monitor with all its links"); + monitor = NAUTILUS_DESKTOP_LINK_MONITOR (object); the_link_monitor = monitor; diff --git a/libnautilus-private/nautilus-directory-async.c b/libnautilus-private/nautilus-directory-async.c index cbe0419..ba67a75 100644 --- a/libnautilus-private/nautilus-directory-async.c +++ b/libnautilus-private/nautilus-directory-async.c @@ -24,6 +24,7 @@ #include <config.h> +#include "nautilus-debug-log.h" #include "nautilus-directory-metafile.h" #include "nautilus-directory-notify.h" #include "nautilus-directory-private.h" @@ -1039,6 +1040,15 @@ directory_load_done (NautilusDirectory *directory, GError *error) { GList *node; + char *uri; + + uri = nautilus_directory_get_uri (directory); + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_ASYNC, + "Directory %p (%s): directory_load_done: %s", + directory, + uri, + error ? error->message : "success"); + g_free (uri); directory->details->directory_loaded = TRUE; directory->details->directory_loaded_sent_notification = FALSE; diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c index 9e6e435..b5d75e1 100644 --- a/libnautilus-private/nautilus-directory.c +++ b/libnautilus-private/nautilus-directory.c @@ -25,6 +25,7 @@ #include <config.h> #include "nautilus-directory-private.h" +#include "nautilus-debug-log.h" #include "nautilus-directory-metafile.h" #include "nautilus-directory-notify.h" #include "nautilus-file-attributes.h" @@ -1593,6 +1594,8 @@ nautilus_directory_schedule_position_set (GList *position_setting_list) char str[64]; for (p = position_setting_list; p != NULL; p = p->next) { + GList node; + item = (NautilusFileChangesQueuePosition *) p->data; file = nautilus_file_get (item->location); @@ -1608,6 +1611,12 @@ nautilus_directory_schedule_position_set (GList *position_setting_list) NULL, str); + node.data = file; + node.prev = NULL; + node.next = NULL; + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_ICON_POSITIONS, &node, + "Directory - saving icon position to \"%s\"", str); + if (item->set) { g_snprintf (str, sizeof (str), "%d", item->screen); } else { diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h index e3de760..d414bed 100644 --- a/libnautilus-private/nautilus-global-preferences.h +++ b/libnautilus-private/nautilus-global-preferences.h @@ -214,6 +214,7 @@ typedef enum #define NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE "desktop/volumes_visible" #define NAUTILUS_PREFERENCES_DESKTOP_NETWORK_VISIBLE "desktop/network_icon_visible" #define NAUTILUS_PREFERENCES_DESKTOP_NETWORK_NAME "desktop/network_icon_name" +#define NAUTILUS_PREFERENCES_DESKTOP_PREDEFINED_ITEMS_DIR "desktop/predefined_items_dir" void nautilus_global_preferences_init (void); char *nautilus_global_preferences_get_default_folder_viewer_preference_as_iid (void); diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index 78d5044..5eafc70 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -8264,14 +8264,11 @@ load_directory (FMDirectoryView *view, view->details->reported_load_error = FALSE; - /* FIXME bugzilla.gnome.org 45062: In theory, we also need to monitor metadata here (as - * well as doing a call when ready), in case external forces - * change the directory's file metadata. - */ attributes = NAUTILUS_FILE_ATTRIBUTE_INFO | NAUTILUS_FILE_ATTRIBUTE_MOUNT | - NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO; + NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO | + NAUTILUS_FILE_ATTRIBUTE_METADATA; view->details->metadata_for_directory_as_file_pending = TRUE; view->details->metadata_for_files_in_directory_pending = TRUE; nautilus_file_call_when_ready diff --git a/src/file-manager/fm-icon-view.c b/src/file-manager/fm-icon-view.c index a5186d6..827ad5e 100644 --- a/src/file-manager/fm-icon-view.c +++ b/src/file-manager/fm-icon-view.c @@ -42,6 +42,7 @@ #include <gtk/gtk.h> #include <glib/gi18n.h> #include <gio/gio.h> +#include <libnautilus-private/nautilus-debug-log.h> #include <libnautilus-private/nautilus-directory-background.h> #include <libnautilus-private/nautilus-directory.h> #include <libnautilus-private/nautilus-dnd.h> @@ -236,6 +237,7 @@ get_stored_icon_position_callback (NautilusIconContainer *container, char *position_string, *scale_string; gboolean position_good; char c; + GList node; g_assert (NAUTILUS_IS_ICON_CONTAINER (container)); g_assert (NAUTILUS_IS_FILE (file)); @@ -252,6 +254,13 @@ get_stored_icon_position_callback (NautilusIconContainer *container, position_good = sscanf (position_string, " %d , %d %c", &position->x, &position->y, &c) == 2; + + node.data = file; + node.prev = NULL; + node.next = NULL; + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_ICON_POSITIONS, &node, + "get_stored_icon_position_callback(): read icon position as \"%s\"", position_string); + g_free (position_string); /* If it is the desktop directory, maybe the gnome-libs metadata has information about it */ @@ -2274,11 +2283,20 @@ icon_position_changed_callback (NautilusIconContainer *container, /* Store the new position of the icon in the metadata. */ if (!fm_icon_view_using_auto_layout (icon_view)) { + GList node; + position_string = g_strdup_printf ("%d,%d", position->x, position->y); nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_ICON_POSITION, NULL, position_string); + + node.data = file; + node.prev = NULL; + node.next = NULL; + nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_ICON_POSITIONS, &node, + "icon_position_changed_callback() - saving icon position to \"%s\"", position_string); + g_free (position_string); } diff --git a/src/nautilus-desktop-window.c b/src/nautilus-desktop-window.c index 6871bde..ea0fc61 100644 --- a/src/nautilus-desktop-window.c +++ b/src/nautilus-desktop-window.c @@ -33,6 +33,7 @@ #include <eel/eel-gtk-macros.h> #include <eel/eel-vfs-extensions.h> #include <libgnome/gnome-macros.h> +#include <libnautilus-private/nautilus-debug-log.h> #include <libnautilus-private/nautilus-file-utilities.h> #include <libnautilus-private/nautilus-icon-names.h> #include <gio/gio.h> @@ -118,6 +119,9 @@ nautilus_desktop_window_new (NautilusApplication *application, width_request = gdk_screen_get_width (screen); height_request = gdk_screen_get_height (screen); + nautilus_debug_log (TRUE, NAUTILUS_DEBUG_LOG_DOMAIN_DESKTOP_ITEMS, + "Initializing desktop window with size %dx%d", width_request, height_request); + window = NAUTILUS_DESKTOP_WINDOW (gtk_widget_new (nautilus_desktop_window_get_type(), "app", application,
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor