[patch] Support showing drives and volumes on the desktop



Right now, Nautilus only supports showing volume icons on the desktop.
This is fine for volumes which are not associated to a drive, and for
auto-mounted volumes which come out of drives which HAL and friends can
monitor.

However, certain drives like floppies and Zip drives (and some broken
CD-ROMs) don't support media checks.  That is, the hardware won't notify
the system when the user inserts media in the drive.  Thus, HAL and
g-v-m are not able to automount the drive as soon as media is inserted.
For this kind of drives, the only way for users to access them is to
open computer:/// and double-click on the drive there.  This is really
cumbersome.

The right policy for showing drives and volumes is exactly what we have
right now, *plus* the addition of showing drives which do not support
media checks.

The first patch (nautilus-drives-and-volumes-on-desktop.diff) implements
this policy.  It's a large patch, but it's well-documented in the
ChangeLog.  It basically adds the ability for NautilusDesktopLink to
represent a drive or a volume, and for the links to be updated whenever
a drive sprouts a volume.  It handles drives with multiple partitions;
in that case, one volume icon is created for each partition that gets
mounted.  This patch applies cleanly to HEAD.

The second patch (nautilus-directory-view-mount-drive.diff) is from
Nautilus in GNOME 2.12, i.e. what is in SLED 10.  I couldn't quite grok
Manny's changes in fm-directory-view.c to support activating multiple
files at the same time.  What the patch does is to handle a race
condition in which the gnome_vfs_drive_mount() callback gets run, *but*
the drive doesn't yet know that it is mounted.  This is because
GnomeVFSVolumeMonitor hasn't been notified yet by gnome-vfs-daemon.  To
handle this, the patch delays the activation callback until the drive
really knows that it is mounted.

Manny, I would love your help in porting this second patch over to HEAD,
since you know the surrounding code a lot better :)

I'm really happy with the way both patches have been working in
SLED 10.  Floppies and old/broken media appear on the desktop
seamlessly, and users have been quite pleased.

  Federico
2006-10-05  Federico Mena Quintero  <federico novell com>

	Support displaying drive icons in the desktop, even if the drives
	are not mounted.  Do this only for drives which are supposed to be
	user-visible (i.e. those that do not support media checks and so
	we cannot know when the user inserts media in them).

	Also, support drives with multiple partitions, which will lead to
	multiple volumes for the same drive.

	To do this, we add several things:

	1. The ability for NautilusDesktopLink to represent a drive as
	well as a volume.

	2. The ability to "transform" a NautilusDesktopLink which
	represented a drive, into one that represents a volume.  This
	happens when a drive is mounted.

	3. Keep the invariant that drives are only displayed if they are
	unmounted and user visible.  If they are mounted, they get
	replaced with volume links.

	* libnautilus-private/nautilus-desktop-link-monitor.c (struct
	NautilusDesktopLinkMonitorDetails): Added "connected_id" and
	"disconnected_id" fields for the signal IDs of GnomeVFSDrive.
	(volume_delete_dialog): Added message about not being able to move
	a drive to the trash.  Support drives or volumes.
	(should_show_drive): New utility function.  Drives are shown if
	they are user-visible, they are not mounted, and the preference to
	show desktop volumes is turned on.
	(should_show_volume): New utility function.  Volumes are shown if
	they are user visible and the preference to show desktop volumes
	is turned on.
	(create_drive_link): New utility function; creates a
	NautilusDesktopLink for a GnomeVFSDrive.
	(create_volume_link): Use should_show_volume().
	(link_corresponds_to_drive): New function.  A NautilusDesktopLink
	corresponds to a drive if it represents the drive itself, or if it
	represents a volume relative to that drive.
	(find_unique_link_for_drive): New function.  Returns the
	NautilusDesktopLink in the desktop that corresponds uniquely to a
	given drive; if there is more than one volume link for a drive
	(e.g. a drive with multiple partitions), returns NULL.
	(drive_connected_callback): New callback.  When a drive is
	connected, we create a link for it if appropriate.
	(drive_disconnected_callback): New callback.  When a drive is
	disconnected, we remove all the links that correspond to it:  a
	single drive link for an unmounted drive, or one or more volume
	links for a mounted drive.
	(volume_mounted_callback): If the volume has a drive, and there is
	an existing link for that drive, update the link to represent the
	volume instead.  Otherwise, create volume link as usual.
	(find_link_for_volume): New utility function; returns the link on
	the desktop which corresponds to a particular volume.
	(volume_unmounted_callback): If unmounting a volume would yield a
	drive that is user visible, transform the corresponding link from
	representing the volume, into one that represents the drive.
	Otherwise, remove the link as usual.
	(refresh_volume_links): New function; does the initial population
	of the links for drives and volumes.
	(desktop_volumes_visible_changed): New callback; use
	refresh_volume_links().
	(nautilus_desktop_link_monitor_init): Use refresh_volume_links()
	instead of doing things by hand here.  Also, connect to
	"drive_connected" and "drive_disconnected" on the volume monitor.

	* libnautilus-private/nautilus-desktop-icon-file.c
	(update_info_from_link): Accept a drive or a volume, not just
	volumes.

	* libnautilus-private/nautilus-desktop-link.h
	(nautilus_desktop_link_new_from_drive_or_volume): New prototype.
	Replaces nautilus_desktop_link_new_from_volume().
	(nautilus_desktop_link_get_drive_or_volume): New prototype.
	Replaces nautilus_desktop_link_get_volume().
	(nautilus_desktop_link_update_from_volume): New prototype.

	* libnautilus-private/nautilus-desktop-link.c (struct
	NautilusDesktopLinkDetails): Replaced the "volume" field with
	"drive_or_volume".
	(reread_drive_or_volume): Refresh the link as appropriate from a
	drive or a volume.
	(desktop_link_finalize): Unref the drive or volume appropriately.
	(nautilus_desktop_link_new_from_drive_or_volume): Replacement for
	nautilus_desktop_link_new_from_volume().
	(nautilus_desktop_link_get_drive_or_volume): Replacement for
	nautilus_desktop_link_get_volume().
	(nautilus_desktop_link_update_from_volume): New public function;
	replaces nautilus_desktop_link_new_from_volume().  Updates the
	link's information from a volume.  This does the actual
	transformation of a link from a drive to volume when an unmounted
	drive gets first mounted, and vice-versa.

Index: libnautilus-private/nautilus-desktop-icon-file.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-desktop-icon-file.c,v
retrieving revision 1.8
diff -u -p -r1.8 nautilus-desktop-icon-file.c
--- libnautilus-private/nautilus-desktop-icon-file.c	18 Mar 2006 07:13:49 -0000	1.8
+++ libnautilus-private/nautilus-desktop-icon-file.c	6 Oct 2006 00:32:43 -0000
@@ -179,7 +179,7 @@ update_info_from_link (NautilusDesktopIc
 	NautilusFile *file;
 	GnomeVFSFileInfo *file_info;
 	NautilusDesktopLink *link;
-	GnomeVFSVolume *volume;
+	GObject *drive_or_volume;
 	
 	file = NAUTILUS_FILE (icon_file);
 	
@@ -216,9 +216,21 @@ update_info_from_link (NautilusDesktopIc
 		GNOME_VFS_FILE_INFO_FIELDS_ACCESS |
 		GNOME_VFS_FILE_INFO_FIELDS_LINK_COUNT;
 
-	volume = nautilus_desktop_link_get_volume (link);
-	nautilus_file_set_volume (file, volume);
-	gnome_vfs_volume_unref (volume);
+	drive_or_volume = nautilus_desktop_link_get_drive_or_volume (link);
+
+	if (GNOME_IS_VFS_VOLUME (drive_or_volume)) {
+		GnomeVFSVolume *volume;
+
+		volume = GNOME_VFS_VOLUME (drive_or_volume);
+		nautilus_file_set_volume (file, volume);
+		gnome_vfs_volume_unref (volume);
+	} else {
+		GnomeVFSDrive *drive;
+
+		drive = GNOME_VFS_DRIVE (drive_or_volume);
+		nautilus_file_set_drive (file, drive);
+		gnome_vfs_drive_unref (drive);
+	}
 	
 	file->details->file_info_is_up_to_date = TRUE;
 
Index: libnautilus-private/nautilus-desktop-link-monitor.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-desktop-link-monitor.c,v
retrieving revision 1.17
diff -u -p -r1.17 nautilus-desktop-link-monitor.c
--- libnautilus-private/nautilus-desktop-link-monitor.c	18 Mar 2006 07:13:49 -0000	1.17
+++ libnautilus-private/nautilus-desktop-link-monitor.c	6 Oct 2006 00:32:43 -0000
@@ -52,13 +52,14 @@ struct NautilusDesktopLinkMonitorDetails
 	NautilusDesktopLink *trash_link;
 	NautilusDesktopLink *network_link;
 
+	gulong connected_id;
+	gulong disconnected_id;
 	gulong mount_id;
 	gulong unmount_id;
 	
 	GList *volume_links;
 };
 
-
 static void nautilus_desktop_link_monitor_init       (gpointer              object,
 						      gpointer              klass);
 static void nautilus_desktop_link_monitor_class_init (gpointer              klass);
@@ -69,6 +70,8 @@ EEL_CLASS_BOILERPLATE (NautilusDesktopLi
 
 static NautilusDesktopLinkMonitor *the_link_monitor = NULL;
 
+static void refresh_volume_links (NautilusDesktopLinkMonitor *monitor);
+
 static void
 destroy_desktop_link_monitor (void)
 {
@@ -104,41 +107,48 @@ static void
 volume_delete_dialog (GtkWidget *parent_view,
                       NautilusDesktopLink *link)
 {
-	GnomeVFSVolume *volume;
+	GObject *drive_or_volume;
 	char *dialog_str;
+	char *detail_str;
 	char *display_name;
 
-	volume = nautilus_desktop_link_get_volume (link);
+	drive_or_volume = nautilus_desktop_link_get_drive_or_volume (link);
+	if (drive_or_volume == NULL)
+		return;
 
-	if (volume != NULL) {
-		display_name = nautilus_desktop_link_get_display_name (link);
+	display_name = nautilus_desktop_link_get_display_name (link);
+
+	if (GNOME_IS_VFS_VOLUME (drive_or_volume)) {
 		dialog_str = g_strdup_printf (_("You cannot move the volume \"%s\" to the trash."),
 					      display_name);
-		g_free (display_name);
 
-		if (eject_for_type (gnome_vfs_volume_get_device_type (volume))) {
-			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);
+		if (eject_for_type (gnome_vfs_volume_get_device_type (GNOME_VFS_VOLUME (drive_or_volume)))) {
+			detail_str = _("If you want to eject the volume, please use \"Eject\" in the "
+				       "popup menu of the volume.");
 		} 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);
+			detail_str = _("If you want to unmount the volume, please use \"Unmount Volume\" in the "
+				       "popup menu of the volume.");
 		}
+	} else {
+		dialog_str = g_strdup_printf (_("You cannot move the drive \"%s\" to the trash."),
+					      display_name);
+
+		detail_str = NULL;
+	}
+
+	eel_run_simple_dialog (parent_view, FALSE, GTK_MESSAGE_ERROR,
+			       dialog_str,
+			       detail_str,
+			       NULL, GTK_STOCK_OK, NULL);
 
-		gnome_vfs_volume_unref (volume);
-		g_free (dialog_str);
+	if (GNOME_IS_VFS_VOLUME (drive_or_volume)) {
+		gnome_vfs_volume_unref (GNOME_VFS_VOLUME (drive_or_volume));
+	} else {
+		gnome_vfs_drive_unref (GNOME_VFS_DRIVE (drive_or_volume));
 	}
+
+	g_free (display_name);
+	g_free (dialog_str);
 }
 
 void
@@ -196,6 +206,34 @@ nautilus_desktop_link_monitor_make_filen
 	return unique_name;
 }
 
+static gboolean
+should_show_drive (GnomeVFSDrive *drive)
+{
+	return (gnome_vfs_drive_is_user_visible (drive)
+		&& !gnome_vfs_drive_is_mounted (drive)
+		&& eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE));
+}
+
+static gboolean
+should_show_volume (GnomeVFSVolume *volume)
+{
+	return (gnome_vfs_volume_is_user_visible (volume)
+		&& eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE));
+}
+
+static void
+create_drive_link (NautilusDesktopLinkMonitor *monitor,
+		   GnomeVFSDrive *drive)
+{
+	NautilusDesktopLink *link;
+
+	if (!should_show_drive (drive))
+		return;
+
+	link = nautilus_desktop_link_new_from_drive_or_volume (G_OBJECT (drive));
+	monitor->details->volume_links = g_list_prepend (monitor->details->volume_links, link);
+}
+
 static void
 create_volume_link (NautilusDesktopLinkMonitor *monitor,
 		    GnomeVFSVolume *volume)
@@ -204,24 +242,198 @@ create_volume_link (NautilusDesktopLinkM
 
 	link = NULL;
 
-	if (!gnome_vfs_volume_is_user_visible (volume)) {
+	if (!should_show_volume (volume)) {
 		return;
 	}
 
-	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE)) {
-		link = nautilus_desktop_link_new_from_volume (volume);
-		monitor->details->volume_links = g_list_prepend (monitor->details->volume_links, link);
+	link = nautilus_desktop_link_new_from_drive_or_volume (G_OBJECT (volume));
+	monitor->details->volume_links = g_list_prepend (monitor->details->volume_links, link);
+}
+
+static gboolean
+link_corresponds_to_drive (NautilusDesktopLink *link,
+			   GnomeVFSDrive *drive)
+{
+	GObject *drive_or_volume;
+	gboolean same;
+
+	drive_or_volume = nautilus_desktop_link_get_drive_or_volume (link);
+	same = FALSE;
+
+	if (GNOME_IS_VFS_DRIVE (drive_or_volume)) {
+		GnomeVFSDrive *link_drive;
+
+		link_drive = GNOME_VFS_DRIVE (drive_or_volume);
+
+		if (link_drive == drive) {
+			same = TRUE;
+		}
+
+		gnome_vfs_drive_unref (link_drive);
+	} else {
+		GnomeVFSVolume *link_volume;
+		GnomeVFSDrive *link_drive;
+
+		link_volume = GNOME_VFS_VOLUME (drive_or_volume);
+		link_drive = gnome_vfs_volume_get_drive (link_volume);
+
+		if (link_drive == drive) {
+			same = TRUE;
+		}
+
+		if (link_drive) {
+			gnome_vfs_drive_unref (link_drive);
+		}
+
+		gnome_vfs_volume_unref (link_volume);
 	}
+
+	return same;
 }
 
+static NautilusDesktopLink *
+find_unique_link_for_drive (NautilusDesktopLinkMonitor *monitor,
+			    GnomeVFSDrive *drive)
+{
+	GList *l;
+	NautilusDesktopLink *first_volume_link_for_drive;
+
+	first_volume_link_for_drive = NULL;
+
+	for (l = monitor->details->volume_links; l; l = l->next) {
+		NautilusDesktopLink *link;
+
+		link = NAUTILUS_DESKTOP_LINK (l->data);
+
+		if (link_corresponds_to_drive (link, drive)) {
+			if (first_volume_link_for_drive == NULL) {
+				first_volume_link_for_drive = link;
+			} else {
+				return NULL; /* We know that we have more than
+					      * one link for volumes that belong
+					      * to the same drive, so there is
+					      * no unique link for the drive.
+					      */
+			}
+		}
+	}
+
+	return first_volume_link_for_drive;
+}
+
+static void
+drive_connected_callback (GnomeVFSVolumeMonitor *volume_monitor,
+			  GnomeVFSDrive *drive,
+			  NautilusDesktopLinkMonitor *monitor)
+{
+	NautilusDesktopLink *link;
+
+	/* fprintf (stderr, "drive connected!\n"); */
+
+	link = find_unique_link_for_drive (monitor, drive);
+
+	if (link)
+		return; /* huh, we already have a link for that drive... */
+
+	create_drive_link (monitor, drive);
+}
+
+static void
+drive_disconnected_callback (GnomeVFSVolumeMonitor *volume_monitor,
+			     GnomeVFSDrive *drive,
+			     NautilusDesktopLinkMonitor *monitor)
+{
+	GList *l;
+
+	/* fprintf (stderr, "drive disconnected!\n"); */
+
+	/* Remove all the links that correspond to that drive, even if they have
+	 * mounted volumes.
+	 */
+
+	l = monitor->details->volume_links;
+
+	while (l) {
+		GList *next;
+		NautilusDesktopLink *link;
 
+		next = l->next;
+		link = NAUTILUS_DESKTOP_LINK (l->data);
+
+		if (link_corresponds_to_drive (link, drive)) {
+			g_object_unref (link);
+			monitor->details->volume_links = g_list_remove_link (monitor->details->volume_links, l);
+			g_list_free_1 (l);
+		}
+
+		l = next;
+	}
+}
 
 static void
 volume_mounted_callback (GnomeVFSVolumeMonitor *volume_monitor,
 			 GnomeVFSVolume *volume, 
 			 NautilusDesktopLinkMonitor *monitor)
 {
-	create_volume_link (monitor, volume);
+	GnomeVFSDrive *drive;
+
+	/* fprintf (stderr, "volume mounted!\n"); */
+
+	drive = gnome_vfs_volume_get_drive (volume);
+
+	if (drive) {
+		NautilusDesktopLink *link;
+
+		/* We may have an existing link for the drive, which needs to be
+		 * updated for the volume.  Or we may have several volumes
+		 * within the same drive; in this case, we need to create a
+		 * completely new link.
+		 */
+
+		link = find_unique_link_for_drive (monitor, drive);
+		gnome_vfs_drive_unref (drive);
+
+		if (link) {
+			/* fprintf (stderr, "updating desktop link from mounted volume\n"); */
+			nautilus_desktop_link_update_from_volume (link, volume);
+		} else {
+			/* fprintf (stderr, "creating desktop link\n"); */
+			create_volume_link (monitor, volume);
+		}
+	} else {
+		/* fprintf (stderr, "creating desktop link\n"); */
+		create_volume_link (monitor, volume);
+	}
+}
+
+static NautilusDesktopLink *
+find_link_for_volume (NautilusDesktopLinkMonitor *monitor,
+		      GnomeVFSVolume             *volume)
+{
+	GList *l;
+
+	for (l = monitor->details->volume_links; l != NULL; l = l->next) {
+		NautilusDesktopLink *link;
+		GObject *drive_or_volume;
+		gboolean same;
+
+		link = NAUTILUS_DESKTOP_LINK (l->data);
+		drive_or_volume = nautilus_desktop_link_get_drive_or_volume (link);
+
+		same = FALSE;
+
+		if (GNOME_IS_VFS_VOLUME (drive_or_volume)) {
+			same = (GNOME_VFS_VOLUME (drive_or_volume) == volume);
+			gnome_vfs_volume_unref (GNOME_VFS_VOLUME (drive_or_volume));
+		} else {
+			gnome_vfs_drive_unref (GNOME_VFS_DRIVE (drive_or_volume));
+		}
+
+		if (same)
+			return link;
+	}
+
+	return NULL;
 }
 
 
@@ -230,22 +442,31 @@ volume_unmounted_callback (GnomeVFSVolum
 			   GnomeVFSVolume *volume, 
 			   NautilusDesktopLinkMonitor *monitor)
 {
-	GList *l;
 	NautilusDesktopLink *link;
-	GnomeVFSVolume *other_volume;
+	GnomeVFSDrive *drive;
+	gboolean remove_link;
 
-	link = NULL;
-	for (l = monitor->details->volume_links; l != NULL; l = l->next) {
-		other_volume = nautilus_desktop_link_get_volume (l->data);
-		if (volume == other_volume) {
-			gnome_vfs_volume_unref (other_volume);
-			link = l->data;
-			break;
+	/* fprintf (stderr, "volume unmounted!\n"); */
+
+	link = find_link_for_volume (monitor, volume);
+	if (!link) {
+		return;
+	}
+
+	remove_link = FALSE;
+
+	drive = gnome_vfs_volume_get_drive (volume);
+	if (drive) {
+		if (should_show_drive (drive)) {
+			nautilus_desktop_link_update_from_volume (link, volume);
+		} else {
+			remove_link = TRUE;
 		}
-		gnome_vfs_volume_unref (other_volume);
+	} else {
+		remove_link = TRUE;
 	}
 
-	if (link) {
+	if (remove_link) {
 		monitor->details->volume_links = g_list_remove (monitor->details->volume_links, link);
 		g_object_unref (link);
 	}
@@ -322,32 +543,60 @@ desktop_network_visible_changed (gpointe
 }
 
 static void
-desktop_volumes_visible_changed (gpointer callback_data)
+refresh_volume_links (NautilusDesktopLinkMonitor *monitor)
 {
 	GnomeVFSVolumeMonitor *volume_monitor;
-	NautilusDesktopLinkMonitor *monitor;
-	GList *l, *volumes;
 	
 	volume_monitor = gnome_vfs_get_volume_monitor ();
-	monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data);
+
+	/* Free existing links */
+
+	g_list_foreach (monitor->details->volume_links, (GFunc)g_object_unref, NULL);
+	g_list_free (monitor->details->volume_links);
+	monitor->details->volume_links = NULL;
+
+	/* Scan the links again */
 
 	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE)) {
-		if (monitor->details->volume_links == NULL) {
-			volumes = gnome_vfs_volume_monitor_get_mounted_volumes (volume_monitor);
-			for (l = volumes; l != NULL; l = l->next) {
-				create_volume_link (monitor, l->data);
-				gnome_vfs_volume_unref (l->data);
-			}
-			g_list_free (volumes);
+		GList *l;
+		GList *volumes, *drives;
+
+		/* Unmounted drives */
+
+		drives = gnome_vfs_volume_monitor_get_connected_drives (volume_monitor);
+		for (l = drives; l != NULL; l = l->next) {
+			GnomeVFSDrive *drive;
+
+			drive = GNOME_VFS_DRIVE (l->data);
+			create_drive_link (monitor, drive);
+			gnome_vfs_drive_unref (drive);
 		}
-	} else {
-		g_list_foreach (monitor->details->volume_links, (GFunc)g_object_unref, NULL);
-		g_list_free (monitor->details->volume_links);
-		monitor->details->volume_links = NULL;
+		g_list_free (drives);
+
+		/* Volumes */
+
+		volumes = gnome_vfs_volume_monitor_get_mounted_volumes (volume_monitor);
+		for (l = volumes; l != NULL; l = l->next) {
+			GnomeVFSVolume *volume;
+
+			volume = GNOME_VFS_VOLUME (l->data);
+			create_volume_link (monitor, volume);
+			gnome_vfs_volume_unref (volume);
+		}
+		g_list_free (volumes);
 	}
 }
 
 static void
+desktop_volumes_visible_changed (gpointer callback_data)
+{
+	NautilusDesktopLinkMonitor *monitor;
+
+	monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data);
+	refresh_volume_links (monitor);
+}
+
+static void
 create_link_and_add_preference (NautilusDesktopLink   **link_ref,
 				NautilusDesktopLinkType link_type,
 				const char             *preference_key,
@@ -365,8 +614,6 @@ static void
 nautilus_desktop_link_monitor_init (gpointer object, gpointer klass)
 {
 	NautilusDesktopLinkMonitor *monitor;
-	GList *l, *volumes;
-	GnomeVFSVolume *volume;
 	GnomeVFSVolumeMonitor *volume_monitor;
 
 	monitor = NAUTILUS_DESKTOP_LINK_MONITOR (object);
@@ -404,22 +651,22 @@ nautilus_desktop_link_monitor_init (gpoi
 					desktop_network_visible_changed,
 					monitor);
 
-	/* Volume links */
+	/* Drives and volumes */
 
-	volume_monitor = gnome_vfs_get_volume_monitor ();
-	
-	volumes = gnome_vfs_volume_monitor_get_mounted_volumes (volume_monitor);
-	for (l = volumes; l != NULL; l = l->next) {
-		volume = l->data;
-		create_volume_link (monitor, volume);
-		gnome_vfs_volume_unref (volume);
-	}
-	g_list_free (volumes);
+	refresh_volume_links (monitor);
 
 	eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_VOLUMES_VISIBLE,
 				      desktop_volumes_visible_changed,
 				      monitor);
 
+	volume_monitor = gnome_vfs_get_volume_monitor ();
+
+	monitor->details->connected_id = g_signal_connect_object (volume_monitor, "drive_connected",
+								  G_CALLBACK (drive_connected_callback),
+								  monitor, 0);
+	monitor->details->disconnected_id = g_signal_connect_object (volume_monitor, "drive_disconnected",
+								     G_CALLBACK (drive_disconnected_callback),
+								     monitor, 0);
 	monitor->details->mount_id = g_signal_connect_object (volume_monitor, "volume_mounted",
 							      G_CALLBACK (volume_mounted_callback), monitor, 0);
 	monitor->details->unmount_id = g_signal_connect_object (volume_monitor, "volume_unmounted",
Index: libnautilus-private/nautilus-desktop-link.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-desktop-link.c,v
retrieving revision 1.14
diff -u -p -r1.14 nautilus-desktop-link.c
--- libnautilus-private/nautilus-desktop-link.c	18 Mar 2006 07:13:49 -0000	1.14
+++ libnautilus-private/nautilus-desktop-link.c	6 Oct 2006 00:32:43 -0000
@@ -53,8 +53,8 @@ struct NautilusDesktopLinkDetails {
 	/* Just for trash icons: */
 	gulong trash_state_handler;
 
-	/* Just for volume icons: */
-	GnomeVFSVolume *volume;
+	/* Just for drive/volume icons */
+	GObject *drive_or_volume;
 };
 
 static void nautilus_desktop_link_init       (gpointer              object,
@@ -192,28 +192,52 @@ nautilus_desktop_link_new (NautilusDeskt
 	return link;
 }
 
-NautilusDesktopLink *
-nautilus_desktop_link_new_from_volume (GnomeVFSVolume *volume)
+static void
+reread_drive_or_volume (NautilusDesktopLink *link)
 {
-	NautilusDesktopLink *link;
-	GnomeVFSDrive *drive;
 	char *name, *filename;
+	char *display_name, *activation_uri, *icon;
 
-	link = NAUTILUS_DESKTOP_LINK (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK, NULL));
-	
-	link->details->type = NAUTILUS_DESKTOP_LINK_VOLUME;
+	g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_VOLUME);
+	g_assert (link->details->drive_or_volume != NULL);
+
+	g_free (link->details->filename);
+	g_free (link->details->display_name);
+	g_free (link->details->activation_uri);
+	g_free (link->details->icon);
 
-	link->details->volume = gnome_vfs_volume_ref (volume);
+	if (GNOME_IS_VFS_VOLUME (link->details->drive_or_volume)) {
+		GnomeVFSVolume *volume;
+		GnomeVFSDrive *drive;
+
+		volume = GNOME_VFS_VOLUME (link->details->drive_or_volume);
+
+		/* We try to use the drive name to get somewhat stable filenames
+		   for metadata */
+		drive = gnome_vfs_volume_get_drive (volume);
+		if (drive != NULL) {
+			name = gnome_vfs_drive_get_display_name (drive);
+		} else {
+			name = gnome_vfs_volume_get_display_name (volume);
+		}
+		gnome_vfs_drive_unref (drive);
 
-	/* We try to use the drive name to get somewhat stable filenames
-	   for metadata */
-	drive = gnome_vfs_volume_get_drive (volume);
-	if (drive != NULL) {
-		name = gnome_vfs_drive_get_display_name (drive);
+		display_name = gnome_vfs_volume_get_display_name (volume);
+		activation_uri = gnome_vfs_volume_get_activation_uri (volume);
+		icon = gnome_vfs_volume_get_icon (volume);
 	} else {
-		name = gnome_vfs_volume_get_display_name (volume);
+		GnomeVFSDrive *drive;
+
+		g_assert (GNOME_IS_VFS_DRIVE (link->details->drive_or_volume));
+
+		drive = GNOME_VFS_DRIVE (link->details->drive_or_volume);
+
+		name = gnome_vfs_drive_get_display_name (drive);
+
+		display_name = gnome_vfs_drive_get_display_name (drive);
+		activation_uri = NULL; /* We don't know the activation URI until the drive gets mounted */
+		icon = gnome_vfs_drive_get_icon (drive);
 	}
-	gnome_vfs_drive_unref (drive);
 
 	filename = g_strconcat (name, ".volume", NULL);
 	link->details->filename =
@@ -221,21 +245,51 @@ nautilus_desktop_link_new_from_volume (G
 								    filename);
 	g_free (filename);
 	g_free (name);
+
+	link->details->display_name = display_name;
+	link->details->activation_uri = activation_uri;
+	link->details->icon = icon;
+}
+
+NautilusDesktopLink *
+nautilus_desktop_link_new_from_drive_or_volume (GObject *object)
+{
+	NautilusDesktopLink *link;
+	gboolean is_volume;
+
+	is_volume = GNOME_IS_VFS_VOLUME (object);
+
+	g_return_val_if_fail (GNOME_IS_VFS_DRIVE (object) || is_volume, NULL);
+
+	link = NAUTILUS_DESKTOP_LINK (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK, NULL));
 	
-	link->details->display_name = gnome_vfs_volume_get_display_name (volume);
-	
-	link->details->activation_uri = gnome_vfs_volume_get_activation_uri (volume);
-	link->details->icon = gnome_vfs_volume_get_icon (volume);
+	link->details->type = NAUTILUS_DESKTOP_LINK_VOLUME;
 
+	if (is_volume) {
+		GnomeVFSVolume *volume;
+
+		volume = gnome_vfs_volume_ref (GNOME_VFS_VOLUME (object));
+		link->details->drive_or_volume = G_OBJECT (volume);
+	} else {
+		GnomeVFSDrive *drive;
+
+		drive = gnome_vfs_drive_ref (GNOME_VFS_DRIVE (object));
+		link->details->drive_or_volume = G_OBJECT (drive);
+	}
+
+	reread_drive_or_volume (link);
 	create_icon_file (link);
 
 	return link;
 }
 
-GnomeVFSVolume *
-nautilus_desktop_link_get_volume (NautilusDesktopLink *link)
+GObject *
+nautilus_desktop_link_get_drive_or_volume (NautilusDesktopLink *link)
 {
-	return gnome_vfs_volume_ref (link->details->volume);
+	if (GNOME_IS_VFS_VOLUME (link->details->drive_or_volume))
+		return G_OBJECT (gnome_vfs_volume_ref (GNOME_VFS_VOLUME (link->details->drive_or_volume)));
+	else
+		return G_OBJECT (gnome_vfs_drive_ref (GNOME_VFS_DRIVE (link->details->drive_or_volume)));
 }
 
 
@@ -389,7 +443,11 @@ desktop_link_finalize (GObject *object)
 	}
 
 	if (link->details->type == NAUTILUS_DESKTOP_LINK_VOLUME) {
-		gnome_vfs_volume_unref (link->details->volume);
+		if (GNOME_IS_VFS_VOLUME (link->details->drive_or_volume)) {
+			gnome_vfs_volume_unref (GNOME_VFS_VOLUME (link->details->drive_or_volume));
+		} else {
+			gnome_vfs_drive_unref (GNOME_VFS_DRIVE (link->details->drive_or_volume));
+		}
 	}
 
 	g_free (link->details->filename);
@@ -410,4 +468,64 @@ nautilus_desktop_link_class_init (gpoint
 	
 	object_class->finalize = desktop_link_finalize;
 
+}
+
+void
+nautilus_desktop_link_update_from_volume (NautilusDesktopLink *link,
+					  GnomeVFSVolume      *volume)
+{
+	g_return_if_fail (NAUTILUS_IS_DESKTOP_LINK (link));
+	g_return_if_fail (GNOME_IS_VFS_VOLUME (volume));
+
+	g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_VOLUME);
+	g_assert (link->details->drive_or_volume != NULL);
+
+	if (GNOME_IS_VFS_DRIVE (link->details->drive_or_volume)) {
+		GnomeVFSDrive *drive;
+
+		drive = gnome_vfs_volume_get_drive (volume);
+
+		g_assert (G_OBJECT (drive) == G_OBJECT (link->details->drive_or_volume));
+		gnome_vfs_drive_unref (drive);
+
+		/* The link is for a drive.  If the new volume is mounted,
+		 * replace the link's object with the volume.  If the new volume
+		 * is unmounted, just refresh the link (who knows why we didn't
+		 * get the mount notification before).
+		 */
+
+		if (gnome_vfs_volume_is_mounted (volume)) {
+			gnome_vfs_drive_unref (GNOME_VFS_DRIVE (link->details->drive_or_volume));
+
+			gnome_vfs_volume_ref (volume);
+			link->details->drive_or_volume = G_OBJECT (volume);
+		}
+
+		/* The link will get updated below */
+	} else {
+		g_assert (GNOME_IS_VFS_VOLUME (link->details->drive_or_volume));
+
+		/* Do we need to use gnome_vfs_volume_compare()? */
+		g_assert (GNOME_VFS_VOLUME (link->details->drive_or_volume) == volume);
+
+		/* If the volume got unmounted, restore the link's object to the
+		 * corresponding drive.  Otherwise, we shouldn't need to be
+		 * called, but just update the link in that case.
+		 */
+
+		if (!gnome_vfs_volume_is_mounted (volume)) {
+			GnomeVFSDrive *drive;
+
+			drive = gnome_vfs_volume_get_drive (volume);
+
+			gnome_vfs_volume_unref (GNOME_VFS_VOLUME (link->details->drive_or_volume));
+
+			link->details->drive_or_volume = G_OBJECT (drive);
+		}
+
+		/* The link will get updated below */
+	}
+
+	reread_drive_or_volume (link);
+	nautilus_desktop_link_changed (link);
 }
Index: libnautilus-private/nautilus-desktop-link.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-desktop-link.h,v
retrieving revision 1.4
diff -u -p -r1.4 nautilus-desktop-link.h
--- libnautilus-private/nautilus-desktop-link.h	10 Dec 2005 02:40:35 -0000	1.4
+++ libnautilus-private/nautilus-desktop-link.h	6 Oct 2006 00:32:43 -0000
@@ -26,6 +26,7 @@
 #define NAUTILUS_DESKTOP_LINK_H
 
 #include <libnautilus-private/nautilus-file.h>
+#include <libgnomevfs/gnome-vfs-drive.h>
 #include <libgnomevfs/gnome-vfs-volume.h>
 
 #define NAUTILUS_TYPE_DESKTOP_LINK \
@@ -61,7 +62,7 @@ typedef enum {
 GType   nautilus_desktop_link_get_type (void);
 
 NautilusDesktopLink *   nautilus_desktop_link_new                (NautilusDesktopLinkType  type);
-NautilusDesktopLink *   nautilus_desktop_link_new_from_volume    (GnomeVFSVolume          *volume);
+NautilusDesktopLink *   nautilus_desktop_link_new_from_drive_or_volume (GObject           *object);
 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);
@@ -70,10 +71,12 @@ char *                  nautilus_desktop
 gboolean                nautilus_desktop_link_get_date           (NautilusDesktopLink     *link,
 								  NautilusDateType         date_type,
 								  time_t                  *date);
-GnomeVFSVolume *        nautilus_desktop_link_get_volume         (NautilusDesktopLink     *link);
+GObject *               nautilus_desktop_link_get_drive_or_volume (NautilusDesktopLink     *link);
 
 gboolean                nautilus_desktop_link_can_rename         (NautilusDesktopLink     *link);
 gboolean                nautilus_desktop_link_rename             (NautilusDesktopLink     *link,
 								  const char              *name);
+void                    nautilus_desktop_link_update_from_volume (NautilusDesktopLink     *link,
+								  GnomeVFSVolume          *volume);
 
 #endif /* NAUTILUS_DESKTOP_LINK_H */
Index: src/file-manager/fm-directory-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-directory-view.c,v
retrieving revision 1.750
diff -u -p -r1.750 fm-directory-view.c
--- src/file-manager/fm-directory-view.c	8 Aug 2006 14:43:25 -0000	1.750
+++ src/file-manager/fm-directory-view.c	6 Oct 2006 00:32:46 -0000
@@ -8498,7 +8498,7 @@ activation_drive_mounted_callback (gbool
 
 	parameters = callback_data;
 
-	parameters->mount_success &= succeeded;
+	parameters->mount_success = parameters->mount_success && succeeded;
 
 	if (!succeeded && !parameters->cancelled) {
 		if (*error == 0 &&
2006-05-22  Federico Mena Quintero  <federico novell com>

	* src/file-manager/fm-directory-view.c (ActivateParameters): Added
	a file_changed_id field.
	(fm_directory_view_activate_file): Initialize
	parameters->file_changed_id to 0.
	(activation_drive_mounted_callback): If the drive thinks it is not
	mounted yet, it is because gnome-vfs-volume-monitor hasn't emitted
	its volume_mounted signal yet.  In that case, wait for the
	parameters->file to change --- that will let us know that the
	drive really got mounted.
	(activation_file_changed_after_drive_mounted): New function to
	handle the "changed" signal on parameters->file from above.
	Actually call activate_activation_uri_ready_callback() here, since
	the drive now really knows that it is mounted, and
	parameters->file has been updated with its activation URI.

diff -uNrp nautilus-old/src/file-manager/fm-directory-view.c nautilus-new/src/file-manager/fm-directory-view.c
--- nautilus-old/src/file-manager/fm-directory-view.c	2006-06-01 13:18:34.000000000 -0500
+++ nautilus-new/src/file-manager/fm-directory-view.c	2006-06-01 13:26:18.000000000 -0500
@@ -278,6 +278,7 @@ typedef struct {
 	gboolean mounted;
 	gboolean mounting;
 	gboolean cancelled;
+	gulong file_changed_id;
 } ActivateParameters;
 
 enum {
@@ -7385,6 +7386,25 @@ activate_callback (NautilusFile *file, g
 }
 
 static void
+activation_file_changed_after_drive_mounted (NautilusFile *file,
+					     gpointer data)
+{
+	ActivateParameters *parameters;
+	GnomeVFSDrive *drive;
+
+	parameters = data;
+
+	drive = nautilus_file_get_drive (parameters->file); /* we don't own this reference */
+	g_assert (drive != NULL);
+	g_assert (gnome_vfs_drive_is_mounted (drive));
+
+	g_signal_handler_disconnect (parameters->file, parameters->file_changed_id);
+	parameters->file_changed_id = 0;
+
+	activate_activation_uri_ready_callback (parameters->file, parameters);
+}
+
+static void
 activation_drive_mounted_callback (gboolean succeeded,
 				   char *error,
 				   char *detailed_error,
@@ -7398,9 +7418,35 @@ activation_drive_mounted_callback (gbool
 	parameters->mounting = FALSE;
 	
 	if (succeeded && !parameters->cancelled) {
-		activate_activation_uri_ready_callback (parameters->file,
-							parameters);
+		GnomeVFSDrive *drive;
+
+		/* fprintf (stderr, "LOG: activation_drive_mounted_callback(): drive got mounted successfully\n"); */
+
+		drive = nautilus_file_get_drive (parameters->file); /* we don't own this reference */
+		g_assert (drive != NULL);
+
+		if (gnome_vfs_drive_is_mounted (drive)) {
+			/* fprintf (stderr, "LOG: activation_drive_mounted_callback(): drive is really mounted; activating...\n"); */
+			activate_activation_uri_ready_callback (parameters->file,
+								parameters);
+		} else {
+			/* Hack alert:  Here, the drive is already mounted, but
+			 * gnome-vfs-volume-monitor thinks that it is not.  This
+			 * is because gnome-vfs-daemon has not yet notified it.
+			 * So we'll wait for the parameters->file to change:
+			 * this will happen when gnome-vfs-volume-monitor
+			 * actually picks up and emits the volume_mounted
+			 * notification, and the NautilusDesktopLink modifies
+			 * the NautilusFile.
+			 */
+			/* fprintf (stderr, "LOG: activation_drive_mounted_callback(): delaying activation...\n"); */
+			parameters->file_changed_id =
+				g_signal_connect (parameters->file, "changed",
+						  G_CALLBACK (activation_file_changed_after_drive_mounted),
+						  parameters);
+		}
 	} else {
+		/* fprintf (stderr, "LOG: activation_drive_mounted_callback(): drive didn't get mounted\n"); */
 		if (!parameters->cancelled) {
 			stop_activate (parameters);
 
@@ -7448,6 +7494,7 @@ activate_activation_uri_ready_callback (
 		if (drive != NULL &&
 		    !gnome_vfs_drive_is_mounted (drive)) {
 			parameters->mounting = TRUE;
+			/* fprintf (stderr, "LOG: activate_activation_uri_ready_callback() calling gnome_vfs_drive_mount()\n"); */
 			gnome_vfs_drive_mount (drive, activation_drive_mounted_callback, callback_data);
 			return;
 		}
@@ -7458,6 +7505,7 @@ activate_activation_uri_ready_callback (
 	 */
 	actual_file = NULL;
 	uri = nautilus_file_get_activation_uri (file);
+	/* fprintf (stderr, "LOG: activate_activation_uri_ready_callback() got activation uri %s\n", uri); */
 	if (!(eel_str_has_prefix (uri, NAUTILUS_DESKTOP_COMMAND_SPECIFIER) ||
 	      eel_str_has_prefix (uri, NAUTILUS_COMMAND_SPECIFIER))) {
 		actual_file = nautilus_file_get (uri);
@@ -7528,6 +7576,7 @@ fm_directory_view_activate_file (FMDirec
 	parameters->mounted = FALSE;
 	parameters->mounting = FALSE;
 	parameters->cancelled = FALSE;
+	parameters->file_changed_id = 0;
 
 	file_name = nautilus_file_get_display_name (file);
 	timed_wait_prompt = g_strdup_printf (_("Opening \"%s\"."), file_name);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]