/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
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 .
Author: Alexander Larsson
*/
#include
#include "nautilus-desktop-link-monitor.h"
#include "nautilus-desktop-link.h"
#include "nautilus-desktop-icon-file.h"
#include "nautilus-directory.h"
#include "nautilus-desktop-directory.h"
#include "nautilus-global-preferences.h"
#include
#include
#include
#include
#include
#include
#include
#include
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 void
volume_delete_dialog (GtkWidget *parent_view,
NautilusDesktopLink *link)
{
GMount *mount;
char *dialog_str;
char *display_name;
mount = nautilus_desktop_link_get_mount (link);
if (mount != NULL) {
display_name = nautilus_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."),
_("_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."),
_("_OK"), NULL);
}
g_object_unref (mount);
g_free (dialog_str);
}
}
void
nautilus_desktop_link_monitor_delete_link (NautilusDesktopLinkMonitor *monitor,
NautilusDesktopLink *link,
GtkWidget *parent_view)
{
switch (nautilus_desktop_link_get_link_type (link)) {
case NAUTILUS_DESKTOP_LINK_HOME:
case NAUTILUS_DESKTOP_LINK_TRASH:
case NAUTILUS_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 (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));
}