nautilus/nautilus-sysadmin-desktop-items.diff

1793 lines
58 KiB
Diff
Raw Normal View History

Sysadmin-defined desktop items for Nautilus
http://www.gnome.org/~federico/news-2008-08.html#nautilus-predefined-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..7ed1af1 100644
--- a/libnautilus-private/nautilus-debug-log.h
+++ b/libnautilus-private/nautilus-debug-log.h
@@ -27,10 +27,12 @@
#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 */
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..b08abef 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,48 @@ 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);
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 +187,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 +260,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 (NAUTILUS_DIRECTORY (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 +282,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 +614,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 +623,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 +642,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 +663,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 +717,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 +753,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 +775,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 +845,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 +872,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 +914,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 +930,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 +1076,6 @@ nautilus_desktop_directory_get_real_directory (NautilusDesktopDirectory *desktop
return desktop->details->real_directory;
}
-
static void
desktop_finalize (GObject *object)
{
@@ -422,39 +1085,431 @@ 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 = 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 +1519,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 +1530,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 +1540,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 +1551,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 +1617,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-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/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,