summaryrefslogtreecommitdiff
path: root/nautilus-desktop
diff options
context:
space:
mode:
authorCarlos Soriano <csoriano@gnome.org>2016-04-15 10:35:34 +0200
committerCarlos Soriano <csoriano@gnome.org>2016-04-15 16:04:34 +0200
commitc9dcccae611e40f48024bdfeccbb081fa10b7b15 (patch)
treee1e51188b0d3973b341a111a40e5802ec70adfae /nautilus-desktop
parent035cd2db2d10c0194b74eb87ce337a775f7e49bb (diff)
downloadnautilus-c9dcccae611e40f48024bdfeccbb081fa10b7b15.tar.gz
desktop: move to a different folder
For a better structured hierarchy.
Diffstat (limited to 'nautilus-desktop')
-rw-r--r--nautilus-desktop/Makefile.am67
-rw-r--r--nautilus-desktop/main-desktop.c36
-rw-r--r--nautilus-desktop/nautilus-desktop-application.c243
-rw-r--r--nautilus-desktop/nautilus-desktop-application.h36
-rw-r--r--nautilus-desktop/nautilus-desktop-canvas-view-container.c199
-rw-r--r--nautilus-desktop/nautilus-desktop-canvas-view-container.h35
-rw-r--r--nautilus-desktop/nautilus-desktop-canvas-view.c744
-rw-r--r--nautilus-desktop/nautilus-desktop-canvas-view.h54
-rw-r--r--nautilus-desktop/nautilus-desktop-directory-file.c557
-rw-r--r--nautilus-desktop/nautilus-desktop-directory-file.h53
-rw-r--r--nautilus-desktop/nautilus-desktop-directory.c571
-rw-r--r--nautilus-desktop/nautilus-desktop-directory.h58
-rw-r--r--nautilus-desktop/nautilus-desktop-icon-file.c520
-rw-r--r--nautilus-desktop/nautilus-desktop-icon-file.h60
-rw-r--r--nautilus-desktop/nautilus-desktop-link-monitor.c432
-rw-r--r--nautilus-desktop/nautilus-desktop-link-monitor.h60
-rw-r--r--nautilus-desktop/nautilus-desktop-link.c436
-rw-r--r--nautilus-desktop/nautilus-desktop-link.h77
-rw-r--r--nautilus-desktop/nautilus-desktop-metadata.c90
-rw-r--r--nautilus-desktop/nautilus-desktop-metadata.h43
-rw-r--r--nautilus-desktop/nautilus-desktop-window-slot.c67
-rw-r--r--nautilus-desktop/nautilus-desktop-window-slot.h36
-rw-r--r--nautilus-desktop/nautilus-desktop-window.c416
-rw-r--r--nautilus-desktop/nautilus-desktop-window.h59
24 files changed, 4949 insertions, 0 deletions
diff --git a/nautilus-desktop/Makefile.am b/nautilus-desktop/Makefile.am
new file mode 100644
index 000000000..0471106c8
--- /dev/null
+++ b/nautilus-desktop/Makefile.am
@@ -0,0 +1,67 @@
+include $(top_srcdir)/Makefile.shared
+
+bin_PROGRAMS= \
+ nautilus-desktop \
+ $(NULL)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libnautilus-private \
+ -I$(top_builddir)/libnautilus-private \
+ -I$(top_srcdir)/libgd \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ $(BASE_CFLAGS) \
+ $(COMMON_CFLAGS) \
+ $(NAUTILUS_CFLAGS) \
+ $(WARNING_CFLAGS) \
+ $(EXIF_CFLAGS) \
+ $(EXEMPI_CFLAGS) \
+ -DDATADIR=\""$(datadir)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DNAUTILUS_DATADIR=\""$(datadir)/nautilus"\" \
+ -DPREFIX=\""$(prefix)"\" \
+ -DVERSION="\"$(VERSION)\"" \
+ $(DISABLE_DEPRECATED) \
+ $(NULL)
+
+LDADD =\
+ $(top_builddir)/libnautilus-private/libnautilus-private.la \
+ $(top_builddir)/libgd/libgd.la \
+ $(top_builddir)/src/libnautilus.la \
+ $(BASE_LIBS) \
+ $(COMMON_LIBS) \
+ $(NAUTILUS_LIBS) \
+ $(CORE_LIBS) \
+ $(EXIF_LIBS) \
+ $(EXEMPI_LIBS) \
+ $(POPT_LIBS) \
+ $(NULL)
+
+nautilus_desktop_SOURCES= \
+ main-desktop.c \
+ nautilus-desktop-application.c \
+ nautilus-desktop-application.h \
+ nautilus-desktop-canvas-view.c \
+ nautilus-desktop-canvas-view.h \
+ nautilus-desktop-canvas-view-container.c \
+ nautilus-desktop-canvas-view-container.h \
+ nautilus-desktop-directory.c \
+ nautilus-desktop-directory.h \
+ nautilus-desktop-directory-file.c \
+ nautilus-desktop-directory-file.h \
+ nautilus-desktop-icon-file.c \
+ nautilus-desktop-icon-file.h \
+ nautilus-desktop-link.c \
+ nautilus-desktop-link.h \
+ nautilus-desktop-link-monitor.c \
+ nautilus-desktop-link-monitor.h \
+ nautilus-desktop-metadata.c \
+ nautilus-desktop-metadata.h \
+ nautilus-desktop-window.c \
+ nautilus-desktop-window.h \
+ nautilus-desktop-window-slot.c \
+ nautilus-desktop-window-slot.h \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/nautilus-desktop/main-desktop.c b/nautilus-desktop/main-desktop.c
new file mode 100644
index 000000000..7c488a8b4
--- /dev/null
+++ b/nautilus-desktop/main-desktop.c
@@ -0,0 +1,36 @@
+#include <config.h>
+
+#include "nautilus-desktop-application.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+main (int argc, char *argv[])
+{
+ NautilusDesktopApplication *application;
+ int retval;
+
+ /* Initialize gettext support */
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ g_set_prgname ("nautilus-desktop");
+
+ application = nautilus_desktop_application_new ();
+
+ retval = g_application_run (G_APPLICATION (application),
+ argc, argv);
+
+ g_object_unref (application);
+
+ return retval;
+}
diff --git a/nautilus-desktop/nautilus-desktop-application.c b/nautilus-desktop/nautilus-desktop-application.c
new file mode 100644
index 000000000..31ff6e603
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-application.c
@@ -0,0 +1,243 @@
+/* nautilus-desktop-application.c
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano@gnome.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "nautilus-desktop-application.h"
+#include "nautilus-desktop-window.h"
+#include "nautilus-desktop-directory.h"
+#include "nautilus-file-utilities.h"
+
+#include "nautilus-freedesktop-generated.h"
+
+#include <libnautilus-private/nautilus-global-preferences.h>
+#include <eel/eel.h>
+#include <gdk/gdkx.h>
+
+static NautilusFreedesktopFileManager1 *freedesktop_proxy = NULL;
+
+struct _NautilusDesktopApplication
+{
+ NautilusApplication parent_instance;
+
+ GCancellable *freedesktop_cancellable;
+};
+
+G_DEFINE_TYPE (NautilusDesktopApplication, nautilus_desktop_application, NAUTILUS_TYPE_APPLICATION)
+
+static void
+on_show_folders (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ nautilus_freedesktop_file_manager1_call_show_items_finish (freedesktop_proxy,
+ res,
+ &error);
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ g_warning ("Unable to show items with File Manager freedesktop proxy: %s", error->message);
+ }
+
+ g_clear_error (&error);
+}
+
+static void
+open_location_on_dbus (NautilusDesktopApplication *self,
+ const gchar *uri)
+{
+ const gchar *uris[] = { uri, NULL };
+
+ nautilus_freedesktop_file_manager1_call_show_folders (freedesktop_proxy,
+ uris,
+ "",
+ self->freedesktop_cancellable,
+ on_show_folders,
+ self);
+}
+
+static void
+open_location_full (NautilusApplication *app,
+ GFile *location,
+ NautilusWindowOpenFlags flags,
+ GList *selection,
+ NautilusWindow *target_window,
+ NautilusWindowSlot *target_slot)
+{
+ NautilusDesktopApplication *self = NAUTILUS_DESKTOP_APPLICATION (app);
+ gchar *uri;
+
+ uri = g_file_get_uri (location);
+ if (eel_uri_is_desktop (uri) && target_window &&
+ NAUTILUS_IS_DESKTOP_WINDOW (target_window))
+ {
+ nautilus_window_open_location_full (target_window, location, flags, selection, NULL);
+ }
+ else
+ {
+ if (freedesktop_proxy)
+ {
+ open_location_on_dbus (self, uri);
+ }
+ else
+ {
+ g_warning ("cannot open folder on desktop, freedesktop bus not ready\n");
+ }
+ }
+
+ g_free (uri);
+}
+
+static void
+nautilus_application_set_desktop_visible (NautilusDesktopApplication *self,
+ gboolean visible)
+{
+ GtkWidget *desktop_window;
+
+ if (visible)
+ {
+ nautilus_desktop_window_ensure ();
+ }
+ else
+ {
+ desktop_window = nautilus_desktop_window_get ();
+ if (desktop_window != NULL)
+ {
+ gtk_widget_destroy (desktop_window);
+ }
+ }
+}
+
+static void
+update_desktop_from_gsettings (NautilusDesktopApplication *self)
+{
+ GdkDisplay *display;
+ gboolean visible;
+
+#ifdef GDK_WINDOWING_X11
+ display = gdk_display_get_default ();
+ visible = g_settings_get_boolean (gnome_background_preferences,
+ NAUTILUS_PREFERENCES_SHOW_DESKTOP);
+ if (!GDK_IS_X11_DISPLAY (display))
+ {
+ if (visible)
+ {
+ g_warning ("Desktop icons only supported on X11. Desktop not created");
+ }
+
+ return;
+ }
+
+ nautilus_application_set_desktop_visible (self, visible);
+
+ return;
+#endif
+
+ g_warning ("Desktop icons only supported on X11. Desktop not created");
+}
+
+static void
+init_desktop (NautilusDesktopApplication *self)
+{
+ g_signal_connect_swapped (gnome_background_preferences, "changed::" NAUTILUS_PREFERENCES_SHOW_DESKTOP,
+ G_CALLBACK (update_desktop_from_gsettings),
+ self);
+ update_desktop_from_gsettings (self);
+}
+
+static void
+nautilus_desktop_application_activate (GApplication *app)
+{
+ /* Do nothing */
+}
+
+static void
+nautilus_desktop_application_startup (GApplication *app)
+{
+ NautilusDesktopApplication *self = NAUTILUS_DESKTOP_APPLICATION (app);
+ GError *error = NULL;
+
+ nautilus_application_startup_common (NAUTILUS_APPLICATION (app));
+ self->freedesktop_cancellable = g_cancellable_new ();
+ freedesktop_proxy = nautilus_freedesktop_file_manager1_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.freedesktop.FileManager1",
+ "/org/freedesktop/FileManager1",
+ self->freedesktop_cancellable,
+ &error);
+
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ g_warning ("Unable to create File Manager freedesktop proxy: %s", error->message);
+ }
+
+ g_clear_error (&error);
+
+ init_desktop (self);
+}
+
+static void
+nautilus_desktop_application_dispose (GObject *object)
+{
+ NautilusDesktopApplication *self = NAUTILUS_DESKTOP_APPLICATION (object);
+
+ g_clear_object (&self->freedesktop_cancellable);
+
+
+ G_OBJECT_CLASS (nautilus_desktop_application_parent_class)->dispose (object);
+}
+
+static void
+nautilus_desktop_application_class_init (NautilusDesktopApplicationClass *klass)
+{
+ GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ NautilusApplicationClass *parent_class = NAUTILUS_APPLICATION_CLASS (klass);
+
+ parent_class->open_location_full = open_location_full;
+
+ application_class->startup = nautilus_desktop_application_startup;
+ application_class->activate = nautilus_desktop_application_activate;
+
+ gobject_class->dispose = nautilus_desktop_application_dispose;
+}
+
+static void
+nautilus_desktop_ensure_builtins (void)
+{
+ /* Ensure the type so it can be registered early as a directory extension provider*/
+ g_type_ensure (NAUTILUS_TYPE_DESKTOP_DIRECTORY);
+}
+
+static void
+nautilus_desktop_application_init (NautilusDesktopApplication *self)
+{
+ nautilus_ensure_extension_points ();
+ nautilus_ensure_extension_builtins ();
+ nautilus_desktop_ensure_builtins ();
+}
+
+NautilusDesktopApplication *
+nautilus_desktop_application_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_DESKTOP_APPLICATION,
+ "application-id", "org.gnome.NautilusDesktop",
+ NULL);
+}
+
diff --git a/nautilus-desktop/nautilus-desktop-application.h b/nautilus-desktop/nautilus-desktop-application.h
new file mode 100644
index 000000000..4f4c62c47
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-application.h
@@ -0,0 +1,36 @@
+/* nautilus-desktop-application.h
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano@gnome.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NAUTILUS_DESKTOP_APPLICATION_H
+#define NAUTILUS_DESKTOP_APPLICATION_H
+
+#include <glib.h>
+#include "nautilus-application.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_DESKTOP_APPLICATION (nautilus_desktop_application_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusDesktopApplication, nautilus_desktop_application, NAUTILUS, DESKTOP_APPLICATION, NautilusApplication)
+
+NautilusDesktopApplication *nautilus_desktop_application_new (void);
+
+G_END_DECLS
+
+#endif /* NAUTILUS_DESKTOP_APPLICATION_H */
+
diff --git a/nautilus-desktop/nautilus-desktop-canvas-view-container.c b/nautilus-desktop/nautilus-desktop-canvas-view-container.c
new file mode 100644
index 000000000..23db902d2
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-canvas-view-container.c
@@ -0,0 +1,199 @@
+/* nautilus-desktop-canvas-view-container.c
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano@gnome.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-desktop-canvas-view-container.h"
+#include "nautilus-desktop-icon-file.h"
+
+struct _NautilusDesktopCanvasViewContainer
+{
+ NautilusCanvasViewContainer parent_instance;
+};
+
+G_DEFINE_TYPE (NautilusDesktopCanvasViewContainer, nautilus_desktop_canvas_view_container, NAUTILUS_TYPE_CANVAS_VIEW_CONTAINER)
+
+/* Sort as follows:
+ * 0) home link
+ * 1) network link
+ * 2) mount links
+ * 3) other
+ * 4) trash link
+ */
+typedef enum {
+ SORT_HOME_LINK,
+ SORT_NETWORK_LINK,
+ SORT_MOUNT_LINK,
+ SORT_OTHER,
+ SORT_TRASH_LINK
+} SortCategory;
+
+static SortCategory
+get_sort_category (NautilusFile *file)
+{
+ NautilusDesktopLink *link;
+ SortCategory category;
+
+ category = SORT_OTHER;
+
+ if (NAUTILUS_IS_DESKTOP_ICON_FILE (file))
+ {
+ link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
+ if (link != NULL)
+ {
+ switch (nautilus_desktop_link_get_link_type (link))
+ {
+ case NAUTILUS_DESKTOP_LINK_HOME:
+ category = SORT_HOME_LINK;
+ break;
+ case NAUTILUS_DESKTOP_LINK_MOUNT:
+ category = SORT_MOUNT_LINK;
+ break;
+ case NAUTILUS_DESKTOP_LINK_TRASH:
+ category = SORT_TRASH_LINK;
+ break;
+ case NAUTILUS_DESKTOP_LINK_NETWORK:
+ category = SORT_NETWORK_LINK;
+ break;
+ default:
+ category = SORT_OTHER;
+ break;
+ }
+ g_object_unref (link);
+ }
+ }
+
+ return category;
+}
+
+static int
+real_compare_icons (NautilusCanvasContainer *container,
+ NautilusCanvasIconData *data_a,
+ NautilusCanvasIconData *data_b)
+{
+ NautilusFile *file_a;
+ NautilusFile *file_b;
+ NautilusFilesView *directory_view;
+ SortCategory category_a, category_b;
+
+ file_a = (NautilusFile *) data_a;
+ file_b = (NautilusFile *) data_b;
+
+ directory_view = NAUTILUS_FILES_VIEW (NAUTILUS_CANVAS_VIEW_CONTAINER (container)->view);
+ g_return_val_if_fail (directory_view != NULL, 0);
+
+ category_a = get_sort_category (file_a);
+ category_b = get_sort_category (file_b);
+
+ if (category_a == category_b)
+ {
+ return nautilus_file_compare_for_sort (file_a,
+ file_b,
+ NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
+ nautilus_files_view_should_sort_directories_first (directory_view),
+ FALSE);
+ }
+
+ if (category_a < category_b)
+ {
+ return -1;
+ }
+ else
+ {
+ return +1;
+ }
+}
+
+static void
+real_get_icon_text (NautilusCanvasContainer *container,
+ NautilusCanvasIconData *data,
+ char **editable_text,
+ char **additional_text,
+ gboolean include_invisible)
+{
+ NautilusFile *file;
+ gboolean use_additional;
+
+ file = NAUTILUS_FILE (data);
+
+ g_assert (NAUTILUS_IS_FILE (file));
+ g_assert (editable_text != NULL);
+
+ use_additional = (additional_text != NULL);
+
+ /* Strip the suffix for nautilus object xml files. */
+ *editable_text = nautilus_file_get_display_name (file);
+
+ if (!use_additional) {
+ return;
+ }
+
+ if (NAUTILUS_IS_DESKTOP_ICON_FILE (file) ||
+ nautilus_file_is_nautilus_link (file))
+ {
+ /* Don't show the normal extra information for desktop icons,
+ * or desktop files, it doesn't make sense.
+ */
+ *additional_text = NULL;
+
+ return;
+ }
+
+ return NAUTILUS_CANVAS_CONTAINER_CLASS (nautilus_desktop_canvas_view_container_parent_class)->get_icon_text (container,
+ data,
+ editable_text,
+ additional_text,
+ include_invisible);
+}
+
+static char *
+real_get_icon_description (NautilusCanvasContainer *container,
+ NautilusCanvasIconData *data)
+{
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (data);
+ g_assert (NAUTILUS_IS_FILE (file));
+
+ if (NAUTILUS_IS_DESKTOP_ICON_FILE (file))
+ {
+ return NULL;
+ }
+
+ return NAUTILUS_CANVAS_CONTAINER_CLASS (nautilus_desktop_canvas_view_container_parent_class)->get_icon_description (container,
+ data);
+}
+
+NautilusDesktopCanvasViewContainer *
+nautilus_desktop_canvas_view_container_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW_CONTAINER, NULL);
+}
+
+static void
+nautilus_desktop_canvas_view_container_class_init (NautilusDesktopCanvasViewContainerClass *klass)
+{
+ NautilusCanvasContainerClass *container_class = NAUTILUS_CANVAS_CONTAINER_CLASS (klass);
+
+ container_class->get_icon_description = real_get_icon_description;
+ container_class->get_icon_text = real_get_icon_text;
+ container_class->compare_icons = real_compare_icons;
+}
+
+static void
+nautilus_desktop_canvas_view_container_init (NautilusDesktopCanvasViewContainer *self)
+{
+}
diff --git a/nautilus-desktop/nautilus-desktop-canvas-view-container.h b/nautilus-desktop/nautilus-desktop-canvas-view-container.h
new file mode 100644
index 000000000..018062b7d
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-canvas-view-container.h
@@ -0,0 +1,35 @@
+/* nautilus-desktop-canvas-view-container.h
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano@gnome.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef NAUTILUS_DESKTOP_CANVAS_VIEW_CONTAINER_H
+#define NAUTILUS_DESKTOP_CANVAS_VIEW_CONTAINER_H
+
+#include <glib.h>
+#include "nautilus-canvas-view-container.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW_CONTAINER (nautilus_desktop_canvas_view_container_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusDesktopCanvasViewContainer, nautilus_desktop_canvas_view_container, NAUTILUS, DESKTOP_CANVAS_VIEW_CONTAINER, NautilusCanvasViewContainer)
+
+NautilusDesktopCanvasViewContainer *nautilus_desktop_canvas_view_container_new (void);
+
+G_END_DECLS
+
+#endif /* NAUTILUS_DESKTOP_CANVAS_VIEW_CONTAINER_H */
+
diff --git a/nautilus-desktop/nautilus-desktop-canvas-view.c b/nautilus-desktop/nautilus-desktop-canvas-view.c
new file mode 100644
index 000000000..04731d96e
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-canvas-view.c
@@ -0,0 +1,744 @@
+
+/* nautilus-desktop-canvas-view.c - implementation of canvas view for managing the desktop.
+
+ Copyright (C) 2000, 2001 Eazel, Inc.mou
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ see <http://www.gnu.org/licenses/>.
+
+ Authors: Mike Engber <engber@eazel.com>
+ Gene Z. Ragan <gzr@eazel.com>
+ Miguel de Icaza <miguel@ximian.com>
+*/
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "nautilus-desktop-canvas-view.h"
+
+#include "nautilus-desktop-canvas-view-container.h"
+#include "nautilus-desktop-icon-file.h"
+#include "nautilus-desktop-directory.h"
+
+#include <X11/Xatom.h>
+#include <gtk/gtk.h>
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-extensions.h>
+#include <eel/eel-vfs-extensions.h>
+#include <fcntl.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+#include <libnautilus-private/nautilus-directory-notify.h>
+#include <libnautilus-private/nautilus-file-changes-queue.h>
+#include <libnautilus-private/nautilus-file-operations.h>
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-ui-utilities.h>
+#include <libnautilus-private/nautilus-global-preferences.h>
+#include <libnautilus-private/nautilus-link.h>
+#include <libnautilus-private/nautilus-metadata.h>
+#include <libnautilus-private/nautilus-monitor.h>
+#include <libnautilus-private/nautilus-program-choosing.h>
+#include <libnautilus-private/nautilus-trash-monitor.h>
+#include <src/nautilus-files-view.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+struct NautilusDesktopCanvasViewDetails
+{
+ GdkWindow *root_window;
+};
+
+static void default_zoom_level_changed (gpointer user_data);
+static void real_update_context_menus (NautilusFilesView *view);
+static char* real_get_backing_uri (NautilusFilesView *view);
+static void real_check_empty_states (NautilusFilesView *view);
+static char * real_get_file_paths_or_uris_as_newline_delimited_string (NautilusFilesView *view,
+ GList *selection,
+ gboolean get_paths);
+static void nautilus_desktop_canvas_view_update_canvas_container_fonts (NautilusDesktopCanvasView *view);
+static void font_changed_callback (gpointer callback_data);
+
+G_DEFINE_TYPE (NautilusDesktopCanvasView, nautilus_desktop_canvas_view, NAUTILUS_TYPE_CANVAS_VIEW)
+
+static char *desktop_directory;
+
+#define get_canvas_container(w) nautilus_canvas_view_get_canvas_container(NAUTILUS_CANVAS_VIEW (w))
+
+#define POPUP_PATH_CANVAS_APPEARANCE "/selection/Canvas Appearance Items"
+
+static void
+canvas_container_set_workarea (NautilusCanvasContainer *canvas_container,
+ GdkScreen *screen,
+ long *workareas,
+ int n_items)
+{
+ int left, right, top, bottom;
+ int screen_width, screen_height;
+ int i;
+
+ left = right = top = bottom = 0;
+
+ screen_width = gdk_screen_get_width (screen);
+ screen_height = gdk_screen_get_height (screen);
+
+ for (i = 0; i < n_items; i += 4) {
+ int x = workareas [i];
+ int y = workareas [i + 1];
+ int width = workareas [i + 2];
+ int height = workareas [i + 3];
+
+ if ((x + width) > screen_width || (y + height) > screen_height)
+ continue;
+
+ left = MAX (left, x);
+ right = MAX (right, screen_width - width - x);
+ top = MAX (top, y);
+ bottom = MAX (bottom, screen_height - height - y);
+ }
+
+ nautilus_canvas_container_set_margins (canvas_container,
+ left, right, top, bottom);
+}
+
+static void
+net_workarea_changed (NautilusDesktopCanvasView *canvas_view,
+ GdkWindow *window)
+{
+ long *nworkareas = NULL;
+ long *workareas = NULL;
+ GdkAtom type_returned;
+ int format_returned;
+ int length_returned;
+ NautilusCanvasContainer *canvas_container;
+ GdkScreen *screen;
+
+ g_return_if_fail (NAUTILUS_IS_DESKTOP_CANVAS_VIEW (canvas_view));
+
+ canvas_container = get_canvas_container (canvas_view);
+
+ /* Find the number of desktops so we know how long the
+ * workareas array is going to be (each desktop will have four
+ * elements in the workareas array describing
+ * x,y,width,height) */
+ gdk_error_trap_push ();
+ if (!gdk_property_get (window,
+ gdk_atom_intern ("_NET_NUMBER_OF_DESKTOPS", FALSE),
+ gdk_x11_xatom_to_atom (XA_CARDINAL),
+ 0, 4, FALSE,
+ &type_returned,
+ &format_returned,
+ &length_returned,
+ (guchar **) &nworkareas)) {
+ g_warning("Can not calculate _NET_NUMBER_OF_DESKTOPS");
+ }
+ if (gdk_error_trap_pop()
+ || nworkareas == NULL
+ || type_returned != gdk_x11_xatom_to_atom (XA_CARDINAL)
+ || format_returned != 32)
+ g_warning("Can not calculate _NET_NUMBER_OF_DESKTOPS");
+
+ /* Note : gdk_property_get() is broken (API documents admit
+ * this). As a length argument, it expects the number of
+ * _bytes_ of data you require. Internally, gdk_property_get
+ * converts that value to a count of 32 bit (4 byte) elements.
+ * However, the length returned is in bytes, but is calculated
+ * via the count of returned elements * sizeof(long). This
+ * means on a 64 bit system, the number of bytes you have to
+ * request does not correspond to the number of bytes you get
+ * back, and is the reason for the workaround below.
+ */
+ gdk_error_trap_push ();
+ if (nworkareas == NULL || (*nworkareas < 1)
+ || !gdk_property_get (window,
+ gdk_atom_intern ("_NET_WORKAREA", FALSE),
+ gdk_x11_xatom_to_atom (XA_CARDINAL),
+ 0, ((*nworkareas) * 4 * 4), FALSE,
+ &type_returned,
+ &format_returned,
+ &length_returned,
+ (guchar **) &workareas)) {
+ g_warning("Can not get _NET_WORKAREA");
+ workareas = NULL;
+ }
+
+ if (gdk_error_trap_pop ()
+ || workareas == NULL
+ || type_returned != gdk_x11_xatom_to_atom (XA_CARDINAL)
+ || ((*nworkareas) * 4 * sizeof(long)) != length_returned
+ || format_returned != 32) {
+ g_warning("Can not determine workarea, guessing at layout");
+ nautilus_canvas_container_set_margins (canvas_container,
+ 0, 0, 0, 0);
+ } else {
+ screen = gdk_window_get_screen (window);
+
+ canvas_container_set_workarea
+ (canvas_container, screen, workareas, length_returned / sizeof (long));
+ }
+
+ if (nworkareas != NULL)
+ g_free (nworkareas);
+
+ if (workareas != NULL)
+ g_free (workareas);
+}
+
+static GdkFilterReturn
+desktop_canvas_view_property_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xevent = gdk_xevent;
+ NautilusDesktopCanvasView *canvas_view;
+
+ canvas_view = NAUTILUS_DESKTOP_CANVAS_VIEW (data);
+
+ switch (xevent->type) {
+ case PropertyNotify:
+ if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("_NET_WORKAREA"))
+ net_workarea_changed (canvas_view, event->any.window);
+ break;
+ default:
+ break;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static guint
+real_get_id (NautilusFilesView *view)
+{
+ return NAUTILUS_VIEW_DESKTOP_ID;
+}
+
+static void
+nautilus_desktop_canvas_view_dispose (GObject *object)
+{
+ NautilusDesktopCanvasView *canvas_view;
+
+ canvas_view = NAUTILUS_DESKTOP_CANVAS_VIEW (object);
+
+ g_signal_handlers_disconnect_by_func (nautilus_icon_view_preferences,
+ default_zoom_level_changed,
+ canvas_view);
+ g_signal_handlers_disconnect_by_func (nautilus_preferences,
+ font_changed_callback,
+ canvas_view);
+ g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences,
+ nautilus_files_view_update_context_menus,
+ canvas_view);
+
+ G_OBJECT_CLASS (nautilus_desktop_canvas_view_parent_class)->dispose (object);
+}
+
+static void
+nautilus_desktop_canvas_view_end_loading (NautilusFilesView *view,
+ gboolean all_files_seen)
+{
+ gboolean needs_reorganization;
+ gchar *stored_size_icon;
+ guint current_zoom;
+ guint current_icon_size;
+ gchar *current_icon_size_string;
+ NautilusFile *file;
+
+ NAUTILUS_FILES_VIEW_CLASS (nautilus_desktop_canvas_view_parent_class)->end_loading (view, all_files_seen);
+
+ if (!all_files_seen)
+ return;
+
+ file = nautilus_files_view_get_directory_as_file (view);
+ g_return_if_fail (file != NULL);
+
+ stored_size_icon = nautilus_file_get_metadata (file, NAUTILUS_METADATA_KEY_DESKTOP_ICON_SIZE, NULL);
+ current_zoom = nautilus_canvas_container_get_zoom_level (get_canvas_container (view));
+ current_icon_size = nautilus_canvas_container_get_icon_size_for_zoom_level (current_zoom);
+ needs_reorganization = stored_size_icon == NULL || atoi (stored_size_icon) != current_icon_size;
+
+ if (needs_reorganization) {
+ current_icon_size_string = g_strdup_printf ("%d", current_icon_size);
+ nautilus_canvas_view_clean_up_by_name (NAUTILUS_CANVAS_VIEW (view));
+ nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_DESKTOP_ICON_SIZE,
+ NULL, current_icon_size_string);
+
+ g_free (current_icon_size_string);
+ }
+
+ g_free (stored_size_icon);
+}
+
+static NautilusCanvasContainer *
+real_create_canvas_container (NautilusCanvasView *canvas_view)
+{
+ return NAUTILUS_CANVAS_CONTAINER (nautilus_desktop_canvas_view_container_new ());
+}
+
+static void
+nautilus_desktop_canvas_view_class_init (NautilusDesktopCanvasViewClass *class)
+{
+ NautilusFilesViewClass *vclass;
+ NautilusCanvasViewClass *canvas_class;
+
+ vclass = NAUTILUS_FILES_VIEW_CLASS (class);
+ canvas_class = NAUTILUS_CANVAS_VIEW_CLASS (class);
+
+
+ G_OBJECT_CLASS (class)->dispose = nautilus_desktop_canvas_view_dispose;
+
+ canvas_class->create_canvas_container = real_create_canvas_container;
+
+ vclass->update_context_menus = real_update_context_menus;
+ vclass->get_view_id = real_get_id;
+ vclass->end_loading = nautilus_desktop_canvas_view_end_loading;
+ vclass->get_backing_uri = real_get_backing_uri;
+ vclass->check_empty_states = real_check_empty_states;
+
+ g_type_class_add_private (class, sizeof (NautilusDesktopCanvasViewDetails));
+}
+
+static void
+unrealized_callback (GtkWidget *widget, NautilusDesktopCanvasView *desktop_canvas_view)
+{
+ g_return_if_fail (desktop_canvas_view->details->root_window != NULL);
+
+ /* Remove the property filter */
+ gdk_window_remove_filter (desktop_canvas_view->details->root_window,
+ desktop_canvas_view_property_filter,
+ desktop_canvas_view);
+ desktop_canvas_view->details->root_window = NULL;
+}
+
+static void
+realized_callback (GtkWidget *widget, NautilusDesktopCanvasView *desktop_canvas_view)
+{
+ GdkWindow *root_window;
+ GdkScreen *screen;
+
+ g_return_if_fail (desktop_canvas_view->details->root_window == NULL);
+
+ screen = gtk_widget_get_screen (widget);
+ root_window = gdk_screen_get_root_window (screen);
+
+ desktop_canvas_view->details->root_window = root_window;
+
+ /* Read out the workarea geometry and update the icon container accordingly */
+ net_workarea_changed (desktop_canvas_view, root_window);
+
+ /* Setup the property filter */
+ gdk_window_set_events (root_window, GDK_PROPERTY_CHANGE_MASK);
+ gdk_window_add_filter (root_window,
+ desktop_canvas_view_property_filter,
+ desktop_canvas_view);
+}
+
+static void
+desktop_canvas_container_realize (GtkWidget *widget,
+ NautilusDesktopCanvasView *desktop_canvas_view)
+{
+ GdkWindow *bin_window;
+ GdkRGBA transparent = { 0, 0, 0, 0 };
+
+ bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (widget));
+ gdk_window_set_background_rgba (bin_window, &transparent);
+}
+
+static NautilusCanvasZoomLevel
+get_default_zoom_level (void)
+{
+ NautilusCanvasZoomLevel default_zoom_level;
+
+ default_zoom_level = g_settings_get_enum (nautilus_icon_view_preferences,
+ NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL);
+
+ return CLAMP (default_zoom_level, NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL, NAUTILUS_CANVAS_ZOOM_LEVEL_LARGE);
+}
+
+static void
+set_up_zoom_level (NautilusDesktopCanvasView *desktop_canvas_view)
+{
+ NautilusCanvasZoomLevel new_level;
+
+ new_level = get_default_zoom_level ();
+ nautilus_canvas_container_set_zoom_level (get_canvas_container (desktop_canvas_view),
+ new_level);
+}
+
+static void
+default_zoom_level_changed (gpointer user_data)
+{
+ NautilusCanvasZoomLevel new_level;
+ NautilusDesktopCanvasView *desktop_canvas_view;
+ gint new_icon_size;
+ NautilusFile *file;
+ gchar *new_icon_size_string;
+
+ desktop_canvas_view = NAUTILUS_DESKTOP_CANVAS_VIEW (user_data);
+ file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (user_data));
+ new_level = get_default_zoom_level ();
+ new_icon_size = nautilus_canvas_container_get_icon_size_for_zoom_level (new_level);
+ new_icon_size_string = g_strdup_printf ("%d", new_icon_size);
+
+ nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_DESKTOP_ICON_SIZE,
+ NULL, new_icon_size_string);
+ set_up_zoom_level (desktop_canvas_view);
+
+ g_free (new_icon_size_string);
+}
+
+static void
+font_changed_callback (gpointer callback_data)
+{
+ g_return_if_fail (NAUTILUS_IS_DESKTOP_CANVAS_VIEW (callback_data));
+
+ nautilus_desktop_canvas_view_update_canvas_container_fonts (NAUTILUS_DESKTOP_CANVAS_VIEW (callback_data));
+}
+
+static void
+nautilus_desktop_canvas_view_update_canvas_container_fonts (NautilusDesktopCanvasView *canvas_view)
+{
+ NautilusCanvasContainer *canvas_container;
+ char *font;
+
+ canvas_container = get_canvas_container (canvas_view);
+ g_assert (canvas_container != NULL);
+
+ font = g_settings_get_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_FONT);
+
+ nautilus_canvas_container_set_font (canvas_container, font);
+
+ g_free (font);
+}
+
+static const gchar *
+get_control_center_command (const gchar ** params_out)
+{
+ gchar *path;
+ const gchar *retval;
+ const gchar *params;
+ const gchar *xdg_current_desktop;
+ gchar **desktop_names;
+ gboolean is_unity;
+ int i;
+
+ path = NULL;
+ retval = NULL;
+ params = NULL;
+
+ xdg_current_desktop = g_getenv ("XDG_CURRENT_DESKTOP");
+
+ /* Detect the Unity-based environments */
+ is_unity = FALSE;
+ if (xdg_current_desktop != NULL) {
+ desktop_names = g_strsplit (xdg_current_desktop, ":", 0);
+ for (i = 0; desktop_names[i]; ++i) {
+ if (!g_strcmp0 (desktop_names[i], "Unity")) {
+ is_unity = TRUE;
+ break;
+ }
+ }
+ g_strfreev (desktop_names);
+ }
+
+ /* In Unity look for unity-control-center */
+ if (is_unity) {
+ path = g_find_program_in_path ("unity-control-center");
+ if (path != NULL) {
+ retval = "unity-control-center";
+ params = "appearance";
+ goto out;
+ }
+ }
+
+ /* Otherwise look for gnome-control-center */
+ path = g_find_program_in_path ("gnome-control-center");
+ if (path != NULL) {
+ retval = "gnome-control-center";
+ params = "background";
+ }
+
+ out:
+ g_free (path);
+ if (params_out != NULL) {
+ *params_out = params;
+ }
+
+ return retval;
+}
+
+static void
+action_change_background (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ const gchar *control_center_cmd, *params;
+
+ g_assert (NAUTILUS_FILES_VIEW (user_data));
+
+ control_center_cmd = get_control_center_command (&params);
+ if (control_center_cmd == NULL) {
+ return;
+ }
+
+ nautilus_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (user_data)),
+ control_center_cmd,
+ FALSE,
+ params, NULL);
+}
+
+static void
+action_empty_trash (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
+
+ nautilus_file_operations_empty_trash (GTK_WIDGET (user_data));
+}
+
+static void
+action_stretch (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ nautilus_canvas_container_show_stretch_handles
+ (get_canvas_container (user_data));
+}
+
+static void
+action_unstretch (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ nautilus_canvas_container_unstretch (get_canvas_container (user_data));
+}
+
+static void
+action_organize_desktop_by_name (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ nautilus_canvas_view_clean_up_by_name (NAUTILUS_CANVAS_VIEW (user_data));
+}
+
+static gboolean
+trash_link_is_selection (NautilusFilesView *view)
+{
+ GList *selection;
+ NautilusDesktopLink *link;
+ gboolean result;
+
+ result = FALSE;
+
+ selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
+
+ if ((g_list_length (selection) == 1) &&
+ NAUTILUS_IS_DESKTOP_ICON_FILE (selection->data)) {
+ link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (selection->data));
+ /* link may be NULL if the link was recently removed (unmounted) */
+ if (link != NULL &&
+ nautilus_desktop_link_get_link_type (link) == NAUTILUS_DESKTOP_LINK_TRASH) {
+ result = TRUE;
+ }
+ if (link) {
+ g_object_unref (link);
+ }
+ }
+
+ nautilus_file_list_free (selection);
+
+ return result;
+}
+
+const GActionEntry desktop_view_entries[] = {
+ { "change-background", action_change_background },
+ { "organize-desktop-by-name", action_organize_desktop_by_name },
+ { "empty-trash", action_empty_trash },
+ { "stretch", action_stretch },
+ { "unstretch", action_unstretch },
+};
+
+static void
+real_check_empty_states (NautilusFilesView *view)
+{
+ /* Do nothing */
+}
+
+static char*
+real_get_backing_uri (NautilusFilesView *view)
+{
+ gchar *uri;
+ NautilusDirectory *directory;
+ NautilusDirectory *model;
+
+ g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
+
+ model = nautilus_files_view_get_model (view);
+
+ if (model == NULL) {
+ return NULL;
+ }
+
+ directory = nautilus_desktop_directory_get_real_directory (NAUTILUS_DESKTOP_DIRECTORY (model));
+
+ uri = nautilus_directory_get_uri (directory);
+
+ nautilus_directory_unref (directory);
+
+ return uri;
+}
+
+static void
+real_update_context_menus (NautilusFilesView *view)
+{
+ NautilusCanvasContainer *canvas_container;
+ NautilusDesktopCanvasView *desktop_view;
+ GAction *action;
+ GActionGroup *view_action_group;
+ GList *selection;
+ int selection_count;
+
+ g_assert (NAUTILUS_IS_DESKTOP_CANVAS_VIEW (view));
+
+ NAUTILUS_FILES_VIEW_CLASS (nautilus_desktop_canvas_view_parent_class)->update_context_menus (view);
+
+ view_action_group = nautilus_files_view_get_action_group (view);
+ desktop_view = NAUTILUS_DESKTOP_CANVAS_VIEW (view);
+ selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
+ selection_count = g_list_length (selection);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "empty-trash");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), trash_link_is_selection (view));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "keep-aligned");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "organize-desktop-by-name");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "change-background");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "properties");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selection_count > 0);
+
+ /* Stretch */
+ canvas_container = get_canvas_container (desktop_view);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "stretch");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selection_count == 1 &&
+ canvas_container != NULL &&
+ !nautilus_canvas_container_has_stretch_handles (canvas_container));
+
+ nautilus_file_list_free (selection);
+
+ /* Unstretch */
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "unstretch");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), canvas_container != NULL &&
+ nautilus_canvas_container_is_stretched (canvas_container));
+}
+
+static void
+nautilus_desktop_canvas_view_init (NautilusDesktopCanvasView *desktop_canvas_view)
+{
+ NautilusCanvasContainer *canvas_container;
+ GtkAllocation allocation;
+ GActionGroup *view_action_group;
+ GtkAdjustment *hadj, *vadj;
+
+ desktop_canvas_view->details = G_TYPE_INSTANCE_GET_PRIVATE (desktop_canvas_view,
+ NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW,
+ NautilusDesktopCanvasViewDetails);
+
+ if (desktop_directory == NULL) {
+ desktop_directory = nautilus_get_desktop_directory ();
+ }
+
+ canvas_container = get_canvas_container (desktop_canvas_view);
+
+ nautilus_canvas_container_set_is_fixed_size (canvas_container, TRUE);
+ nautilus_canvas_container_set_is_desktop (canvas_container, TRUE);
+ nautilus_canvas_container_set_store_layout_timestamps (canvas_container, TRUE);
+
+ /* Set allocation to be at 0, 0 */
+ gtk_widget_get_allocation (GTK_WIDGET (canvas_container), &allocation);
+ allocation.x = 0;
+ allocation.y = 0;
+ gtk_widget_set_allocation (GTK_WIDGET (canvas_container), &allocation);
+
+ gtk_widget_queue_resize (GTK_WIDGET (canvas_container));
+
+ hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas_container));
+ vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas_container));
+
+ gtk_adjustment_set_value (hadj, 0);
+ gtk_adjustment_set_value (vadj, 0);
+
+ nautilus_files_view_ignore_hidden_file_preferences
+ (NAUTILUS_FILES_VIEW (desktop_canvas_view));
+
+ nautilus_files_view_set_show_foreign (NAUTILUS_FILES_VIEW (desktop_canvas_view),
+ FALSE);
+
+ g_signal_connect_object (canvas_container, "realize",
+ G_CALLBACK (desktop_canvas_container_realize), desktop_canvas_view, 0);
+
+ g_signal_connect_object (desktop_canvas_view, "realize",
+ G_CALLBACK (realized_callback), desktop_canvas_view, 0);
+ g_signal_connect_object (desktop_canvas_view, "unrealize",
+ G_CALLBACK (unrealized_callback), desktop_canvas_view, 0);
+
+ g_signal_connect_swapped (nautilus_icon_view_preferences,
+ "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
+ G_CALLBACK (default_zoom_level_changed),
+ desktop_canvas_view);
+
+ g_signal_connect_swapped (nautilus_desktop_preferences,
+ "changed::" NAUTILUS_PREFERENCES_DESKTOP_FONT,
+ G_CALLBACK (font_changed_callback),
+ desktop_canvas_view);
+
+ set_up_zoom_level (desktop_canvas_view);
+ nautilus_desktop_canvas_view_update_canvas_container_fonts (desktop_canvas_view);
+
+ g_signal_connect_swapped (gnome_lockdown_preferences,
+ "changed::" NAUTILUS_PREFERENCES_LOCKDOWN_COMMAND_LINE,
+ G_CALLBACK (nautilus_files_view_update_context_menus),
+ desktop_canvas_view);
+
+ view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (desktop_canvas_view));
+
+ g_action_map_add_action_entries (G_ACTION_MAP (view_action_group),
+ desktop_view_entries,
+ G_N_ELEMENTS (desktop_view_entries),
+ NAUTILUS_FILES_VIEW (desktop_canvas_view));
+}
+
+NautilusFilesView *
+nautilus_desktop_canvas_view_new (NautilusWindowSlot *slot)
+{
+ return g_object_new (NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW,
+ "window-slot", slot,
+ "supports-zooming", FALSE,
+ "supports-auto-layout", FALSE,
+ "supports-manual-layout", TRUE,
+ "supports-scaling", TRUE,
+ "supports-keep-aligned", TRUE,
+ NULL);
+}
diff --git a/nautilus-desktop/nautilus-desktop-canvas-view.h b/nautilus-desktop/nautilus-desktop-canvas-view.h
new file mode 100644
index 000000000..e40d80ff4
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-canvas-view.h
@@ -0,0 +1,54 @@
+
+/* fm-icon-view.h - interface for icon view of directory.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ see <http://www.gnu.org/licenses/>.
+
+ Authors: Mike Engber <engber@eazel.com>
+*/
+
+#ifndef NAUTILUS_DESKTOP_CANVAS_VIEW_H
+#define NAUTILUS_DESKTOP_CANVAS_VIEW_H
+
+#include "nautilus-canvas-view.h"
+
+#define NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW nautilus_desktop_canvas_view_get_type()
+#define NAUTILUS_DESKTOP_CANVAS_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW, NautilusDesktopCanvasView))
+#define NAUTILUS_DESKTOP_CANVAS_VIEW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW, NautilusDesktopCanvasViewClass))
+#define NAUTILUS_IS_DESKTOP_CANVAS_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW))
+#define NAUTILUS_IS_DESKTOP_CANVAS_VIEW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW))
+#define NAUTILUS_DESKTOP_CANVAS_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_DESKTOP_CANVAS_VIEW, NautilusDesktopCanvasViewClass))
+
+typedef struct NautilusDesktopCanvasViewDetails NautilusDesktopCanvasViewDetails;
+typedef struct {
+ NautilusCanvasView parent;
+ NautilusDesktopCanvasViewDetails *details;
+} NautilusDesktopCanvasView;
+
+typedef struct {
+ NautilusCanvasViewClass parent_class;
+} NautilusDesktopCanvasViewClass;
+
+/* GObject support */
+GType nautilus_desktop_canvas_view_get_type (void);
+NautilusFilesView * nautilus_desktop_canvas_view_new (NautilusWindowSlot *slot);
+
+#endif /* NAUTILUS_DESKTOP_CANVAS_VIEW_H */
diff --git a/nautilus-desktop/nautilus-desktop-directory-file.c b/nautilus-desktop/nautilus-desktop-directory-file.c
new file mode 100644
index 000000000..ba3cd136c
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-directory-file.c
@@ -0,0 +1,557 @@
+/*
+ nautilus-desktop-directory-file.c: Subclass of NautilusFile to help implement the
+ virtual desktop.
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#include <config.h>
+#include "nautilus-desktop-directory-file.h"
+#include "nautilus-desktop-metadata.h"
+#include "nautilus-desktop-directory.h"
+
+#include <libnautilus-private/nautilus-directory-notify.h>
+#include <libnautilus-private/nautilus-directory-private.h>
+#include <libnautilus-private/nautilus-file-attributes.h>
+#include <libnautilus-private/nautilus-file-private.h>
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-metadata.h>
+
+#include <eel/eel-glib-extensions.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+struct NautilusDesktopDirectoryFileDetails {
+ NautilusDesktopDirectory *desktop_directory;
+
+ NautilusFile *real_dir_file;
+
+ GHashTable *callbacks;
+ GHashTable *monitors;
+};
+
+typedef struct {
+ NautilusDesktopDirectoryFile *desktop_file;
+ NautilusFileCallback callback;
+ gpointer callback_data;
+
+ NautilusFileAttributes delegated_attributes;
+ NautilusFileAttributes non_delegated_attributes;
+
+ GList *non_ready_files;
+
+ gboolean initializing;
+} DesktopCallback;
+
+typedef struct {
+ NautilusDesktopDirectoryFile *desktop_file;
+
+ NautilusFileAttributes delegated_attributes;
+ NautilusFileAttributes non_delegated_attributes;
+} DesktopMonitor;
+
+G_DEFINE_TYPE (NautilusDesktopDirectoryFile, nautilus_desktop_directory_file,
+ NAUTILUS_TYPE_FILE);
+
+static guint
+desktop_callback_hash (gconstpointer desktop_callback_as_pointer)
+{
+ const DesktopCallback *desktop_callback;
+
+ desktop_callback = desktop_callback_as_pointer;
+ return GPOINTER_TO_UINT (desktop_callback->callback)
+ ^ GPOINTER_TO_UINT (desktop_callback->callback_data);
+}
+
+static gboolean
+desktop_callback_equal (gconstpointer desktop_callback_as_pointer,
+ gconstpointer desktop_callback_as_pointer_2)
+{
+ const DesktopCallback *desktop_callback, *desktop_callback_2;
+
+ desktop_callback = desktop_callback_as_pointer;
+ desktop_callback_2 = desktop_callback_as_pointer_2;
+
+ return desktop_callback->callback == desktop_callback_2->callback
+ && desktop_callback->callback_data == desktop_callback_2->callback_data;
+}
+
+
+static void
+real_file_changed_callback (NautilusFile *real_file,
+ gpointer callback_data)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (callback_data);
+ nautilus_file_changed (NAUTILUS_FILE (desktop_file));
+}
+
+static NautilusFileAttributes
+get_delegated_attributes_mask (void)
+{
+ return NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS |
+ NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
+ NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES |
+ NAUTILUS_FILE_ATTRIBUTE_INFO;
+}
+
+static void
+partition_attributes (NautilusFileAttributes attributes,
+ NautilusFileAttributes *delegated_attributes,
+ NautilusFileAttributes *non_delegated_attributes)
+{
+ NautilusFileAttributes mask;
+
+ mask = get_delegated_attributes_mask ();
+
+ *delegated_attributes = attributes & mask;
+ *non_delegated_attributes = attributes & ~mask;
+}
+
+static void
+desktop_directory_file_monitor_add (NautilusFile *file,
+ gconstpointer client,
+ NautilusFileAttributes attributes)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+ DesktopMonitor *monitor;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ /* Map the client to a unique value so this doesn't interfere
+ * with direct monitoring of the file by the same client.
+ */
+ monitor = g_hash_table_lookup (desktop_file->details->monitors, client);
+ if (monitor != NULL) {
+ g_assert (monitor->desktop_file == desktop_file);
+ } else {
+ monitor = g_new0 (DesktopMonitor, 1);
+ monitor->desktop_file = desktop_file;
+ g_hash_table_insert (desktop_file->details->monitors,
+ (gpointer) client, monitor);
+ }
+
+ partition_attributes (attributes,
+ &monitor->delegated_attributes,
+ &monitor->non_delegated_attributes);
+
+ /* Pawn off partioned attributes to real dir file */
+ nautilus_file_monitor_add (desktop_file->details->real_dir_file,
+ monitor, monitor->delegated_attributes);
+
+ /* Do the rest ourself */
+ nautilus_directory_monitor_add_internal
+ (file->details->directory, file,
+ client, TRUE,
+ monitor->non_delegated_attributes,
+ NULL, NULL);
+}
+
+static void
+desktop_directory_file_monitor_remove (NautilusFile *file,
+ gconstpointer client)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+ DesktopMonitor *monitor;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ /* Map the client to the value used by the earlier add call. */
+ monitor = g_hash_table_lookup (desktop_file->details->monitors, client);
+ if (monitor == NULL) {
+ return;
+ }
+
+ /* Call through to the real file remove calls. */
+ g_hash_table_remove (desktop_file->details->monitors, client);
+
+ /* Remove the locally handled parts */
+ nautilus_directory_monitor_remove_internal
+ (file->details->directory, file, client);
+}
+
+static void
+desktop_callback_destroy (DesktopCallback *desktop_callback)
+{
+ g_assert (desktop_callback != NULL);
+ g_assert (NAUTILUS_IS_DESKTOP_DIRECTORY_FILE (desktop_callback->desktop_file));
+
+ nautilus_file_unref (NAUTILUS_FILE (desktop_callback->desktop_file));
+ g_list_free (desktop_callback->non_ready_files);
+ g_free (desktop_callback);
+}
+
+static void
+desktop_callback_check_done (DesktopCallback *desktop_callback)
+{
+ /* Check if we are ready. */
+ if (desktop_callback->initializing ||
+ desktop_callback->non_ready_files != NULL) {
+ return;
+ }
+
+ /* Ensure our metadata is updated before calling back */
+ nautilus_desktop_update_metadata_from_keyfile (NAUTILUS_FILE (desktop_callback->desktop_file), "directory");
+
+ /* Remove from the hash table before sending it. */
+ g_hash_table_remove (desktop_callback->desktop_file->details->callbacks,
+ desktop_callback);
+
+ /* We are ready, so do the real callback. */
+ (* desktop_callback->callback) (NAUTILUS_FILE (desktop_callback->desktop_file),
+ desktop_callback->callback_data);
+
+ /* And we are done. */
+ desktop_callback_destroy (desktop_callback);
+}
+
+static void
+desktop_callback_remove_file (DesktopCallback *desktop_callback,
+ NautilusFile *file)
+{
+ desktop_callback->non_ready_files = g_list_remove
+ (desktop_callback->non_ready_files, file);
+ desktop_callback_check_done (desktop_callback);
+}
+
+static void
+ready_callback (NautilusFile *file,
+ gpointer callback_data)
+{
+ DesktopCallback *desktop_callback;
+
+ g_assert (NAUTILUS_IS_FILE (file));
+ g_assert (callback_data != NULL);
+
+ desktop_callback = callback_data;
+ g_assert (g_list_find (desktop_callback->non_ready_files, file) != NULL);
+
+ desktop_callback_remove_file (desktop_callback, file);
+}
+
+static void
+desktop_directory_file_call_when_ready (NautilusFile *file,
+ NautilusFileAttributes attributes,
+ NautilusFileCallback callback,
+ gpointer callback_data)
+
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+ DesktopCallback search_key, *desktop_callback;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ /* Check to be sure we aren't overwriting. */
+ search_key.callback = callback;
+ search_key.callback_data = callback_data;
+ if (g_hash_table_lookup (desktop_file->details->callbacks, &search_key) != NULL) {
+ g_warning ("tried to add a new callback while an old one was pending");
+ return;
+ }
+
+ /* Create a desktop_callback record. */
+ desktop_callback = g_new0 (DesktopCallback, 1);
+ nautilus_file_ref (file);
+ desktop_callback->desktop_file = desktop_file;
+ desktop_callback->callback = callback;
+ desktop_callback->callback_data = callback_data;
+ desktop_callback->initializing = TRUE;
+
+ partition_attributes (attributes,
+ &desktop_callback->delegated_attributes,
+ &desktop_callback->non_delegated_attributes);
+
+ desktop_callback->non_ready_files = g_list_prepend
+ (desktop_callback->non_ready_files, file);
+ desktop_callback->non_ready_files = g_list_prepend
+ (desktop_callback->non_ready_files, desktop_file->details->real_dir_file);
+
+ /* Put it in the hash table. */
+ g_hash_table_insert (desktop_file->details->callbacks,
+ desktop_callback, desktop_callback);
+
+ /* Now connect to each file's call_when_ready. */
+ nautilus_directory_call_when_ready_internal
+ (file->details->directory, file,
+ desktop_callback->non_delegated_attributes,
+ FALSE, NULL, ready_callback, desktop_callback);
+ nautilus_file_call_when_ready
+ (desktop_file->details->real_dir_file,
+ desktop_callback->delegated_attributes,
+ ready_callback, desktop_callback);
+
+ desktop_callback->initializing = FALSE;
+
+ /* Check if any files became read while we were connecting up
+ * the call_when_ready callbacks (also handles the pathological
+ * case where there are no files at all).
+ */
+ desktop_callback_check_done (desktop_callback);
+
+}
+
+static void
+desktop_directory_file_cancel_call_when_ready (NautilusFile *file,
+ NautilusFileCallback callback,
+ gpointer callback_data)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+ DesktopCallback search_key, *desktop_callback;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ /* Find the entry in the table. */
+ search_key.callback = callback;
+ search_key.callback_data = callback_data;
+ desktop_callback = g_hash_table_lookup (desktop_file->details->callbacks, &search_key);
+ if (desktop_callback == NULL) {
+ return;
+ }
+
+ /* Remove from the hash table before working with it. */
+ g_hash_table_remove (desktop_callback->desktop_file->details->callbacks, desktop_callback);
+
+ /* Tell the real directory to cancel the call. */
+ nautilus_directory_cancel_callback_internal
+ (file->details->directory, file,
+ NULL, ready_callback, desktop_callback);
+
+ nautilus_file_cancel_call_when_ready
+ (desktop_file->details->real_dir_file,
+ ready_callback, desktop_callback);
+
+ desktop_callback_destroy (desktop_callback);
+}
+
+static gboolean
+real_check_if_ready (NautilusFile *file,
+ NautilusFileAttributes attributes)
+{
+ return nautilus_directory_check_if_ready_internal
+ (file->details->directory, file,
+ attributes);
+}
+
+static gboolean
+desktop_directory_file_check_if_ready (NautilusFile *file,
+ NautilusFileAttributes attributes)
+{
+ NautilusFileAttributes delegated_attributes, non_delegated_attributes;
+ NautilusDesktopDirectoryFile *desktop_file;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ partition_attributes (attributes,
+ &delegated_attributes,
+ &non_delegated_attributes);
+
+ return real_check_if_ready (file, non_delegated_attributes) &&
+ nautilus_file_check_if_ready (desktop_file->details->real_dir_file,
+ delegated_attributes);
+}
+
+static gboolean
+desktop_directory_file_get_item_count (NautilusFile *file,
+ guint *count,
+ gboolean *count_unreadable)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+ gboolean got_count;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ got_count = nautilus_file_get_directory_item_count (desktop_file->details->real_dir_file,
+ count,
+ count_unreadable);
+
+ if (count) {
+ *count += g_list_length (file->details->directory->details->file_list);
+ }
+
+ return got_count;
+}
+
+static NautilusRequestStatus
+desktop_directory_file_get_deep_counts (NautilusFile *file,
+ guint *directory_count,
+ guint *file_count,
+ guint *unreadable_directory_count,
+ goffset *total_size)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+ NautilusRequestStatus status;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ status = nautilus_file_get_deep_counts (desktop_file->details->real_dir_file,
+ directory_count,
+ file_count,
+ unreadable_directory_count,
+ total_size,
+ TRUE);
+
+ if (file_count) {
+ *file_count += g_list_length (file->details->directory->details->file_list);
+ }
+
+ return status;
+}
+
+static gboolean
+desktop_directory_file_get_date (NautilusFile *file,
+ NautilusDateType date_type,
+ time_t *date)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file);
+
+ return nautilus_file_get_date (desktop_file->details->real_dir_file,
+ date_type,
+ date);
+}
+
+static char *
+desktop_directory_file_get_where_string (NautilusFile *file)
+{
+ return g_strdup (_("on the desktop"));
+}
+
+
+static void
+monitor_destroy (gpointer data)
+{
+ DesktopMonitor *monitor = data;
+
+ nautilus_file_monitor_remove
+ (NAUTILUS_FILE (monitor->desktop_file->details->real_dir_file), monitor);
+ g_free (monitor);
+}
+
+static void
+nautilus_desktop_directory_file_set_metadata (NautilusFile *file,
+ const char *key,
+ const char *value)
+{
+ nautilus_desktop_set_metadata_string (file, "directory", key, value);
+}
+
+static void
+nautilus_desktop_directory_file_set_metadata_as_list (NautilusFile *file,
+ const char *key,
+ char **value)
+{
+ nautilus_desktop_set_metadata_stringv (file, "directory", key, (const gchar **) value);
+}
+
+static void
+nautilus_desktop_directory_file_init (NautilusDesktopDirectoryFile *desktop_file)
+{
+ NautilusDesktopDirectory *desktop_directory;
+ NautilusDirectory *real_dir;
+ NautilusFile *real_dir_file;
+
+ desktop_file->details = G_TYPE_INSTANCE_GET_PRIVATE (desktop_file,
+ NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE,
+ NautilusDesktopDirectoryFileDetails);
+
+ desktop_directory = NAUTILUS_DESKTOP_DIRECTORY (nautilus_directory_get_by_uri (EEL_DESKTOP_URI));
+ desktop_file->details->desktop_directory = desktop_directory;
+
+ desktop_file->details->callbacks = g_hash_table_new
+ (desktop_callback_hash, desktop_callback_equal);
+ desktop_file->details->monitors = g_hash_table_new_full (NULL, NULL,
+ NULL, monitor_destroy);
+
+ real_dir = nautilus_desktop_directory_get_real_directory (desktop_directory);
+ real_dir_file = nautilus_directory_get_corresponding_file (real_dir);
+ nautilus_directory_unref (real_dir);
+
+ desktop_file->details->real_dir_file = real_dir_file;
+ g_signal_connect_object (real_dir_file, "changed",
+ G_CALLBACK (real_file_changed_callback), desktop_file, 0);
+}
+
+
+static void
+desktop_callback_remove_file_cover (gpointer key,
+ gpointer value,
+ gpointer callback_data)
+{
+ desktop_callback_remove_file
+ (value, NAUTILUS_FILE (callback_data));
+}
+
+
+static void
+desktop_finalize (GObject *object)
+{
+ NautilusDesktopDirectoryFile *desktop_file;
+ NautilusDesktopDirectory *desktop_directory;
+
+ desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (object);
+ desktop_directory = desktop_file->details->desktop_directory;
+
+ /* Todo: ghash now safe? */
+ eel_g_hash_table_safe_for_each
+ (desktop_file->details->callbacks,
+ desktop_callback_remove_file_cover,
+ desktop_file->details->real_dir_file);
+
+ if (g_hash_table_size (desktop_file->details->callbacks) != 0) {
+ g_warning ("call_when_ready still pending when desktop virtual file is destroyed");
+ }
+
+ g_hash_table_destroy (desktop_file->details->callbacks);
+ g_hash_table_destroy (desktop_file->details->monitors);
+
+ nautilus_file_unref (desktop_file->details->real_dir_file);
+ nautilus_directory_unref (NAUTILUS_DIRECTORY (desktop_directory));
+
+ G_OBJECT_CLASS (nautilus_desktop_directory_file_parent_class)->finalize (object);
+}
+
+static void
+nautilus_desktop_directory_file_class_init (NautilusDesktopDirectoryFileClass *klass)
+{
+ GObjectClass *object_class;
+ NautilusFileClass *file_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ file_class = NAUTILUS_FILE_CLASS (klass);
+
+ object_class->finalize = desktop_finalize;
+
+ file_class->default_file_type = G_FILE_TYPE_DIRECTORY;
+
+ file_class->monitor_add = desktop_directory_file_monitor_add;
+ file_class->monitor_remove = desktop_directory_file_monitor_remove;
+ file_class->call_when_ready = desktop_directory_file_call_when_ready;
+ file_class->cancel_call_when_ready = desktop_directory_file_cancel_call_when_ready;
+ file_class->check_if_ready = desktop_directory_file_check_if_ready;
+ file_class->get_item_count = desktop_directory_file_get_item_count;
+ file_class->get_deep_counts = desktop_directory_file_get_deep_counts;
+ file_class->get_date = desktop_directory_file_get_date;
+ file_class->get_where_string = desktop_directory_file_get_where_string;
+ file_class->set_metadata = nautilus_desktop_directory_file_set_metadata;
+ file_class->set_metadata_as_list = nautilus_desktop_directory_file_set_metadata_as_list;
+
+ g_type_class_add_private (klass, sizeof (NautilusDesktopDirectoryFileDetails));
+}
diff --git a/nautilus-desktop/nautilus-desktop-directory-file.h b/nautilus-desktop/nautilus-desktop-directory-file.h
new file mode 100644
index 000000000..2a5097980
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-directory-file.h
@@ -0,0 +1,53 @@
+/*
+ nautilus-desktop-directory-file.h: Subclass of NautilusFile to implement the
+ the case of the desktop directory
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#ifndef NAUTILUS_DESKTOP_DIRECTORY_FILE_H
+#define NAUTILUS_DESKTOP_DIRECTORY_FILE_H
+
+#include <libnautilus-private/nautilus-file.h>
+
+#define NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE nautilus_desktop_directory_file_get_type()
+#define NAUTILUS_DESKTOP_DIRECTORY_FILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NautilusDesktopDirectoryFile))
+#define NAUTILUS_DESKTOP_DIRECTORY_FILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NautilusDesktopDirectoryFileClass))
+#define NAUTILUS_IS_DESKTOP_DIRECTORY_FILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE))
+#define NAUTILUS_IS_DESKTOP_DIRECTORY_FILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE))
+#define NAUTILUS_DESKTOP_DIRECTORY_FILE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NautilusDesktopDirectoryFileClass))
+
+typedef struct NautilusDesktopDirectoryFileDetails NautilusDesktopDirectoryFileDetails;
+
+typedef struct {
+ NautilusFile parent_slot;
+ NautilusDesktopDirectoryFileDetails *details;
+} NautilusDesktopDirectoryFile;
+
+typedef struct {
+ NautilusFileClass parent_slot;
+} NautilusDesktopDirectoryFileClass;
+
+GType nautilus_desktop_directory_file_get_type (void);
+
+#endif /* NAUTILUS_DESKTOP_DIRECTORY_FILE_H */
diff --git a/nautilus-desktop/nautilus-desktop-directory.c b/nautilus-desktop/nautilus-desktop-directory.c
new file mode 100644
index 000000000..6a43ec5e8
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-directory.c
@@ -0,0 +1,571 @@
+/*
+ nautilus-desktop-directory.c: Subclass of NautilusDirectory to implement
+ a virtual directory consisting of the desktop directory and the desktop
+ icons
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#include <config.h>
+#include "nautilus-desktop-directory.h"
+#include "nautilus-desktop-directory-file.h"
+
+#include <libnautilus-private/nautilus-directory-private.h>
+#include <libnautilus-private/nautilus-file.h>
+#include <libnautilus-private/nautilus-file-private.h>
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-global-preferences.h>
+#include <gtk/gtk.h>
+
+struct NautilusDesktopDirectoryDetails {
+ NautilusDirectory *real_directory;
+ GHashTable *callbacks;
+ GHashTable *monitors;
+};
+
+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;
+
+
+typedef struct {
+ NautilusDesktopDirectory *desktop_dir;
+
+ gboolean monitor_hidden_files;
+ NautilusFileAttributes monitor_attributes;
+} MergedMonitor;
+
+static void desktop_directory_changed_callback (gpointer data);
+
+G_DEFINE_TYPE_WITH_CODE (NautilusDesktopDirectory, nautilus_desktop_directory, NAUTILUS_TYPE_DIRECTORY,
+ nautilus_ensure_extension_points ();
+ g_io_extension_point_implement (NAUTILUS_DIRECTORY_PROVIDER_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ NAUTILUS_DESKTOP_DIRECTORY_PROVIDER_NAME,
+ 0));
+static gboolean
+desktop_contains_file (NautilusDirectory *directory,
+ NautilusFile *file)
+{
+ NautilusDesktopDirectory *desktop;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ if (nautilus_directory_contains_file (desktop->details->real_directory, file)) {
+ return TRUE;
+ }
+
+ return file->details->directory == directory;
+}
+
+static guint
+merged_callback_hash (gconstpointer merged_callback_as_pointer)
+{
+ const MergedCallback *merged_callback;
+
+ merged_callback = merged_callback_as_pointer;
+ return GPOINTER_TO_UINT (merged_callback->callback)
+ ^ GPOINTER_TO_UINT (merged_callback->callback_data);
+}
+
+static gboolean
+merged_callback_equal (gconstpointer merged_callback_as_pointer,
+ gconstpointer merged_callback_as_pointer_2)
+{
+ const MergedCallback *merged_callback, *merged_callback_2;
+
+ merged_callback = merged_callback_as_pointer;
+ merged_callback_2 = merged_callback_as_pointer_2;
+
+ return merged_callback->callback == merged_callback_2->callback
+ && merged_callback->callback_data == merged_callback_2->callback_data;
+}
+
+static void
+merged_callback_destroy (MergedCallback *merged_callback)
+{
+ g_assert (merged_callback != NULL);
+ 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
+merged_callback_check_done (MergedCallback *merged_callback)
+{
+ /* Check if we are ready. */
+ if (merged_callback->non_ready_directories != NULL) {
+ return;
+ }
+
+ /* Remove from the hash table before sending it. */
+ 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,
+ merged_callback->callback_data);
+
+ /* And we are done. */
+ merged_callback_destroy (merged_callback);
+}
+
+static void
+merged_callback_remove_directory (MergedCallback *merged_callback,
+ NautilusDirectory *directory)
+{
+ merged_callback->non_ready_directories = g_list_remove
+ (merged_callback->non_ready_directories, directory);
+ merged_callback_check_done (merged_callback);
+}
+
+static void
+directory_ready_callback (NautilusDirectory *directory,
+ GList *files,
+ gpointer callback_data)
+{
+ MergedCallback *merged_callback;
+
+ g_assert (NAUTILUS_IS_DIRECTORY (directory));
+ g_assert (callback_data != NULL);
+
+ 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));
+
+ /* Check if we are ready. */
+ merged_callback_remove_directory (merged_callback, directory);
+}
+
+static void
+desktop_call_when_ready (NautilusDirectory *directory,
+ NautilusFileAttributes file_attributes,
+ gboolean wait_for_file_list,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ NautilusDesktopDirectory *desktop;
+ MergedCallback search_key, *merged_callback;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ /* Check to be sure we aren't overwriting. */
+ search_key.callback = callback;
+ search_key.callback_data = callback_data;
+ if (g_hash_table_lookup (desktop->details->callbacks, &search_key) != NULL) {
+ g_warning ("tried to add a new callback while an old one was pending");
+ return;
+ }
+
+ /* Create a merged_callback record. */
+ merged_callback = g_new0 (MergedCallback, 1);
+ 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;
+ 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));
+
+ /* Put it in the hash table. */
+ g_hash_table_insert (desktop->details->callbacks,
+ merged_callback, merged_callback);
+
+ /* Now tell all the directories about it. */
+ nautilus_directory_call_when_ready
+ (desktop->details->real_directory,
+ merged_callback->wait_for_attributes,
+ merged_callback->wait_for_file_list,
+ directory_ready_callback, merged_callback);
+ nautilus_directory_call_when_ready_internal
+ (directory,
+ NULL,
+ merged_callback->wait_for_attributes,
+ merged_callback->wait_for_file_list,
+ directory_ready_callback,
+ NULL,
+ merged_callback);
+
+}
+
+static void
+desktop_cancel_callback (NautilusDirectory *directory,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ NautilusDesktopDirectory *desktop;
+ MergedCallback search_key, *merged_callback;
+ GList *node;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ /* Find the entry in the table. */
+ search_key.callback = callback;
+ search_key.callback_data = callback_data;
+ merged_callback = g_hash_table_lookup (desktop->details->callbacks, &search_key);
+ if (merged_callback == NULL) {
+ return;
+ }
+
+ /* Remove from the hash table before working with it. */
+ g_hash_table_steal (merged_callback->desktop_dir->details->callbacks, merged_callback);
+
+ /* Tell all the directories to cancel the call. */
+ for (node = merged_callback->non_ready_directories; node != NULL; node = node->next) {
+ nautilus_directory_cancel_callback
+ (node->data,
+ directory_ready_callback, merged_callback);
+ }
+ merged_callback_destroy (merged_callback);
+}
+
+static void
+merged_monitor_destroy (MergedMonitor *monitor)
+{
+ NautilusDesktopDirectory *desktop;
+
+ desktop = monitor->desktop_dir;
+
+ /* Call through to the real directory remove calls. */
+ nautilus_directory_file_monitor_remove (desktop->details->real_directory, 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)
+{
+ GList **merged_list;
+
+ merged_list = callback_data;
+ *merged_list = g_list_concat (*merged_list,
+ nautilus_file_list_copy (file_list));
+}
+
+static void
+desktop_monitor_add (NautilusDirectory *directory,
+ gconstpointer client,
+ gboolean monitor_hidden_files,
+ NautilusFileAttributes file_attributes,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ NautilusDesktopDirectory *desktop;
+ MergedMonitor *monitor;
+ GList *merged_callback_list;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ /* Map the client to a unique value so this doesn't interfere
+ * with direct monitoring of the directory by the same client.
+ */
+ monitor = g_hash_table_lookup (desktop->details->monitors, client);
+ if (monitor != NULL) {
+ g_assert (monitor->desktop_dir == desktop);
+ } else {
+ monitor = g_new0 (MergedMonitor, 1);
+ monitor->desktop_dir = desktop;
+ g_hash_table_insert (desktop->details->monitors,
+ (gpointer) client, monitor);
+ }
+ monitor->monitor_hidden_files = monitor_hidden_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,
+ 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));
+
+
+ if (callback != NULL) {
+ (* callback) (directory, merged_callback_list, callback_data);
+ }
+ nautilus_file_list_free (merged_callback_list);
+}
+
+static void
+desktop_monitor_remove (NautilusDirectory *directory,
+ gconstpointer client)
+{
+ NautilusDesktopDirectory *desktop;
+ MergedMonitor *monitor;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ monitor = g_hash_table_lookup (desktop->details->monitors, client);
+ if (monitor == NULL) {
+ return;
+ }
+
+ g_hash_table_remove (desktop->details->monitors, client);
+}
+
+static void
+desktop_force_reload (NautilusDirectory *directory)
+{
+ NautilusDesktopDirectory *desktop;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ 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.) */
+}
+
+static gboolean
+desktop_are_all_files_seen (NautilusDirectory *directory)
+{
+ NautilusDesktopDirectory *desktop;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ if (!nautilus_directory_are_all_files_seen (desktop->details->real_directory)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+desktop_is_not_empty (NautilusDirectory *directory)
+{
+ NautilusDesktopDirectory *desktop;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (directory);
+
+ if (nautilus_directory_is_not_empty (desktop->details->real_directory)) {
+ return TRUE;
+ }
+
+ return directory->details->file_list != NULL;
+}
+
+static GList *
+desktop_get_file_list (NautilusDirectory *directory)
+{
+ GList *real_dir_file_list, *desktop_dir_file_list = NULL;
+
+ real_dir_file_list = nautilus_directory_get_file_list
+ (NAUTILUS_DESKTOP_DIRECTORY (directory)->details->real_directory);
+ desktop_dir_file_list = NAUTILUS_DIRECTORY_CLASS (nautilus_desktop_directory_parent_class)->get_file_list (directory);
+
+ return g_list_concat (real_dir_file_list, desktop_dir_file_list);
+}
+
+NautilusDirectory *
+nautilus_desktop_directory_get_real_directory (NautilusDesktopDirectory *desktop)
+{
+ nautilus_directory_ref (desktop->details->real_directory);
+ return desktop->details->real_directory;
+}
+
+
+static void
+desktop_finalize (GObject *object)
+{
+ NautilusDesktopDirectory *desktop;
+
+ desktop = NAUTILUS_DESKTOP_DIRECTORY (object);
+
+ nautilus_directory_unref (desktop->details->real_directory);
+
+ g_hash_table_destroy (desktop->details->callbacks);
+ g_hash_table_destroy (desktop->details->monitors);
+ g_free (desktop->details);
+
+ g_signal_handlers_disconnect_by_func (nautilus_preferences,
+ desktop_directory_changed_callback,
+ desktop);
+
+ G_OBJECT_CLASS (nautilus_desktop_directory_parent_class)->finalize (object);
+}
+
+static void
+done_loading_callback (NautilusDirectory *real_directory,
+ NautilusDesktopDirectory *desktop)
+{
+ nautilus_directory_emit_done_loading (NAUTILUS_DIRECTORY (desktop));
+}
+
+
+static void
+forward_files_added_cover (NautilusDirectory *real_directory,
+ GList *files,
+ gpointer callback_data)
+{
+ nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (callback_data), files);
+}
+
+static void
+forward_files_changed_cover (NautilusDirectory *real_directory,
+ GList *files,
+ gpointer callback_data)
+{
+ nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (callback_data), files);
+}
+
+static void
+update_desktop_directory (NautilusDesktopDirectory *desktop)
+{
+ char *desktop_path;
+ 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);
+
+ 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);
+ }
+
+ desktop_path = nautilus_get_desktop_directory ();
+ desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
+ real_directory = nautilus_directory_get_by_uri (desktop_uri);
+ g_free (desktop_uri);
+ g_free (desktop_path);
+
+ g_signal_connect_object (real_directory, "done-loading",
+ G_CALLBACK (done_loading_callback), desktop, 0);
+ g_signal_connect_object (real_directory, "files-added",
+ G_CALLBACK (forward_files_added_cover), desktop, 0);
+ g_signal_connect_object (real_directory, "files-changed",
+ G_CALLBACK (forward_files_changed_cover), desktop, 0);
+
+ desktop->details->real_directory = real_directory;
+}
+
+static NautilusFile *
+real_new_file_from_filename (NautilusDirectory *directory,
+ const char *filename,
+ gboolean self_owned)
+{
+ NautilusFile *file;
+
+ g_assert (NAUTILUS_IS_DIRECTORY (directory));
+ g_assert (filename != NULL);
+ g_assert (filename[0] != '\0');
+
+ if (self_owned) {
+ file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NULL));
+ } else {
+ g_critical ("Accessing desktop uris directly is not supported.");
+
+ return NULL;
+ }
+
+ nautilus_file_set_directory (file, directory);
+
+ return file;
+}
+
+static gboolean
+real_handles_location (GFile *location)
+{
+ g_autofree gchar *uri;
+
+ uri = g_file_get_uri (location);
+
+ return eel_uri_is_desktop (uri);
+}
+
+static void
+desktop_directory_changed_callback (gpointer data)
+{
+ update_desktop_directory (NAUTILUS_DESKTOP_DIRECTORY (data));
+ nautilus_directory_force_reload (NAUTILUS_DIRECTORY (data));
+}
+
+static void
+nautilus_desktop_directory_init (NautilusDesktopDirectory *desktop)
+{
+ desktop->details = g_new0 (NautilusDesktopDirectoryDetails, 1);
+
+ desktop->details->callbacks = g_hash_table_new_full
+ (merged_callback_hash, merged_callback_equal,
+ NULL, (GDestroyNotify)merged_callback_destroy);
+ desktop->details->monitors = g_hash_table_new_full (NULL, NULL,
+ NULL, (GDestroyNotify)merged_monitor_destroy);
+
+ update_desktop_directory (NAUTILUS_DESKTOP_DIRECTORY (desktop));
+}
+
+static void
+nautilus_desktop_directory_class_init (NautilusDesktopDirectoryClass *class)
+{
+ NautilusDirectoryClass *directory_class;
+
+ directory_class = NAUTILUS_DIRECTORY_CLASS (class);
+
+ G_OBJECT_CLASS (class)->finalize = desktop_finalize;
+
+ directory_class->contains_file = desktop_contains_file;
+ directory_class->call_when_ready = desktop_call_when_ready;
+ directory_class->cancel_callback = desktop_cancel_callback;
+ directory_class->file_monitor_add = desktop_monitor_add;
+ directory_class->file_monitor_remove = desktop_monitor_remove;
+ directory_class->force_reload = desktop_force_reload;
+ directory_class->are_all_files_seen = desktop_are_all_files_seen;
+ directory_class->is_not_empty = desktop_is_not_empty;
+ directory_class->new_file_from_filename = real_new_file_from_filename;
+ directory_class->handles_location = real_handles_location;
+ /* Override get_file_list so that we can return the list of files
+ * in NautilusDesktopDirectory->details->real_directory,
+ * in addition to the list of standard desktop icons on the desktop.
+ */
+ directory_class->get_file_list = desktop_get_file_list;
+}
+
diff --git a/nautilus-desktop/nautilus-desktop-directory.h b/nautilus-desktop/nautilus-desktop-directory.h
new file mode 100644
index 000000000..9e9dc4949
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-directory.h
@@ -0,0 +1,58 @@
+/*
+ nautilus-desktop-directory.h: Subclass of NautilusDirectory to implement
+ a virtual directory consisting of the desktop directory and the desktop
+ icons
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#ifndef NAUTILUS_DESKTOP_DIRECTORY_H
+#define NAUTILUS_DESKTOP_DIRECTORY_H
+
+#include <libnautilus-private/nautilus-directory.h>
+
+#define NAUTILUS_TYPE_DESKTOP_DIRECTORY nautilus_desktop_directory_get_type()
+#define NAUTILUS_DESKTOP_DIRECTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY, NautilusDesktopDirectory))
+#define NAUTILUS_DESKTOP_DIRECTORY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY, NautilusDesktopDirectoryClass))
+#define NAUTILUS_IS_DESKTOP_DIRECTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY))
+#define NAUTILUS_IS_DESKTOP_DIRECTORY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY))
+#define NAUTILUS_DESKTOP_DIRECTORY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY, NautilusDesktopDirectoryClass))
+
+#define NAUTILUS_DESKTOP_DIRECTORY_PROVIDER_NAME "desktop-directory-provider"
+
+typedef struct NautilusDesktopDirectoryDetails NautilusDesktopDirectoryDetails;
+
+typedef struct {
+ NautilusDirectory parent_slot;
+ NautilusDesktopDirectoryDetails *details;
+} NautilusDesktopDirectory;
+
+typedef struct {
+ NautilusDirectoryClass parent_slot;
+
+} NautilusDesktopDirectoryClass;
+
+GType nautilus_desktop_directory_get_type (void);
+NautilusDirectory * nautilus_desktop_directory_get_real_directory (NautilusDesktopDirectory *desktop_directory);
+
+#endif /* NAUTILUS_DESKTOP_DIRECTORY_H */
diff --git a/nautilus-desktop/nautilus-desktop-icon-file.c b/nautilus-desktop/nautilus-desktop-icon-file.c
new file mode 100644
index 000000000..073b81318
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-icon-file.c
@@ -0,0 +1,520 @@
+/*
+ nautilus-desktop-icon-file.c: Subclass of NautilusFile to help implement the
+ virtual desktop icons.
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#include <config.h>
+#include "nautilus-desktop-icon-file.h"
+#include "nautilus-desktop-metadata.h"
+#include "nautilus-desktop-directory-file.h"
+#include "nautilus-desktop-directory.h"
+
+#include <libnautilus-private/nautilus-directory-notify.h>
+#include <libnautilus-private/nautilus-directory-private.h>
+#include <libnautilus-private/nautilus-file-attributes.h>
+#include <libnautilus-private/nautilus-file-private.h>
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-file-operations.h>
+#include <libnautilus-private/nautilus-link.h>
+#include <libnautilus-private/nautilus-file-undo-manager.h>
+
+#include <eel/eel-glib-extensions.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include <gio/gio.h>
+
+struct NautilusDesktopIconFileDetails {
+ NautilusDesktopLink *link;
+};
+
+G_DEFINE_TYPE(NautilusDesktopIconFile, nautilus_desktop_icon_file, NAUTILUS_TYPE_FILE)
+
+
+static void
+desktop_icon_file_monitor_add (NautilusFile *file,
+ gconstpointer client,
+ NautilusFileAttributes attributes)
+{
+ nautilus_directory_monitor_add_internal
+ (file->details->directory, file,
+ client, TRUE, attributes, NULL, NULL);
+}
+
+static void
+desktop_icon_file_monitor_remove (NautilusFile *file,
+ gconstpointer client)
+{
+ nautilus_directory_monitor_remove_internal
+ (file->details->directory, file, client);
+}
+
+static void
+desktop_icon_file_call_when_ready (NautilusFile *file,
+ NautilusFileAttributes attributes,
+ NautilusFileCallback callback,
+ gpointer callback_data)
+{
+ nautilus_directory_call_when_ready_internal
+ (file->details->directory, file,
+ attributes, FALSE, NULL, callback, callback_data);
+}
+
+static void
+desktop_icon_file_cancel_call_when_ready (NautilusFile *file,
+ NautilusFileCallback callback,
+ gpointer callback_data)
+{
+ nautilus_directory_cancel_callback_internal
+ (file->details->directory, file,
+ NULL, callback, callback_data);
+}
+
+static gboolean
+desktop_icon_file_check_if_ready (NautilusFile *file,
+ NautilusFileAttributes attributes)
+{
+ return nautilus_directory_check_if_ready_internal
+ (file->details->directory, file,
+ attributes);
+}
+
+static gboolean
+desktop_icon_file_get_item_count (NautilusFile *file,
+ guint *count,
+ gboolean *count_unreadable)
+{
+ if (count != NULL) {
+ *count = 0;
+ }
+ if (count_unreadable != NULL) {
+ *count_unreadable = FALSE;
+ }
+ return TRUE;
+}
+
+static NautilusRequestStatus
+desktop_icon_file_get_deep_counts (NautilusFile *file,
+ guint *directory_count,
+ guint *file_count,
+ guint *unreadable_directory_count,
+ goffset *total_size)
+{
+ if (directory_count != NULL) {
+ *directory_count = 0;
+ }
+ if (file_count != NULL) {
+ *file_count = 0;
+ }
+ if (unreadable_directory_count != NULL) {
+ *unreadable_directory_count = 0;
+ }
+ if (total_size != NULL) {
+ *total_size = 0;
+ }
+
+ return NAUTILUS_REQUEST_DONE;
+}
+
+static gboolean
+desktop_icon_file_get_date (NautilusFile *file,
+ NautilusDateType date_type,
+ time_t *date)
+{
+ NautilusDesktopIconFile *desktop_file;
+
+ desktop_file = NAUTILUS_DESKTOP_ICON_FILE (file);
+
+ return nautilus_desktop_link_get_date (desktop_file->details->link,
+ date_type, date);
+}
+
+static char *
+desktop_icon_file_get_where_string (NautilusFile *file)
+{
+ return g_strdup (_("on the desktop"));
+}
+
+static void
+nautilus_desktop_icon_file_init (NautilusDesktopIconFile *desktop_file)
+{
+ desktop_file->details = G_TYPE_INSTANCE_GET_PRIVATE (desktop_file,
+ NAUTILUS_TYPE_DESKTOP_ICON_FILE,
+ NautilusDesktopIconFileDetails);
+}
+
+static void
+update_info_from_link (NautilusDesktopIconFile *icon_file)
+{
+ NautilusFile *file;
+ NautilusDesktopLink *link;
+ char *display_name;
+ GMount *mount;
+
+ file = NAUTILUS_FILE (icon_file);
+
+ link = icon_file->details->link;
+
+ if (link == NULL) {
+ return;
+ }
+
+ eel_ref_str_unref (file->details->mime_type);
+ file->details->mime_type = eel_ref_str_get_unique ("application/x-nautilus-link");
+ file->details->type = G_FILE_TYPE_SHORTCUT;
+ file->details->size = 0;
+ file->details->has_permissions = FALSE;
+ file->details->can_read = TRUE;
+ file->details->can_write = TRUE;
+
+ file->details->can_mount = FALSE;
+ file->details->can_unmount = FALSE;
+ file->details->can_eject = FALSE;
+ if (file->details->mount) {
+ g_object_unref (file->details->mount);
+ }
+ mount = nautilus_desktop_link_get_mount (link);
+ file->details->mount = mount;
+ if (mount) {
+ file->details->can_unmount = g_mount_can_unmount (mount);
+ file->details->can_eject = g_mount_can_eject (mount);
+ }
+
+ file->details->file_info_is_up_to_date = TRUE;
+
+ display_name = nautilus_desktop_link_get_display_name (link);
+ nautilus_file_set_display_name (file,
+ display_name, NULL, TRUE);
+ g_free (display_name);
+
+ if (file->details->icon != NULL) {
+ g_object_unref (file->details->icon);
+ }
+ file->details->icon = nautilus_desktop_link_get_icon (link);
+ g_free (file->details->activation_uri);
+ file->details->activation_uri = nautilus_desktop_link_get_activation_uri (link);
+ file->details->got_link_info = TRUE;
+ file->details->link_info_is_up_to_date = TRUE;
+
+ file->details->directory_count = 0;
+ file->details->got_directory_count = TRUE;
+ file->details->directory_count_is_up_to_date = TRUE;
+}
+
+void
+nautilus_desktop_icon_file_update (NautilusDesktopIconFile *icon_file)
+{
+ NautilusFile *file;
+
+ update_info_from_link (icon_file);
+ file = NAUTILUS_FILE (icon_file);
+ nautilus_file_changed (file);
+}
+
+void
+nautilus_desktop_icon_file_remove (NautilusDesktopIconFile *icon_file)
+{
+ NautilusFile *file;
+ GList list;
+
+ icon_file->details->link = NULL;
+
+ file = NAUTILUS_FILE (icon_file);
+
+ /* ref here because we might be removing the last ref when we
+ * mark the file gone below, but we need to keep a ref at
+ * least long enough to send the change notification.
+ */
+ nautilus_file_ref (file);
+
+ file->details->is_gone = TRUE;
+
+ list.data = file;
+ list.next = NULL;
+ list.prev = NULL;
+
+ nautilus_directory_remove_file (file->details->directory, file);
+ nautilus_directory_emit_change_signals (file->details->directory, &list);
+
+ nautilus_file_unref (file);
+}
+
+NautilusDesktopIconFile *
+nautilus_desktop_icon_file_new (NautilusDesktopLink *link)
+{
+ NautilusFile *file;
+ NautilusDirectory *directory;
+ NautilusDesktopIconFile *icon_file;
+ GList list;
+ char *name;
+
+ directory = nautilus_directory_get_by_uri (EEL_DESKTOP_URI);
+
+ file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_DESKTOP_ICON_FILE, NULL));
+
+#ifdef NAUTILUS_FILE_DEBUG_REF
+ printf("%10p ref'd\n", file);
+ eazel_dump_stack_trace ("\t", 10);
+#endif
+
+ nautilus_file_set_directory (file, directory);
+
+ icon_file = NAUTILUS_DESKTOP_ICON_FILE (file);
+ icon_file->details->link = link;
+
+ name = nautilus_desktop_link_get_file_name (link);
+ file->details->name = eel_ref_str_new (name);
+ g_free (name);
+
+ update_info_from_link (icon_file);
+
+ nautilus_desktop_update_metadata_from_keyfile (file, file->details->name);
+
+ nautilus_directory_add_file (directory, file);
+
+ list.data = file;
+ list.next = NULL;
+ list.prev = NULL;
+ nautilus_directory_emit_files_added (directory, &list);
+
+ return icon_file;
+}
+
+/* Note: This can return NULL if the link was recently removed (i.e. unmounted) */
+NautilusDesktopLink *
+nautilus_desktop_icon_file_get_link (NautilusDesktopIconFile *icon_file)
+{
+ if (icon_file->details->link)
+ return g_object_ref (icon_file->details->link);
+ else
+ return NULL;
+}
+
+static void
+nautilus_desktop_icon_file_unmount (NautilusFile *file,
+ GMountOperation *mount_op,
+ GCancellable *cancellable,
+ NautilusFileOperationCallback callback,
+ gpointer callback_data)
+{
+ NautilusDesktopIconFile *desktop_file;
+ GMount *mount;
+
+ desktop_file = NAUTILUS_DESKTOP_ICON_FILE (file);
+ if (desktop_file) {
+ mount = nautilus_desktop_link_get_mount (desktop_file->details->link);
+ if (mount != NULL) {
+ nautilus_file_operations_unmount_mount (NULL, mount, FALSE, TRUE);
+ }
+ }
+
+}
+
+static void
+nautilus_desktop_icon_file_eject (NautilusFile *file,
+ GMountOperation *mount_op,
+ GCancellable *cancellable,
+ NautilusFileOperationCallback callback,
+ gpointer callback_data)
+{
+ NautilusDesktopIconFile *desktop_file;
+ GMount *mount;
+
+ desktop_file = NAUTILUS_DESKTOP_ICON_FILE (file);
+ if (desktop_file) {
+ mount = nautilus_desktop_link_get_mount (desktop_file->details->link);
+ if (mount != NULL) {
+ nautilus_file_operations_unmount_mount (NULL, mount, TRUE, TRUE);
+ }
+ }
+}
+
+static char*
+real_get_target_uri (NautilusFile *file)
+{
+ char *uri = NULL;
+ GFile *location;
+ NautilusDesktopLink *link;
+
+ g_return_val_if_fail (NAUTILUS_IS_DESKTOP_ICON_FILE (file), NULL);
+
+ link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
+
+ if (link != NULL) {
+ location = nautilus_desktop_link_get_activation_location (link);
+ g_object_unref (link);
+ if (location != NULL) {
+ uri = g_file_get_uri (location);
+ g_object_unref (location);
+
+ return uri;
+ }
+ }
+
+ return NAUTILUS_FILE_CLASS (nautilus_desktop_icon_file_parent_class)->get_target_uri (file);
+}
+
+static void
+real_rename (NautilusFile *file,
+ const char *new_name,
+ NautilusFileOperationCallback callback,
+ gpointer callback_data)
+{
+ NautilusDesktopLink *link;
+ char *old_name;
+ gboolean success;
+ GError *error;
+
+ g_return_if_fail (NAUTILUS_IS_FILE (file));
+ g_return_if_fail (new_name != NULL);
+ g_return_if_fail (callback != NULL);
+
+ /* Can't rename a file that's already gone.
+ * We need to check this here because there may be a new
+ * file with the same name.
+ */
+ if (nautilus_file_rename_handle_file_gone (file, callback, callback_data)) {
+ return;
+ }
+
+ link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
+ old_name = nautilus_file_get_display_name (file);
+
+ if ((old_name != NULL && strcmp (new_name, old_name) == 0)) {
+ success = TRUE;
+ } else {
+ success = (link != NULL && nautilus_desktop_link_rename (link, new_name));
+ }
+
+ if (success) {
+ (* callback) (file, NULL, NULL, callback_data);
+ } else {
+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to rename desktop icon"));
+ (* callback) (file, NULL, error, callback_data);
+ g_error_free (error);
+ }
+
+ g_free (old_name);
+ g_object_unref (link);
+
+ return;
+}
+
+static gboolean
+real_can_rename (NautilusFile *file)
+{
+ NautilusDesktopLink *link;
+ gboolean can_rename;
+
+ can_rename = NAUTILUS_FILE_CLASS (nautilus_desktop_icon_file_parent_class)->can_rename (file);
+
+ if (!can_rename)
+ return FALSE;
+
+ link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
+
+ /* Certain types of links can't be renamed */
+ if (link != NULL) {
+ can_rename = nautilus_desktop_link_can_rename (link);
+ g_object_unref (link);
+ }
+
+ return can_rename;
+}
+
+static gboolean
+real_drag_can_accept_files (NautilusFile *drop_target_item)
+{
+ return TRUE;
+}
+
+static void
+real_invalidate_attributes_internal (NautilusFile *file,
+ NautilusFileAttributes attributes)
+{
+ /* Desktop icon files are always up to date.
+ * If we invalidate their attributes they
+ * will lose data, so we just ignore them.
+ */
+ return;
+}
+
+static gboolean
+real_opens_in_view (NautilusFile *file)
+{
+ return TRUE;
+}
+
+static gboolean
+real_is_special_link (NautilusFile *file)
+{
+ return TRUE;
+}
+
+static void
+nautilus_desktop_icon_file_set_metadata (NautilusFile *file,
+ const char *key,
+ const char *value)
+{
+ nautilus_desktop_set_metadata_string (file, file->details->name, key, value);
+}
+
+static void
+nautilus_desktop_icon_file_set_metadata_as_list (NautilusFile *file,
+ const char *key,
+ char **value)
+{
+ nautilus_desktop_set_metadata_stringv (file, file->details->name, key, (const gchar **) value);
+}
+
+static void
+nautilus_desktop_icon_file_class_init (NautilusDesktopIconFileClass *klass)
+{
+ GObjectClass *object_class;
+ NautilusFileClass *file_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ file_class = NAUTILUS_FILE_CLASS (klass);
+
+ file_class->default_file_type = G_FILE_TYPE_DIRECTORY;
+
+ file_class->monitor_add = desktop_icon_file_monitor_add;
+ file_class->monitor_remove = desktop_icon_file_monitor_remove;
+ file_class->call_when_ready = desktop_icon_file_call_when_ready;
+ file_class->cancel_call_when_ready = desktop_icon_file_cancel_call_when_ready;
+ file_class->check_if_ready = desktop_icon_file_check_if_ready;
+ file_class->get_item_count = desktop_icon_file_get_item_count;
+ file_class->get_deep_counts = desktop_icon_file_get_deep_counts;
+ file_class->get_date = desktop_icon_file_get_date;
+ file_class->get_where_string = desktop_icon_file_get_where_string;
+ file_class->set_metadata = nautilus_desktop_icon_file_set_metadata;
+ file_class->set_metadata_as_list = nautilus_desktop_icon_file_set_metadata_as_list;
+ file_class->unmount = nautilus_desktop_icon_file_unmount;
+ file_class->eject = nautilus_desktop_icon_file_eject;
+ file_class->can_rename = real_can_rename;
+ file_class->rename = real_rename;
+ file_class->get_target_uri = real_get_target_uri;
+ file_class->drag_can_accept_files = real_drag_can_accept_files;
+ file_class->invalidate_attributes_internal = real_invalidate_attributes_internal;
+ file_class->opens_in_view = real_opens_in_view;
+ file_class->is_special_link = real_is_special_link;
+
+ g_type_class_add_private (object_class, sizeof(NautilusDesktopIconFileDetails));
+}
diff --git a/nautilus-desktop/nautilus-desktop-icon-file.h b/nautilus-desktop/nautilus-desktop-icon-file.h
new file mode 100644
index 000000000..c65236531
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-icon-file.h
@@ -0,0 +1,60 @@
+/*
+ nautilus-desktop-file.h: Subclass of NautilusFile to implement the
+ the case of a desktop icon file
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#ifndef NAUTILUS_DESKTOP_ICON_FILE_H
+#define NAUTILUS_DESKTOP_ICON_FILE_H
+
+#include "nautilus-desktop-link.h"
+
+#include <libnautilus-private/nautilus-file.h>
+
+#define NAUTILUS_TYPE_DESKTOP_ICON_FILE nautilus_desktop_icon_file_get_type()
+#define NAUTILUS_DESKTOP_ICON_FILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_DESKTOP_ICON_FILE, NautilusDesktopIconFile))
+#define NAUTILUS_DESKTOP_ICON_FILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_ICON_FILE, NautilusDesktopIconFileClass))
+#define NAUTILUS_IS_DESKTOP_ICON_FILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_ICON_FILE))
+#define NAUTILUS_IS_DESKTOP_ICON_FILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_ICON_FILE))
+#define NAUTILUS_DESKTOP_ICON_FILE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_DESKTOP_ICON_FILE, NautilusDesktopIconFileClass))
+
+typedef struct NautilusDesktopIconFileDetails NautilusDesktopIconFileDetails;
+
+typedef struct {
+ NautilusFile parent_slot;
+ NautilusDesktopIconFileDetails *details;
+} NautilusDesktopIconFile;
+
+typedef struct {
+ NautilusFileClass parent_slot;
+} NautilusDesktopIconFileClass;
+
+GType nautilus_desktop_icon_file_get_type (void);
+
+NautilusDesktopIconFile *nautilus_desktop_icon_file_new (NautilusDesktopLink *link);
+void nautilus_desktop_icon_file_update (NautilusDesktopIconFile *icon_file);
+void nautilus_desktop_icon_file_remove (NautilusDesktopIconFile *icon_file);
+NautilusDesktopLink *nautilus_desktop_icon_file_get_link (NautilusDesktopIconFile *icon_file);
+
+#endif /* NAUTILUS_DESKTOP_ICON_FILE_H */
diff --git a/nautilus-desktop/nautilus-desktop-link-monitor.c b/nautilus-desktop/nautilus-desktop-link-monitor.c
new file mode 100644
index 000000000..54ce6daf9
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-link-monitor.c
@@ -0,0 +1,432 @@
+/*
+ nautilus-desktop-link-monitor.c: singleton thatn manages the links
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#include <config.h>
+#include "nautilus-desktop-link-monitor.h"
+#include "nautilus-desktop-link.h"
+#include "nautilus-desktop-icon-file.h"
+#include "nautilus-desktop-directory.h"
+
+#include <eel/eel-debug.h>
+#include <eel/eel-vfs-extensions.h>
+#include <eel/eel-stock-dialogs.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libnautilus-private/nautilus-trash-monitor.h>
+#include <libnautilus-private/nautilus-global-preferences.h>
+#include <libnautilus-private/nautilus-directory.h>
+
+#include <string.h>
+
+struct NautilusDesktopLinkMonitorDetails {
+ GVolumeMonitor *volume_monitor;
+ NautilusDirectory *desktop_dir;
+
+ NautilusDesktopLink *home_link;
+ NautilusDesktopLink *trash_link;
+ NautilusDesktopLink *network_link;
+
+ GList *mount_links;
+};
+
+G_DEFINE_TYPE (NautilusDesktopLinkMonitor, nautilus_desktop_link_monitor, G_TYPE_OBJECT);
+
+static NautilusDesktopLinkMonitor *the_link_monitor = NULL;
+
+void
+nautilus_desktop_link_monitor_shutdown (void)
+{
+ g_clear_object (&the_link_monitor);
+}
+
+NautilusDesktopLinkMonitor *
+nautilus_desktop_link_monitor_get (void)
+{
+ if (the_link_monitor == NULL) {
+ g_object_new (NAUTILUS_TYPE_DESKTOP_LINK_MONITOR, NULL);
+ eel_debug_call_at_shutdown (nautilus_desktop_link_monitor_shutdown);
+ }
+ return the_link_monitor;
+}
+
+static gboolean
+volume_file_name_used (NautilusDesktopLinkMonitor *monitor,
+ const char *name)
+{
+ GList *l;
+ char *other_name;
+ gboolean same;
+
+ for (l = monitor->details->mount_links; l != NULL; l = l->next) {
+ other_name = nautilus_desktop_link_get_file_name (l->data);
+ same = strcmp (name, other_name) == 0;
+ g_free (other_name);
+
+ if (same) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+char *
+nautilus_desktop_link_monitor_make_filename_unique (NautilusDesktopLinkMonitor *monitor,
+ const char *filename)
+{
+ char *unique_name;
+ int i;
+
+ i = 2;
+ unique_name = g_strdup (filename);
+ while (volume_file_name_used (monitor, unique_name)) {
+ g_free (unique_name);
+ unique_name = g_strdup_printf ("%s.%d", filename, i++);
+ }
+ return unique_name;
+}
+
+static gboolean
+has_mount (NautilusDesktopLinkMonitor *monitor,
+ GMount *mount)
+{
+ gboolean ret;
+ GMount *other_mount;
+ GList *l;
+
+ ret = FALSE;
+
+ for (l = monitor->details->mount_links; l != NULL; l = l->next) {
+ other_mount = nautilus_desktop_link_get_mount (l->data);
+ if (mount == other_mount) {
+ g_object_unref (other_mount);
+ ret = TRUE;
+ break;
+ }
+ g_object_unref (other_mount);
+ }
+
+ return ret;
+}
+
+static void
+create_mount_link (NautilusDesktopLinkMonitor *monitor,
+ GMount *mount)
+{
+ NautilusDesktopLink *link;
+
+ if (has_mount (monitor, mount))
+ return;
+
+ if ((!g_mount_is_shadowed (mount)) &&
+ g_settings_get_boolean (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE)) {
+ link = nautilus_desktop_link_new_from_mount (mount);
+ monitor->details->mount_links = g_list_prepend (monitor->details->mount_links, link);
+ }
+}
+
+static void
+remove_mount_link (NautilusDesktopLinkMonitor *monitor,
+ GMount *mount)
+{
+ GList *l;
+ NautilusDesktopLink *link;
+ GMount *other_mount;
+
+ link = NULL;
+ for (l = monitor->details->mount_links; l != NULL; l = l->next) {
+ other_mount = nautilus_desktop_link_get_mount (l->data);
+ if (mount == other_mount) {
+ g_object_unref (other_mount);
+ link = l->data;
+ break;
+ }
+ g_object_unref (other_mount);
+ }
+
+ if (link) {
+ monitor->details->mount_links = g_list_remove (monitor->details->mount_links, link);
+ g_object_unref (link);
+ }
+}
+
+
+
+static void
+mount_added_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ NautilusDesktopLinkMonitor *monitor)
+{
+ create_mount_link (monitor, mount);
+}
+
+
+static void
+mount_removed_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ NautilusDesktopLinkMonitor *monitor)
+{
+ remove_mount_link (monitor, mount);
+}
+
+static void
+mount_changed_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ NautilusDesktopLinkMonitor *monitor)
+{
+ /* TODO: update the mount with other details */
+
+ /* remove a mount if it goes into the shadows */
+ if (g_mount_is_shadowed (mount) && has_mount (monitor, mount)) {
+ remove_mount_link (monitor, mount);
+ }}
+
+static void
+update_link_visibility (NautilusDesktopLinkMonitor *monitor,
+ NautilusDesktopLink **link_ref,
+ NautilusDesktopLinkType link_type,
+ const char *preference_key)
+{
+ if (g_settings_get_boolean (nautilus_desktop_preferences, preference_key)) {
+ if (*link_ref == NULL) {
+ *link_ref = nautilus_desktop_link_new (link_type);
+ }
+ } else {
+ if (*link_ref != NULL) {
+ g_object_unref (*link_ref);
+ *link_ref = NULL;
+ }
+ }
+}
+
+static void
+desktop_home_visible_changed (gpointer callback_data)
+{
+ NautilusDesktopLinkMonitor *monitor;
+
+ monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data);
+
+ update_link_visibility (NAUTILUS_DESKTOP_LINK_MONITOR (monitor),
+ &monitor->details->home_link,
+ NAUTILUS_DESKTOP_LINK_HOME,
+ NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE);
+}
+
+static void
+desktop_trash_visible_changed (gpointer callback_data)
+{
+ NautilusDesktopLinkMonitor *monitor;
+
+ monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data);
+
+ update_link_visibility (NAUTILUS_DESKTOP_LINK_MONITOR (callback_data),
+ &monitor->details->trash_link,
+ NAUTILUS_DESKTOP_LINK_TRASH,
+ NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE);
+}
+
+static void
+desktop_network_visible_changed (gpointer callback_data)
+{
+ NautilusDesktopLinkMonitor *monitor;
+
+ monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data);
+
+ update_link_visibility (NAUTILUS_DESKTOP_LINK_MONITOR (callback_data),
+ &monitor->details->network_link,
+ NAUTILUS_DESKTOP_LINK_NETWORK,
+ NAUTILUS_PREFERENCES_DESKTOP_NETWORK_VISIBLE);
+}
+
+static void
+desktop_volumes_visible_changed (gpointer callback_data)
+{
+ NautilusDesktopLinkMonitor *monitor;
+ GList *l, *mounts;
+
+ monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data);
+
+ if (g_settings_get_boolean (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE)) {
+ if (monitor->details->mount_links == NULL) {
+ mounts = g_volume_monitor_get_mounts (monitor->details->volume_monitor);
+ for (l = mounts; l != NULL; l = l->next) {
+ create_mount_link (monitor, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free (mounts);
+ }
+ } else {
+ g_list_foreach (monitor->details->mount_links, (GFunc)g_object_unref, NULL);
+ g_list_free (monitor->details->mount_links);
+ monitor->details->mount_links = NULL;
+ }
+}
+
+static void
+create_link_and_add_preference (NautilusDesktopLink **link_ref,
+ NautilusDesktopLinkType link_type,
+ const char *preference_key,
+ GCallback callback,
+ gpointer callback_data)
+{
+ char *detailed_signal;
+
+ if (g_settings_get_boolean (nautilus_desktop_preferences, preference_key)) {
+ *link_ref = nautilus_desktop_link_new (link_type);
+ }
+
+ detailed_signal = g_strconcat ("changed::", preference_key, NULL);
+ g_signal_connect_swapped (nautilus_desktop_preferences,
+ detailed_signal,
+ callback, callback_data);
+
+ g_free (detailed_signal);
+}
+
+static void
+nautilus_desktop_link_monitor_init (NautilusDesktopLinkMonitor *monitor)
+{
+ GList *l, *mounts;
+ GMount *mount;
+
+ monitor->details = G_TYPE_INSTANCE_GET_PRIVATE (monitor, NAUTILUS_TYPE_DESKTOP_LINK_MONITOR,
+ NautilusDesktopLinkMonitorDetails);
+
+ the_link_monitor = monitor;
+ monitor->details->volume_monitor = g_volume_monitor_get ();
+
+ /* We keep around a ref to the desktop dir */
+ monitor->details->desktop_dir = nautilus_directory_get_by_uri (EEL_DESKTOP_URI);
+
+ /* Default links */
+
+ create_link_and_add_preference (&monitor->details->home_link,
+ NAUTILUS_DESKTOP_LINK_HOME,
+ NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE,
+ G_CALLBACK (desktop_home_visible_changed),
+ monitor);
+
+ create_link_and_add_preference (&monitor->details->trash_link,
+ NAUTILUS_DESKTOP_LINK_TRASH,
+ NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE,
+ G_CALLBACK (desktop_trash_visible_changed),
+ monitor);
+
+ create_link_and_add_preference (&monitor->details->network_link,
+ NAUTILUS_DESKTOP_LINK_NETWORK,
+ NAUTILUS_PREFERENCES_DESKTOP_NETWORK_VISIBLE,
+ G_CALLBACK (desktop_network_visible_changed),
+ monitor);
+
+ /* Mount links */
+
+ mounts = g_volume_monitor_get_mounts (monitor->details->volume_monitor);
+ for (l = mounts; l != NULL; l = l->next) {
+ mount = l->data;
+ create_mount_link (monitor, mount);
+ g_object_unref (mount);
+ }
+ g_list_free (mounts);
+
+ g_signal_connect_swapped (nautilus_desktop_preferences,
+ "changed::" NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE,
+ G_CALLBACK (desktop_volumes_visible_changed),
+ monitor);
+
+ g_signal_connect_object (monitor->details->volume_monitor, "mount-added",
+ G_CALLBACK (mount_added_callback), monitor, 0);
+ g_signal_connect_object (monitor->details->volume_monitor, "mount-removed",
+ G_CALLBACK (mount_removed_callback), monitor, 0);
+ g_signal_connect_object (monitor->details->volume_monitor, "mount-changed",
+ G_CALLBACK (mount_changed_callback), monitor, 0);
+}
+
+static void
+remove_link_and_preference (NautilusDesktopLink **link_ref,
+ const char *preference_key,
+ GCallback callback,
+ gpointer callback_data)
+{
+ if (*link_ref != NULL) {
+ g_object_unref (*link_ref);
+ *link_ref = NULL;
+ }
+
+ g_signal_handlers_disconnect_by_func (nautilus_desktop_preferences,
+ callback, callback_data);
+}
+
+static void
+desktop_link_monitor_finalize (GObject *object)
+{
+ NautilusDesktopLinkMonitor *monitor;
+
+ monitor = NAUTILUS_DESKTOP_LINK_MONITOR (object);
+
+ /* Default links */
+
+ remove_link_and_preference (&monitor->details->home_link,
+ NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE,
+ G_CALLBACK (desktop_home_visible_changed),
+ monitor);
+
+ remove_link_and_preference (&monitor->details->trash_link,
+ NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE,
+ G_CALLBACK (desktop_trash_visible_changed),
+ monitor);
+
+ remove_link_and_preference (&monitor->details->network_link,
+ NAUTILUS_PREFERENCES_DESKTOP_NETWORK_VISIBLE,
+ G_CALLBACK (desktop_network_visible_changed),
+ monitor);
+
+ /* Mounts */
+
+ g_list_foreach (monitor->details->mount_links, (GFunc)g_object_unref, NULL);
+ g_list_free (monitor->details->mount_links);
+ monitor->details->mount_links = NULL;
+
+ nautilus_directory_unref (monitor->details->desktop_dir);
+ monitor->details->desktop_dir = NULL;
+
+ g_signal_handlers_disconnect_by_func (nautilus_desktop_preferences,
+ desktop_volumes_visible_changed,
+ monitor);
+
+ g_object_unref (monitor->details->volume_monitor);
+
+ G_OBJECT_CLASS (nautilus_desktop_link_monitor_parent_class)->finalize (object);
+}
+
+static void
+nautilus_desktop_link_monitor_class_init (NautilusDesktopLinkMonitorClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = desktop_link_monitor_finalize;
+
+ g_type_class_add_private (klass, sizeof (NautilusDesktopLinkMonitorDetails));
+}
diff --git a/nautilus-desktop/nautilus-desktop-link-monitor.h b/nautilus-desktop/nautilus-desktop-link-monitor.h
new file mode 100644
index 000000000..304f23910
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-link-monitor.h
@@ -0,0 +1,60 @@
+/*
+ nautilus-desktop-link-monitor.h: singleton that manages the desktop links
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#ifndef NAUTILUS_DESKTOP_LINK_MONITOR_H
+#define NAUTILUS_DESKTOP_LINK_MONITOR_H
+
+#include <gtk/gtk.h>
+#include "nautilus-desktop-link.h"
+
+#define NAUTILUS_TYPE_DESKTOP_LINK_MONITOR nautilus_desktop_link_monitor_get_type()
+#define NAUTILUS_DESKTOP_LINK_MONITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR, NautilusDesktopLinkMonitor))
+#define NAUTILUS_DESKTOP_LINK_MONITOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR, NautilusDesktopLinkMonitorClass))
+#define NAUTILUS_IS_DESKTOP_LINK_MONITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR))
+#define NAUTILUS_IS_DESKTOP_LINK_MONITOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR))
+#define NAUTILUS_DESKTOP_LINK_MONITOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR, NautilusDesktopLinkMonitorClass))
+
+typedef struct NautilusDesktopLinkMonitorDetails NautilusDesktopLinkMonitorDetails;
+
+typedef struct {
+ GObject parent_slot;
+ NautilusDesktopLinkMonitorDetails *details;
+} NautilusDesktopLinkMonitor;
+
+typedef struct {
+ GObjectClass parent_slot;
+} NautilusDesktopLinkMonitorClass;
+
+GType nautilus_desktop_link_monitor_get_type (void);
+
+NautilusDesktopLinkMonitor * nautilus_desktop_link_monitor_get (void);
+void nautilus_desktop_link_monitor_shutdown (void);
+
+/* Used by nautilus-desktop-link.c */
+char * nautilus_desktop_link_monitor_make_filename_unique (NautilusDesktopLinkMonitor *monitor,
+ const char *filename);
+
+#endif /* NAUTILUS_DESKTOP_LINK_MONITOR_H */
diff --git a/nautilus-desktop/nautilus-desktop-link.c b/nautilus-desktop/nautilus-desktop-link.c
new file mode 100644
index 000000000..df2566361
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-link.c
@@ -0,0 +1,436 @@
+/*
+ nautilus-desktop-link.c: Class that handles the links on the desktop
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#include <config.h>
+
+#include "nautilus-desktop-link.h"
+#include "nautilus-desktop-link-monitor.h"
+#include "nautilus-desktop-icon-file.h"
+#include "nautilus-directory-private.h"
+#include "nautilus-desktop-directory.h"
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-trash-monitor.h>
+#include <libnautilus-private/nautilus-global-preferences.h>
+#include <libnautilus-private/nautilus-icon-names.h>
+
+#include <string.h>
+
+struct NautilusDesktopLinkDetails {
+ NautilusDesktopLinkType type;
+ char *filename;
+ char *display_name;
+ GFile *activation_location;
+ GIcon *icon;
+
+ NautilusDesktopIconFile *icon_file;
+
+ /* Just for mount icons: */
+ GMount *mount;
+};
+
+G_DEFINE_TYPE(NautilusDesktopLink, nautilus_desktop_link, G_TYPE_OBJECT)
+
+static void
+create_icon_file (NautilusDesktopLink *link)
+{
+ link->details->icon_file = nautilus_desktop_icon_file_new (link);
+}
+
+static void
+nautilus_desktop_link_changed (NautilusDesktopLink *link)
+{
+ if (link->details->icon_file != NULL) {
+ nautilus_desktop_icon_file_update (link->details->icon_file);
+ }
+}
+
+static void
+mount_changed_callback (GMount *mount, NautilusDesktopLink *link)
+{
+ g_free (link->details->display_name);
+ if (link->details->activation_location) {
+ g_object_unref (link->details->activation_location);
+ }
+ if (link->details->icon) {
+ g_object_unref (link->details->icon);
+ }
+
+ link->details->display_name = g_mount_get_name (mount);
+ link->details->activation_location = g_mount_get_default_location (mount);
+ link->details->icon = g_mount_get_icon (mount);
+
+ nautilus_desktop_link_changed (link);
+}
+
+static GIcon *
+get_desktop_trash_icon (void)
+{
+ const gchar *icon_name;
+
+ if (nautilus_trash_monitor_is_empty ()) {
+ icon_name = NAUTILUS_DESKTOP_ICON_TRASH;
+ } else {
+ icon_name = NAUTILUS_DESKTOP_ICON_TRASH_FULL;
+ }
+
+ return g_themed_icon_new (icon_name);
+}
+
+static void
+trash_state_changed_callback (NautilusTrashMonitor *trash_monitor,
+ gboolean state,
+ gpointer callback_data)
+{
+ NautilusDesktopLink *link;
+
+ link = NAUTILUS_DESKTOP_LINK (callback_data);
+ g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_TRASH);
+
+ if (link->details->icon) {
+ g_object_unref (link->details->icon);
+ }
+ link->details->icon = get_desktop_trash_icon ();
+
+ nautilus_desktop_link_changed (link);
+}
+
+static void
+home_name_changed (gpointer callback_data)
+{
+ NautilusDesktopLink *link;
+
+ link = NAUTILUS_DESKTOP_LINK (callback_data);
+ g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_HOME);
+
+ g_free (link->details->display_name);
+ link->details->display_name = g_settings_get_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME);
+ if (link->details->display_name[0] == 0) {
+ g_free (link->details->display_name);
+ link->details->display_name = g_strdup (_("Home"));
+ }
+
+ nautilus_desktop_link_changed (link);
+}
+
+static void
+trash_name_changed (gpointer callback_data)
+{
+ NautilusDesktopLink *link;
+
+ link = NAUTILUS_DESKTOP_LINK (callback_data);
+ g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_TRASH);
+
+ g_free (link->details->display_name);
+ link->details->display_name = g_settings_get_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME);
+ nautilus_desktop_link_changed (link);
+}
+
+static void
+network_name_changed (gpointer callback_data)
+{
+ NautilusDesktopLink *link;
+
+ link = NAUTILUS_DESKTOP_LINK (callback_data);
+ g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_NETWORK);
+
+ g_free (link->details->display_name);
+ link->details->display_name = g_settings_get_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_NETWORK_NAME);
+ nautilus_desktop_link_changed (link);
+}
+
+NautilusDesktopLink *
+nautilus_desktop_link_new (NautilusDesktopLinkType type)
+{
+ NautilusDesktopLink *link;
+
+ link = NAUTILUS_DESKTOP_LINK (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK, NULL));
+
+ link->details->type = type;
+ switch (type) {
+ case NAUTILUS_DESKTOP_LINK_HOME:
+ link->details->filename = g_strdup ("home");
+ link->details->display_name = g_settings_get_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME);
+ link->details->activation_location = g_file_new_for_path (g_get_home_dir ());
+ link->details->icon = g_themed_icon_new (NAUTILUS_DESKTOP_ICON_HOME);
+
+ g_signal_connect_swapped (nautilus_desktop_preferences,
+ "changed::" NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME,
+ G_CALLBACK (home_name_changed),
+ link);
+ break;
+
+ case NAUTILUS_DESKTOP_LINK_TRASH:
+ link->details->filename = g_strdup ("trash");
+ link->details->display_name = g_settings_get_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME);
+ link->details->activation_location = g_file_new_for_uri (EEL_TRASH_URI);
+ link->details->icon = get_desktop_trash_icon ();
+
+ g_signal_connect_swapped (nautilus_desktop_preferences,
+ "changed::" NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME,
+ G_CALLBACK (trash_name_changed),
+ link);
+ g_signal_connect_object (nautilus_trash_monitor_get (), "trash-state-changed",
+ G_CALLBACK (trash_state_changed_callback), link, 0);
+ break;
+
+ case NAUTILUS_DESKTOP_LINK_NETWORK:
+ link->details->filename = g_strdup ("network");
+ link->details->display_name = g_settings_get_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_NETWORK_NAME);
+ link->details->activation_location = g_file_new_for_uri ("network:///");
+ link->details->icon = g_themed_icon_new (NAUTILUS_DESKTOP_ICON_NETWORK);
+
+ g_signal_connect_swapped (nautilus_desktop_preferences,
+ "changed::" NAUTILUS_PREFERENCES_DESKTOP_NETWORK_NAME,
+ G_CALLBACK (network_name_changed),
+ link);
+ break;
+
+ default:
+ case NAUTILUS_DESKTOP_LINK_MOUNT:
+ g_assert_not_reached();
+ }
+
+ create_icon_file (link);
+
+ return link;
+}
+
+NautilusDesktopLink *
+nautilus_desktop_link_new_from_mount (GMount *mount)
+{
+ NautilusDesktopLink *link;
+ GVolume *volume;
+ char *name, *filename;
+
+ link = NAUTILUS_DESKTOP_LINK (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK, NULL));
+
+ link->details->type = NAUTILUS_DESKTOP_LINK_MOUNT;
+
+ link->details->mount = g_object_ref (mount);
+
+ /* We try to use the drive name to get somewhat stable filenames
+ for metadata */
+ volume = g_mount_get_volume (mount);
+ if (volume != NULL) {
+ name = g_volume_get_name (volume);
+ g_object_unref (volume);
+ } else {
+ name = g_mount_get_name (mount);
+ }
+
+ /* Replace slashes in name */
+ filename = g_strconcat (g_strdelimit (name, "/", '-'), ".volume", NULL);
+ link->details->filename =
+ nautilus_desktop_link_monitor_make_filename_unique (nautilus_desktop_link_monitor_get (),
+ filename);
+ g_free (filename);
+ g_free (name);
+
+ link->details->display_name = g_mount_get_name (mount);
+
+ link->details->activation_location = g_mount_get_default_location (mount);
+ link->details->icon = g_mount_get_icon (mount);
+
+ g_signal_connect_object (mount, "changed",
+ G_CALLBACK (mount_changed_callback), link, 0);
+
+ create_icon_file (link);
+
+ return link;
+}
+
+GMount *
+nautilus_desktop_link_get_mount (NautilusDesktopLink *link)
+{
+ if (link->details->mount) {
+ return g_object_ref (link->details->mount);
+ }
+ return NULL;
+}
+
+NautilusDesktopLinkType
+nautilus_desktop_link_get_link_type (NautilusDesktopLink *link)
+{
+ return link->details->type;
+}
+
+char *
+nautilus_desktop_link_get_file_name (NautilusDesktopLink *link)
+{
+ return g_strdup (link->details->filename);
+}
+
+char *
+nautilus_desktop_link_get_display_name (NautilusDesktopLink *link)
+{
+ return g_strdup (link->details->display_name);
+}
+
+GIcon *
+nautilus_desktop_link_get_icon (NautilusDesktopLink *link)
+{
+ if (link->details->icon != NULL) {
+ return g_object_ref (link->details->icon);
+ }
+ return NULL;
+}
+
+GFile *
+nautilus_desktop_link_get_activation_location (NautilusDesktopLink *link)
+{
+ if (link->details->activation_location) {
+ return g_object_ref (link->details->activation_location);
+ }
+ return NULL;
+}
+
+char *
+nautilus_desktop_link_get_activation_uri (NautilusDesktopLink *link)
+{
+ if (link->details->activation_location) {
+ return g_file_get_uri (link->details->activation_location);
+ }
+ return NULL;
+}
+
+
+gboolean
+nautilus_desktop_link_get_date (NautilusDesktopLink *link,
+ NautilusDateType date_type,
+ time_t *date)
+{
+ return FALSE;
+}
+
+gboolean
+nautilus_desktop_link_can_rename (NautilusDesktopLink *link)
+{
+ return (link->details->type == NAUTILUS_DESKTOP_LINK_HOME ||
+ link->details->type == NAUTILUS_DESKTOP_LINK_TRASH ||
+ link->details->type == NAUTILUS_DESKTOP_LINK_NETWORK);
+}
+
+gboolean
+nautilus_desktop_link_rename (NautilusDesktopLink *link,
+ const char *name)
+{
+ switch (link->details->type) {
+ case NAUTILUS_DESKTOP_LINK_HOME:
+ g_settings_set_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME,
+ name);
+ break;
+ case NAUTILUS_DESKTOP_LINK_TRASH:
+ g_settings_set_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME,
+ name);
+ break;
+ case NAUTILUS_DESKTOP_LINK_NETWORK:
+ g_settings_set_string (nautilus_desktop_preferences,
+ NAUTILUS_PREFERENCES_DESKTOP_NETWORK_NAME,
+ name);
+ break;
+ default:
+ g_assert_not_reached ();
+ /* FIXME: Do we want volume renaming?
+ * We didn't support that before. */
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+nautilus_desktop_link_init (NautilusDesktopLink *link)
+{
+ link->details = G_TYPE_INSTANCE_GET_PRIVATE (link,
+ NAUTILUS_TYPE_DESKTOP_LINK,
+ NautilusDesktopLinkDetails);
+}
+
+static void
+desktop_link_finalize (GObject *object)
+{
+ NautilusDesktopLink *link;
+
+ link = NAUTILUS_DESKTOP_LINK (object);
+
+ if (link->details->icon_file != NULL) {
+ nautilus_desktop_icon_file_remove (link->details->icon_file);
+ nautilus_file_unref (NAUTILUS_FILE (link->details->icon_file));
+ link->details->icon_file = NULL;
+ }
+
+ if (link->details->type == NAUTILUS_DESKTOP_LINK_HOME) {
+ g_signal_handlers_disconnect_by_func (nautilus_desktop_preferences,
+ home_name_changed,
+ link);
+ }
+
+ if (link->details->type == NAUTILUS_DESKTOP_LINK_TRASH) {
+ g_signal_handlers_disconnect_by_func (nautilus_desktop_preferences,
+ trash_name_changed,
+ link);
+ }
+
+ if (link->details->type == NAUTILUS_DESKTOP_LINK_NETWORK) {
+ g_signal_handlers_disconnect_by_func (nautilus_desktop_preferences,
+ network_name_changed,
+ link);
+ }
+
+ if (link->details->type == NAUTILUS_DESKTOP_LINK_MOUNT) {
+ g_object_unref (link->details->mount);
+ }
+
+ g_free (link->details->filename);
+ g_free (link->details->display_name);
+ if (link->details->activation_location) {
+ g_object_unref (link->details->activation_location);
+ }
+ if (link->details->icon) {
+ g_object_unref (link->details->icon);
+ }
+
+ G_OBJECT_CLASS (nautilus_desktop_link_parent_class)->finalize (object);
+}
+
+static void
+nautilus_desktop_link_class_init (NautilusDesktopLinkClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = desktop_link_finalize;
+
+ g_type_class_add_private (object_class, sizeof(NautilusDesktopLinkDetails));
+}
diff --git a/nautilus-desktop/nautilus-desktop-link.h b/nautilus-desktop/nautilus-desktop-link.h
new file mode 100644
index 000000000..7c1025b40
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-link.h
@@ -0,0 +1,77 @@
+/*
+ nautilus-desktop-link.h: Class that handles the links on the desktop
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#ifndef NAUTILUS_DESKTOP_LINK_H
+#define NAUTILUS_DESKTOP_LINK_H
+
+#include <libnautilus-private/nautilus-file.h>
+#include <gio/gio.h>
+
+#define NAUTILUS_TYPE_DESKTOP_LINK nautilus_desktop_link_get_type()
+#define NAUTILUS_DESKTOP_LINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_DESKTOP_LINK, NautilusDesktopLink))
+#define NAUTILUS_DESKTOP_LINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_LINK, NautilusDesktopLinkClass))
+#define NAUTILUS_IS_DESKTOP_LINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_LINK))
+#define NAUTILUS_IS_DESKTOP_LINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_LINK))
+#define NAUTILUS_DESKTOP_LINK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_DESKTOP_LINK, NautilusDesktopLinkClass))
+
+typedef struct NautilusDesktopLinkDetails NautilusDesktopLinkDetails;
+
+typedef struct {
+ GObject parent_slot;
+ NautilusDesktopLinkDetails *details;
+} NautilusDesktopLink;
+
+typedef struct {
+ GObjectClass parent_slot;
+} NautilusDesktopLinkClass;
+
+typedef enum {
+ NAUTILUS_DESKTOP_LINK_HOME,
+ NAUTILUS_DESKTOP_LINK_TRASH,
+ NAUTILUS_DESKTOP_LINK_MOUNT,
+ NAUTILUS_DESKTOP_LINK_NETWORK
+} NautilusDesktopLinkType;
+
+GType nautilus_desktop_link_get_type (void);
+
+NautilusDesktopLink * nautilus_desktop_link_new (NautilusDesktopLinkType type);
+NautilusDesktopLink * nautilus_desktop_link_new_from_mount (GMount *mount);
+NautilusDesktopLinkType nautilus_desktop_link_get_link_type (NautilusDesktopLink *link);
+char * nautilus_desktop_link_get_file_name (NautilusDesktopLink *link);
+char * nautilus_desktop_link_get_display_name (NautilusDesktopLink *link);
+GIcon * nautilus_desktop_link_get_icon (NautilusDesktopLink *link);
+GFile * nautilus_desktop_link_get_activation_location (NautilusDesktopLink *link);
+char * nautilus_desktop_link_get_activation_uri (NautilusDesktopLink *link);
+gboolean nautilus_desktop_link_get_date (NautilusDesktopLink *link,
+ NautilusDateType date_type,
+ time_t *date);
+GMount * nautilus_desktop_link_get_mount (NautilusDesktopLink *link);
+gboolean nautilus_desktop_link_can_rename (NautilusDesktopLink *link);
+gboolean nautilus_desktop_link_rename (NautilusDesktopLink *link,
+ const char *name);
+
+
+#endif /* NAUTILUS_DESKTOP_LINK_H */
diff --git a/nautilus-desktop/nautilus-desktop-metadata.c b/nautilus-desktop/nautilus-desktop-metadata.c
new file mode 100644
index 000000000..91a120095
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-metadata.c
@@ -0,0 +1,90 @@
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * Nautilus is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; see the file COPYING. If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Cosimo Cecchi <cosimoc@redhat.com>
+ */
+
+#include <config.h>
+
+#include "nautilus-desktop-metadata.h"
+
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-keyfile-metadata.h>
+
+static gchar *
+get_keyfile_path (void)
+{
+ gchar *xdg_dir, *retval;
+
+ xdg_dir = nautilus_get_user_directory ();
+ retval = g_build_filename (xdg_dir, "desktop-metadata", NULL);
+
+ g_free (xdg_dir);
+
+ return retval;
+}
+
+void
+nautilus_desktop_set_metadata_string (NautilusFile *file,
+ const gchar *name,
+ const gchar *key,
+ const gchar *string)
+{
+ gchar *keyfile_filename;
+
+ keyfile_filename = get_keyfile_path ();
+
+ nautilus_keyfile_metadata_set_string (file, keyfile_filename,
+ name, key, string);
+
+ g_free (keyfile_filename);
+}
+
+void
+nautilus_desktop_set_metadata_stringv (NautilusFile *file,
+ const char *name,
+ const char *key,
+ const char * const *stringv)
+{
+ gchar *keyfile_filename;
+
+ keyfile_filename = get_keyfile_path ();
+
+ nautilus_keyfile_metadata_set_stringv (file, keyfile_filename,
+ name, key, stringv);
+
+ g_free (keyfile_filename);
+}
+
+gboolean
+nautilus_desktop_update_metadata_from_keyfile (NautilusFile *file,
+ const gchar *name)
+{
+ gchar *keyfile_filename;
+ gboolean result;
+
+ keyfile_filename = get_keyfile_path ();
+
+ result = nautilus_keyfile_metadata_update_from_keyfile (file,
+ keyfile_filename,
+ name);
+
+ g_free (keyfile_filename);
+ return result;
+}
diff --git a/nautilus-desktop/nautilus-desktop-metadata.h b/nautilus-desktop/nautilus-desktop-metadata.h
new file mode 100644
index 000000000..f8c67d3cf
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-metadata.h
@@ -0,0 +1,43 @@
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * Nautilus is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; see the file COPYING. If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Cosimo Cecchi <cosimoc@redhat.com>
+ */
+
+#ifndef __NAUTILUS_DESKTOP_METADATA_H__
+#define __NAUTILUS_DESKTOP_METADATA_H__
+
+#include <glib.h>
+
+#include <libnautilus-private/nautilus-file.h>
+
+void nautilus_desktop_set_metadata_string (NautilusFile *file,
+ const gchar *name,
+ const gchar *key,
+ const gchar *string);
+
+void nautilus_desktop_set_metadata_stringv (NautilusFile *file,
+ const char *name,
+ const char *key,
+ const char * const *stringv);
+
+gboolean nautilus_desktop_update_metadata_from_keyfile (NautilusFile *file,
+ const gchar *name);
+
+#endif /* __NAUTILUS_DESKTOP_METADATA_H__ */
diff --git a/nautilus-desktop/nautilus-desktop-window-slot.c b/nautilus-desktop/nautilus-desktop-window-slot.c
new file mode 100644
index 000000000..d1c05e7fc
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-window-slot.c
@@ -0,0 +1,67 @@
+/* nautilus-desktop-window-slot.c
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano@gnome.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-desktop-window-slot.h"
+#include "nautilus-desktop-canvas-view.h"
+
+struct _NautilusDesktopWindowSlot
+{
+ NautilusWindowSlot parent_instance;
+};
+
+G_DEFINE_TYPE (NautilusDesktopWindowSlot, nautilus_desktop_window_slot, NAUTILUS_TYPE_WINDOW_SLOT)
+
+static NautilusView *
+real_get_view_for_location (NautilusWindowSlot *self,
+ GFile *location)
+{
+ return NAUTILUS_VIEW (nautilus_desktop_canvas_view_new (self));
+}
+
+NautilusDesktopWindowSlot *
+nautilus_desktop_window_slot_new (NautilusWindow *window)
+{
+ return g_object_new (NAUTILUS_TYPE_DESKTOP_WINDOW_SLOT,
+ "window", window,
+ NULL);
+}
+
+static void
+nautilus_desktop_window_slot_class_init (NautilusDesktopWindowSlotClass *klass)
+{
+ NautilusWindowSlotClass *parent_class = NAUTILUS_WINDOW_SLOT_CLASS (klass);
+
+ parent_class->get_view_for_location = real_get_view_for_location;
+}
+
+static void
+nautilus_desktop_window_slot_init (NautilusDesktopWindowSlot *self)
+{
+ GAction *action;
+ GActionGroup *action_group;
+
+ /* Disable search on desktop */
+ action_group = gtk_widget_get_action_group (GTK_WIDGET (self), "slot");
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "search-visible");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ /* Disable the ability to change between types of views */
+ action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "files-view-mode");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+}
diff --git a/nautilus-desktop/nautilus-desktop-window-slot.h b/nautilus-desktop/nautilus-desktop-window-slot.h
new file mode 100644
index 000000000..fcc64afba
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-window-slot.h
@@ -0,0 +1,36 @@
+/* nautilus-window-desktop-slot.h
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano@gnome.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef NAUTILUS_DESKTOP_WINDOW_SLOT_H
+#define NAUTILUS_DESKTOP_WINDOW_SLOT_H
+
+#include <src/nautilus-window-slot.h>
+#include <src/nautilus-window.h>
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_DESKTOP_WINDOW_SLOT (nautilus_desktop_window_slot_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusDesktopWindowSlot, nautilus_desktop_window_slot, NAUTILUS, DESKTOP_WINDOW_SLOT, NautilusWindowSlot)
+
+
+NautilusDesktopWindowSlot *nautilus_desktop_window_slot_new (NautilusWindow *window);
+
+G_END_DECLS
+
+#endif /* NAUTILUS_DESKTOP_WINDOW_SLOT_H */
+
diff --git a/nautilus-desktop/nautilus-desktop-window.c b/nautilus-desktop/nautilus-desktop-window.c
new file mode 100644
index 000000000..3e361be80
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-window.c
@@ -0,0 +1,416 @@
+
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2000 Eazel, Inc.
+ *
+ * Nautilus is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Darin Adler <darin@bentspoon.com>
+ */
+
+#include <config.h>
+
+#include "nautilus-desktop-window.h"
+#include "nautilus-desktop-window-slot.h"
+#include "nautilus-desktop-link-monitor.h"
+
+#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+
+#include <eel/eel-vfs-extensions.h>
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-icon-names.h>
+#include <libnautilus-private/nautilus-global-preferences.h>
+#include <src/nautilus-window.h>
+#include <src/nautilus-application.h>
+
+struct NautilusDesktopWindowDetails {
+ gulong size_changed_id;
+
+ gboolean loaded;
+
+ GtkWidget *desktop_selection;
+};
+
+G_DEFINE_TYPE (NautilusDesktopWindow, nautilus_desktop_window,
+ NAUTILUS_TYPE_WINDOW);
+
+static void
+nautilus_desktop_window_update_directory (NautilusDesktopWindow *window)
+{
+ GFile *location;
+
+ g_assert (NAUTILUS_IS_DESKTOP_WINDOW (window));
+
+ window->details->loaded = FALSE;
+ location = g_file_new_for_uri (EEL_DESKTOP_URI);
+ /* We use NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE so the nautilus-window
+ * doesn't call gtk_window_present () which raises the window on the stack
+ * and actually hides it from the background */
+ nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
+ location,
+ NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE,
+ NULL, NAUTILUS_WINDOW (window), NULL);
+ window->details->loaded = TRUE;
+
+ g_object_unref (location);
+}
+
+static void
+nautilus_desktop_window_finalize (GObject *obj)
+{
+ nautilus_desktop_link_monitor_shutdown ();
+
+ G_OBJECT_CLASS (nautilus_desktop_window_parent_class)->finalize (obj);
+}
+
+static void
+nautilus_desktop_window_init_actions (NautilusDesktopWindow *window)
+{
+ GAction *action;
+
+ /* Don't allow close action on desktop */
+ action = g_action_map_lookup_action (G_ACTION_MAP (window),
+ "close-current-view");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ /* Don't allow new tab on desktop */
+ action = g_action_map_lookup_action (G_ACTION_MAP (window),
+ "new-tab");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+
+ /* Don't allow switching to home dir on desktop */
+ action = g_action_map_lookup_action (G_ACTION_MAP (window),
+ "go-home");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+}
+
+static void
+selection_get_cb (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ /* No extra targets atm */
+}
+
+static gboolean
+selection_clear_event_cb (GtkWidget *widget,
+ GdkEventSelection *event,
+ NautilusDesktopWindow *window)
+{
+ gtk_widget_destroy (GTK_WIDGET (window));
+
+ return TRUE;
+}
+
+static void
+nautilus_desktop_window_init_selection (NautilusDesktopWindow *window)
+{
+ char selection_name[32];
+ GdkAtom selection_atom;
+ Window selection_owner;
+ GdkDisplay *display;
+ GtkWidget *selection_widget;
+ GdkScreen *screen;
+
+ screen = gdk_screen_get_default ();
+
+ g_snprintf (selection_name, sizeof (selection_name),
+ "_NET_DESKTOP_MANAGER_S%d", gdk_screen_get_number (screen));
+ selection_atom = gdk_atom_intern (selection_name, FALSE);
+ display = gdk_screen_get_display (screen);
+
+ selection_owner = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
+ gdk_x11_atom_to_xatom_for_display (display,
+ selection_atom));
+ if (selection_owner != None) {
+ g_critical ("Another desktop manager in use; desktop window won't be created");
+ return;
+ }
+
+ selection_widget = gtk_invisible_new_for_screen (screen);
+ /* We need this for gdk_x11_get_server_time() */
+ gtk_widget_add_events (selection_widget, GDK_PROPERTY_CHANGE_MASK);
+
+ if (!gtk_selection_owner_set_for_display (display,
+ selection_widget,
+ selection_atom,
+ gdk_x11_get_server_time (gtk_widget_get_window (selection_widget)))) {
+ gtk_widget_destroy (selection_widget);
+ g_critical ("Can't set ourselves as selection owner for desktop manager; "
+ "desktop window won't be created");
+ return;
+ }
+
+ g_signal_connect (selection_widget, "selection-get",
+ G_CALLBACK (selection_get_cb), window);
+ g_signal_connect (selection_widget, "selection-clear-event",
+ G_CALLBACK (selection_clear_event_cb), window);
+
+ window->details->desktop_selection = selection_widget;
+}
+
+static void
+nautilus_desktop_window_constructed (GObject *obj)
+{
+ AtkObject *accessible;
+ NautilusDesktopWindow *window = NAUTILUS_DESKTOP_WINDOW (obj);
+
+ G_OBJECT_CLASS (nautilus_desktop_window_parent_class)->constructed (obj);
+
+ /* Initialize the desktop link monitor singleton */
+ nautilus_desktop_link_monitor_get ();
+
+ /* shouldn't really be needed given our semantic type
+ * of _NET_WM_TYPE_DESKTOP, but why not
+ */
+ gtk_window_set_resizable (GTK_WINDOW (window),
+ FALSE);
+ gtk_window_set_decorated (GTK_WINDOW (window),
+ FALSE);
+
+ gtk_window_move (GTK_WINDOW (window), 0, 0);
+
+ g_object_set_data (G_OBJECT (window), "is_desktop_window",
+ GINT_TO_POINTER (1));
+
+ nautilus_desktop_window_init_selection (window);
+ nautilus_desktop_window_init_actions (window);
+
+ if (window->details->desktop_selection != NULL) {
+ /* Set the accessible name so that it doesn't inherit the cryptic desktop URI. */
+ accessible = gtk_widget_get_accessible (GTK_WIDGET (window));
+
+ if (accessible) {
+ atk_object_set_name (accessible, _("Desktop"));
+ }
+
+ /* Special sawmill setting */
+ gtk_window_set_wmclass (GTK_WINDOW (window), "desktop_window", "Nautilus");
+
+ /* Point window at the desktop folder.
+ * Note that nautilus_desktop_window_init is too early to do this.
+ */
+ nautilus_desktop_window_update_directory (window);
+
+ /* We realize it immediately so that the NAUTILUS_DESKTOP_WINDOW_ID
+ * property is set so gnome-settings-daemon doesn't try to set
+ * background. And we do a gdk_flush() to be sure X gets it.
+ */
+ gtk_widget_realize (GTK_WIDGET (window));
+ gdk_flush ();
+ }
+}
+
+static void
+nautilus_desktop_window_init (NautilusDesktopWindow *window)
+{
+ window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NAUTILUS_TYPE_DESKTOP_WINDOW,
+ NautilusDesktopWindowDetails);
+ gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)),
+ "nautilus-desktop-window");
+
+}
+
+static void
+nautilus_desktop_window_screen_size_changed (GdkScreen *screen,
+ NautilusDesktopWindow *window)
+{
+ int width_request, height_request;
+
+ width_request = gdk_screen_get_width (screen);
+ height_request = gdk_screen_get_height (screen);
+
+ g_object_set (window,
+ "width_request", width_request,
+ "height_request", height_request,
+ NULL);
+}
+
+static NautilusDesktopWindow *
+nautilus_desktop_window_new (void)
+{
+ GdkScreen *screen;
+ GApplication *application;
+ NautilusDesktopWindow *window;
+ int width_request, height_request;
+
+ application = g_application_get_default ();
+ screen = gdk_screen_get_default ();
+ width_request = gdk_screen_get_width (screen);
+ height_request = gdk_screen_get_height (screen);
+
+ window = g_object_new (NAUTILUS_TYPE_DESKTOP_WINDOW,
+ "application", application,
+ "disable-chrome", TRUE,
+ "width_request", width_request,
+ "height_request", height_request,
+ NULL);
+
+ return window;
+}
+
+static NautilusDesktopWindow *the_desktop_window = NULL;
+
+void
+nautilus_desktop_window_ensure (void)
+{
+ NautilusDesktopWindow *window;
+
+ if (!the_desktop_window) {
+ window = nautilus_desktop_window_new ();
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &the_desktop_window);
+ the_desktop_window = window;
+ }
+}
+
+GtkWidget *
+nautilus_desktop_window_get (void)
+{
+ return GTK_WIDGET (the_desktop_window);
+}
+
+static gboolean
+nautilus_desktop_window_delete_event (GtkWidget *widget,
+ GdkEventAny *event)
+{
+ /* Returning true tells GTK+ not to delete the window. */
+ return TRUE;
+}
+
+static void
+map (GtkWidget *widget)
+{
+ /* Chain up to realize our children */
+ GTK_WIDGET_CLASS (nautilus_desktop_window_parent_class)->map (widget);
+ gdk_window_lower (gtk_widget_get_window (widget));
+}
+
+static void
+unrealize (GtkWidget *widget)
+{
+ NautilusDesktopWindow *window;
+ NautilusDesktopWindowDetails *details;
+
+ window = NAUTILUS_DESKTOP_WINDOW (widget);
+ details = window->details;
+
+ if (details->size_changed_id != 0) {
+ g_signal_handler_disconnect (gtk_window_get_screen (GTK_WINDOW (window)),
+ details->size_changed_id);
+ details->size_changed_id = 0;
+ }
+
+ gtk_widget_destroy (details->desktop_selection);
+
+ GTK_WIDGET_CLASS (nautilus_desktop_window_parent_class)->unrealize (widget);
+}
+
+static void
+set_wmspec_desktop_hint (GdkWindow *window)
+{
+ GdkAtom atom;
+
+ atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DESKTOP", FALSE);
+
+ gdk_property_change (window,
+ gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE),
+ gdk_x11_xatom_to_atom (XA_ATOM), 32,
+ GDK_PROP_MODE_REPLACE, (guchar *) &atom, 1);
+}
+
+static void
+realize (GtkWidget *widget)
+{
+ NautilusDesktopWindow *window;
+ NautilusDesktopWindowDetails *details;
+ GdkVisual *visual;
+
+ window = NAUTILUS_DESKTOP_WINDOW (widget);
+ details = window->details;
+
+ /* Make sure we get keyboard events */
+ gtk_widget_set_events (widget, gtk_widget_get_events (widget)
+ | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
+
+ visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (widget));
+ if (visual) {
+ gtk_widget_set_visual (widget, visual);
+ }
+
+ /* Do the work of realizing. */
+ GTK_WIDGET_CLASS (nautilus_desktop_window_parent_class)->realize (widget);
+
+ /* This is the new way to set up the desktop window */
+ set_wmspec_desktop_hint (gtk_widget_get_window (widget));
+
+ details->size_changed_id =
+ g_signal_connect (gtk_window_get_screen (GTK_WINDOW (window)), "size-changed",
+ G_CALLBACK (nautilus_desktop_window_screen_size_changed), window);
+}
+
+static void
+real_sync_title (NautilusWindow *window,
+ NautilusWindowSlot *slot)
+{
+ /* hardcode "Desktop" */
+ gtk_window_set_title (GTK_WINDOW (window), _("Desktop"));
+}
+
+static void
+real_window_close (NautilusWindow *window)
+{
+ /* stub, does nothing */
+ return;
+}
+
+static NautilusWindowSlot *
+real_create_slot (NautilusWindow *window,
+ GFile *location)
+{
+ return NAUTILUS_WINDOW_SLOT (nautilus_desktop_window_slot_new (window));
+}
+
+static void
+nautilus_desktop_window_class_init (NautilusDesktopWindowClass *klass)
+{
+ GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass);
+ NautilusWindowClass *nclass = NAUTILUS_WINDOW_CLASS (klass);
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->constructed = nautilus_desktop_window_constructed;
+ oclass->finalize = nautilus_desktop_window_finalize;
+
+ wclass->realize = realize;
+ wclass->unrealize = unrealize;
+ wclass->map = map;
+ wclass->delete_event = nautilus_desktop_window_delete_event;
+
+ nclass->sync_title = real_sync_title;
+ nclass->close = real_window_close;
+ nclass->create_slot = real_create_slot;
+
+ g_type_class_add_private (klass, sizeof (NautilusDesktopWindowDetails));
+}
+
+gboolean
+nautilus_desktop_window_loaded (NautilusDesktopWindow *window)
+{
+ return window->details->loaded;
+}
diff --git a/nautilus-desktop/nautilus-desktop-window.h b/nautilus-desktop/nautilus-desktop-window.h
new file mode 100644
index 000000000..818c23bc7
--- /dev/null
+++ b/nautilus-desktop/nautilus-desktop-window.h
@@ -0,0 +1,59 @@
+
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2000 Eazel, Inc.
+ *
+ * Nautilus is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Darin Adler <darin@bentspoon.com>
+ */
+
+/* nautilus-desktop-window.h
+ */
+
+#ifndef NAUTILUS_DESKTOP_WINDOW_H
+#define NAUTILUS_DESKTOP_WINDOW_H
+
+#include <src/nautilus-window.h>
+
+#define NAUTILUS_TYPE_DESKTOP_WINDOW nautilus_desktop_window_get_type()
+#define NAUTILUS_DESKTOP_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_DESKTOP_WINDOW, NautilusDesktopWindow))
+#define NAUTILUS_DESKTOP_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_WINDOW, NautilusDesktopWindowClass))
+#define NAUTILUS_IS_DESKTOP_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_WINDOW))
+#define NAUTILUS_IS_DESKTOP_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_WINDOW))
+#define NAUTILUS_DESKTOP_WINDOW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_DESKTOP_WINDOW, NautilusDesktopWindowClass))
+
+typedef struct NautilusDesktopWindowDetails NautilusDesktopWindowDetails;
+
+typedef struct {
+ NautilusWindow parent_spot;
+ NautilusDesktopWindowDetails *details;
+} NautilusDesktopWindow;
+
+typedef struct {
+ NautilusWindowClass parent_spot;
+} NautilusDesktopWindowClass;
+
+GType nautilus_desktop_window_get_type (void);
+GtkWidget * nautilus_desktop_window_get (void);
+void nautilus_desktop_window_ensure (void);
+gboolean nautilus_desktop_window_loaded (NautilusDesktopWindow *window);
+
+#endif /* NAUTILUS_DESKTOP_WINDOW_H */