/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- caja-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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. Author: Alexander Larsson <alexl@redhat.com> */ #include <config.h> #include "caja-desktop-link-monitor.h" #include "caja-desktop-link.h" #include "caja-desktop-icon-file.h" #include "caja-directory.h" #include "caja-desktop-directory.h" #include "caja-global-preferences.h" #include <eel/eel-debug.h> #include <eel/eel-gtk-macros.h> #include <eel/eel-glib-extensions.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 <libcaja-private/caja-trash-monitor.h> #include <string.h> struct CajaDesktopLinkMonitorDetails { GVolumeMonitor *volume_monitor; CajaDirectory *desktop_dir; CajaDesktopLink *home_link; CajaDesktopLink *computer_link; CajaDesktopLink *trash_link; CajaDesktopLink *network_link; gulong mount_id; gulong unmount_id; gulong changed_id; GList *mount_links; }; static void caja_desktop_link_monitor_init (gpointer object, gpointer klass); static void caja_desktop_link_monitor_class_init (gpointer klass); EEL_CLASS_BOILERPLATE (CajaDesktopLinkMonitor, caja_desktop_link_monitor, G_TYPE_OBJECT) static CajaDesktopLinkMonitor *the_link_monitor = NULL; static void destroy_desktop_link_monitor (void) { if (the_link_monitor != NULL) { g_object_unref (the_link_monitor); } } CajaDesktopLinkMonitor * caja_desktop_link_monitor_get (void) { if (the_link_monitor == NULL) { g_object_new (CAJA_TYPE_DESKTOP_LINK_MONITOR, NULL); eel_debug_call_at_shutdown (destroy_desktop_link_monitor); } return the_link_monitor; } static void volume_delete_dialog (GtkWidget *parent_view, CajaDesktopLink *link) { GMount *mount; char *dialog_str; char *display_name; mount = caja_desktop_link_get_mount (link); if (mount != NULL) { display_name = caja_desktop_link_get_display_name (link); dialog_str = g_strdup_printf (_("You cannot move the volume \"%s\" to the trash."), display_name); g_free (display_name); if (g_mount_can_eject (mount)) { eel_run_simple_dialog (parent_view, FALSE, GTK_MESSAGE_ERROR, dialog_str, _("If you want to eject the volume, please use \"Eject\" in the " "popup menu of the volume."), GTK_STOCK_OK, NULL); } else { eel_run_simple_dialog (parent_view, FALSE, GTK_MESSAGE_ERROR, dialog_str, _("If you want to unmount the volume, please use \"Unmount Volume\" in the " "popup menu of the volume."), GTK_STOCK_OK, NULL); } g_object_unref (mount); g_free (dialog_str); } } void caja_desktop_link_monitor_delete_link (CajaDesktopLinkMonitor *monitor, CajaDesktopLink *link, GtkWidget *parent_view) { switch (caja_desktop_link_get_link_type (link)) { case CAJA_DESKTOP_LINK_HOME: case CAJA_DESKTOP_LINK_COMPUTER: case CAJA_DESKTOP_LINK_TRASH: case CAJA_DESKTOP_LINK_NETWORK: /* just ignore. We don't allow you to delete these */ break; default: volume_delete_dialog (parent_view, link); break; } } static gboolean volume_file_name_used (CajaDesktopLinkMonitor *monitor, const char *name) { GList *l; char *other_name; gboolean same; for (l = monitor->details->mount_links; l != NULL; l = l->next) { other_name = caja_desktop_link_get_file_name (l->data); same = strcmp (name, other_name) == 0; g_free (other_name); if (same) { return TRUE; } } return FALSE; } char * caja_desktop_link_monitor_make_filename_unique (CajaDesktopLinkMonitor *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 (CajaDesktopLinkMonitor *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 = caja_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 (CajaDesktopLinkMonitor *monitor, GMount *mount) { CajaDesktopLink *link; if (has_mount (monitor, mount)) return; if ((!g_mount_is_shadowed (mount)) && g_settings_get_boolean (caja_desktop_preferences, CAJA_PREFERENCES_DESKTOP_VOLUMES_VISIBLE)) { link = caja_desktop_link_new_from_mount (mount); monitor->details->mount_links = g_list_prepend (monitor->details->mount_links, link); } } static void remove_mount_link (CajaDesktopLinkMonitor *monitor, GMount *mount) { GList *l; CajaDesktopLink *link; GMount *other_mount; link = NULL; for (l = monitor->details->mount_links; l != NULL; l = l->next) { other_mount = caja_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, CajaDesktopLinkMonitor *monitor) { create_mount_link (monitor, mount); } static void mount_removed_callback (GVolumeMonitor *volume_monitor, GMount *mount, CajaDesktopLinkMonitor *monitor) { remove_mount_link (monitor, mount); } static void mount_changed_callback (GVolumeMonitor *volume_monitor, GMount *mount, CajaDesktopLinkMonitor *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 (CajaDesktopLinkMonitor *monitor, CajaDesktopLink **link_ref, CajaDesktopLinkType link_type, const char *preference_key) { if (g_settings_get_boolean (caja_desktop_preferences, preference_key)) { if (*link_ref == NULL) { *link_ref = caja_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) { CajaDesktopLinkMonitor *monitor; monitor = CAJA_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (CAJA_DESKTOP_LINK_MONITOR (monitor), &monitor->details->home_link, CAJA_DESKTOP_LINK_HOME, CAJA_PREFERENCES_DESKTOP_HOME_VISIBLE); } static void desktop_computer_visible_changed (gpointer callback_data) { CajaDesktopLinkMonitor *monitor; monitor = CAJA_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (CAJA_DESKTOP_LINK_MONITOR (callback_data), &monitor->details->computer_link, CAJA_DESKTOP_LINK_COMPUTER, CAJA_PREFERENCES_DESKTOP_COMPUTER_VISIBLE); } static void desktop_trash_visible_changed (gpointer callback_data) { CajaDesktopLinkMonitor *monitor; monitor = CAJA_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (CAJA_DESKTOP_LINK_MONITOR (callback_data), &monitor->details->trash_link, CAJA_DESKTOP_LINK_TRASH, CAJA_PREFERENCES_DESKTOP_TRASH_VISIBLE); } static void desktop_network_visible_changed (gpointer callback_data) { CajaDesktopLinkMonitor *monitor; monitor = CAJA_DESKTOP_LINK_MONITOR (callback_data); update_link_visibility (CAJA_DESKTOP_LINK_MONITOR (callback_data), &monitor->details->network_link, CAJA_DESKTOP_LINK_NETWORK, CAJA_PREFERENCES_DESKTOP_NETWORK_VISIBLE); } static void desktop_volumes_visible_changed (gpointer callback_data) { CajaDesktopLinkMonitor *monitor; GList *l, *mounts; monitor = CAJA_DESKTOP_LINK_MONITOR (callback_data); if (g_settings_get_boolean (caja_desktop_preferences, CAJA_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 (CajaDesktopLink **link_ref, CajaDesktopLinkType link_type, const char *preference_key, GCallback callback, gpointer callback_data) { char *detailed_signal; if (g_settings_get_boolean (caja_desktop_preferences, preference_key)) { *link_ref = caja_desktop_link_new (link_type); } detailed_signal = g_strconcat ("changed::", preference_key, NULL); g_signal_connect_swapped (caja_desktop_preferences, detailed_signal, callback, callback_data); } static void caja_desktop_link_monitor_init (gpointer object, gpointer klass) { CajaDesktopLinkMonitor *monitor; GList *l, *mounts; GMount *mount; monitor = CAJA_DESKTOP_LINK_MONITOR (object); the_link_monitor = monitor; monitor->details = g_new0 (CajaDesktopLinkMonitorDetails, 1); monitor->details->volume_monitor = g_volume_monitor_get (); /* We keep around a ref to the desktop dir */ monitor->details->desktop_dir = caja_directory_get_by_uri (EEL_DESKTOP_URI); /* Default links */ create_link_and_add_preference (&monitor->details->home_link, CAJA_DESKTOP_LINK_HOME, CAJA_PREFERENCES_DESKTOP_HOME_VISIBLE, G_CALLBACK (desktop_home_visible_changed), monitor); create_link_and_add_preference (&monitor->details->computer_link, CAJA_DESKTOP_LINK_COMPUTER, CAJA_PREFERENCES_DESKTOP_COMPUTER_VISIBLE, G_CALLBACK (desktop_computer_visible_changed), monitor); create_link_and_add_preference (&monitor->details->trash_link, CAJA_DESKTOP_LINK_TRASH, CAJA_PREFERENCES_DESKTOP_TRASH_VISIBLE, G_CALLBACK (desktop_trash_visible_changed), monitor); create_link_and_add_preference (&monitor->details->network_link, CAJA_DESKTOP_LINK_NETWORK, CAJA_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 (caja_desktop_preferences, "changed::" CAJA_PREFERENCES_DESKTOP_VOLUMES_VISIBLE, G_CALLBACK (desktop_volumes_visible_changed), monitor); monitor->details->mount_id = g_signal_connect_object (monitor->details->volume_monitor, "mount_added", G_CALLBACK (mount_added_callback), monitor, 0); monitor->details->unmount_id = g_signal_connect_object (monitor->details->volume_monitor, "mount_removed", G_CALLBACK (mount_removed_callback), monitor, 0); monitor->details->changed_id = g_signal_connect_object (monitor->details->volume_monitor, "mount_changed", G_CALLBACK (mount_changed_callback), monitor, 0); } static void remove_link_and_preference (CajaDesktopLink **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 (caja_desktop_preferences, callback, callback_data); } static void desktop_link_monitor_finalize (GObject *object) { CajaDesktopLinkMonitor *monitor; monitor = CAJA_DESKTOP_LINK_MONITOR (object); g_object_unref (monitor->details->volume_monitor); /* Default links */ remove_link_and_preference (&monitor->details->home_link, CAJA_PREFERENCES_DESKTOP_HOME_VISIBLE, G_CALLBACK (desktop_home_visible_changed), monitor); remove_link_and_preference (&monitor->details->computer_link, CAJA_PREFERENCES_DESKTOP_COMPUTER_VISIBLE, G_CALLBACK (desktop_computer_visible_changed), monitor); remove_link_and_preference (&monitor->details->trash_link, CAJA_PREFERENCES_DESKTOP_TRASH_VISIBLE, G_CALLBACK (desktop_trash_visible_changed), monitor); remove_link_and_preference (&monitor->details->network_link, CAJA_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; caja_directory_unref (monitor->details->desktop_dir); monitor->details->desktop_dir = NULL; g_signal_handlers_disconnect_by_func (caja_desktop_preferences, desktop_volumes_visible_changed, monitor); if (monitor->details->mount_id != 0) { g_source_remove (monitor->details->mount_id); } if (monitor->details->unmount_id != 0) { g_source_remove (monitor->details->unmount_id); } if (monitor->details->changed_id != 0) { g_source_remove (monitor->details->changed_id); } g_free (monitor->details); EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); } static void caja_desktop_link_monitor_class_init (gpointer klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = desktop_link_monitor_finalize; }