diff options
Diffstat (limited to 'nautilus-desktop')
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 (¶ms); + 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 */ |