Index: libgnomevfs/gnome-vfs-volume-monitor.h
===================================================================
--- libgnomevfs/gnome-vfs-volume-monitor.h	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume-monitor.h	(Arbeitskopie)
@@ -61,6 +61,8 @@ struct _GnomeVFSVolumeMonitorClass {
 				   	 GnomeVFSDrive	       *drive);
 	void (* drive_disconnected)	(GnomeVFSVolumeMonitor *volume_monitor,
 				   	 GnomeVFSDrive         *drive);
+	void (* volume_changed)	  	(GnomeVFSVolumeMonitor *volume_monitor,
+				   	 GnomeVFSVolume	       *volume);
 };
 
 GType gnome_vfs_volume_monitor_get_type (void) G_GNUC_CONST;
Index: libgnomevfs/gnome-vfs-volume-monitor-daemon.c
===================================================================
--- libgnomevfs/gnome-vfs-volume-monitor-daemon.c	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume-monitor-daemon.c	(Arbeitskopie)
@@ -505,18 +505,32 @@ get_icon_from_type (GnomeVFSDeviceType t
 	return g_strdup (icon_name);
 }
 
-
+/* major_compare affects added and removed.
+ * If an item is neither added nor removed,
+ * and minor_compare does not return 0, it
+ * is added to changed.
+ */
 static void
-diff_sorted_lists (GList *list1, GList *list2, GCompareFunc compare,
-		   GList **added, GList **removed)
+diff_sorted_lists (GList *list1, GList *list2,
+		   GCompareFunc major_compare,
+		   GCompareFunc minor_compare,
+		   GList **added, GList **removed,
+		   GList **changed)
 {
 	int order;
-	
+
+	g_assert (!(minor_compare == NULL && changed != NULL));
+	g_assert (!(minor_compare != NULL && changed == NULL));
+
 	*added = *removed = NULL;
 
+	if (changed != NULL) {
+		*changed = NULL;
+	}
+
 	while (list1 != NULL &&
 	       list2 != NULL) {
-		order = (*compare) (list1->data, list2->data);
+		order = (*major_compare) (list1->data, list2->data);
 		if (order < 0) {
 			*removed = g_list_prepend (*removed, list1->data);
 			list1 = list1->next;
@@ -524,6 +538,10 @@ diff_sorted_lists (GList *list1, GList *
 			*added = g_list_prepend (*added, list2->data);
 			list2 = list2->next;
 		} else { /* same item */
+			if (minor_compare != NULL && (* minor_compare) (list1->data, list2->data)) {
+				*changed = g_list_prepend (*changed, list2->data);
+			}
+
 			list1 = list1->next;
 			list2 = list2->next;
 		}
@@ -734,7 +752,7 @@ update_fstab_drives (GnomeVFSVolumeMonit
 		
 		diff_sorted_lists (volume_monitor_daemon->last_fstab,
 				   new_fstab, (GCompareFunc) _gnome_vfs_unix_mount_point_compare,
-				   &added, &removed);
+				   NULL, &added, &removed, NULL);
 
 		for (l = removed; l != NULL; l = l->next) {
 			mount = l->data;
@@ -1022,7 +1040,7 @@ update_mtab_volumes (GnomeVFSVolumeMonit
 		
 		diff_sorted_lists (volume_monitor_daemon->last_mtab,
 				   new_mtab, (GCompareFunc) _gnome_vfs_unix_mount_compare,
-				   &added, &removed);
+				   NULL, &added, &removed, NULL);
 
 		for (l = removed; l != NULL; l = l->next) {
 			GnomeVFSUnixMount *mount = l->data;
@@ -1098,6 +1116,13 @@ connected_server_free (GnomeVFSConnected
 }
 
 static int
+connected_server_id_compare (GnomeVFSConnectedServer *a,
+			     GnomeVFSConnectedServer *b)
+{
+	return strcmp (a->id, b->id);
+}
+
+static int
 connected_server_compare (GnomeVFSConnectedServer *a,
 			  GnomeVFSConnectedServer *b)
 {
@@ -1223,7 +1248,7 @@ update_connected_servers (GnomeVFSVolume
 {
 	GList *new_servers;
 	GnomeVFSVolumeMonitor *volume_monitor;
-	GList *removed, *added;
+	GList *removed, *added, *changed;
 	GnomeVFSConnectedServer *server;
 	GnomeVFSVolume *volume;
 	GList *l;
@@ -1232,9 +1257,10 @@ update_connected_servers (GnomeVFSVolume
 
 	new_servers = get_connected_servers (volume_monitor_daemon);
 	new_servers = g_list_sort (new_servers, (GCompareFunc) connected_server_compare);
-	diff_sorted_lists (volume_monitor_daemon->last_connected_servers,
-			   new_servers, (GCompareFunc) connected_server_compare,
-			   &added, &removed);
+	diff_sorted_lists (volume_monitor_daemon->last_connected_servers, new_servers,
+			   (GCompareFunc) connected_server_id_compare,
+			   (GCompareFunc) connected_server_compare,
+			   &added, &removed, &changed);
 
 	for (l = removed; l != NULL; l = l->next) {
 		server = l->data;
@@ -1242,6 +1268,33 @@ update_connected_servers (GnomeVFSVolume
 		
 		if (volume != NULL) {
 			_gnome_vfs_volume_monitor_unmounted (volume_monitor, volume);
+		} else {
+			g_warning ("failed to look up removed server %s (%s), ID %s. Ignoring.",
+				   server->display_name, server->uri, server->id);
+		}
+	}
+
+	for (l = changed; l != NULL; l = l->next) {
+		server = l->data;
+
+		volume = _gnome_vfs_volume_monitor_find_connected_server_by_gconf_id (volume_monitor, server->id);
+		if (volume != NULL) {
+			char *display_name;
+
+			if (server->display_name == NULL || volume->priv->display_name == NULL
+			    || strcmp (server->display_name, volume->priv->display_name)) {
+				display_name = _gnome_vfs_volume_monitor_uniquify_volume_name (volume_monitor, server->display_name);
+			} else {
+				/* don't uniquify name if it matches the old one */
+				display_name = g_strdup (volume->priv->display_name);
+			}
+
+			gnome_vfs_volume_update (volume, display_name, server->uri, server->icon);
+			gnome_vfs_volume_monitor_emit_changed (volume_monitor, volume);
+			g_free (display_name);
+		} else {
+			g_warning ("failed to look up changed server %s (%s), ID %s. Ignoring.",
+				   server->display_name, server->uri, server->id);
 		}
 	}
 	
@@ -1252,9 +1305,10 @@ update_connected_servers (GnomeVFSVolume
 		_gnome_vfs_volume_monitor_mounted (volume_monitor, volume);
 		gnome_vfs_volume_unref (volume);
 	}
-	
+
 	g_list_free (added);
 	g_list_free (removed);
+	g_list_free (changed);
 	g_list_foreach (volume_monitor_daemon->last_connected_servers,
 			(GFunc)connected_server_free, NULL);
 	g_list_free (volume_monitor_daemon->last_connected_servers);
Index: libgnomevfs/gnome-vfs-dbus-utils.h
===================================================================
--- libgnomevfs/gnome-vfs-dbus-utils.h	(Revision 5340)
+++ libgnomevfs/gnome-vfs-dbus-utils.h	(Arbeitskopie)
@@ -92,6 +92,7 @@ G_BEGIN_DECLS
 
 /* Volume monitor signals. */
 #define DVD_DAEMON_VOLUME_MOUNTED_SIGNAL            "VolumeMountedSignal"
+#define DVD_DAEMON_VOLUME_CHANGED_SIGNAL            "VolumeChangedSignal"
 #define DVD_DAEMON_VOLUME_UNMOUNTED_SIGNAL          "VolumeUnmountedSignal"
 #define DVD_DAEMON_VOLUME_PRE_UNMOUNT_SIGNAL        "VolumePreUnmountSignal"
 #define DVD_DAEMON_DRIVE_CONNECTED_SIGNAL           "DriveConnectedSignal"
Index: libgnomevfs/gnome-vfs-volume-ops.c
===================================================================
--- libgnomevfs/gnome-vfs-volume-ops.c	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume-ops.c	(Arbeitskopie)
@@ -1386,3 +1386,121 @@ gnome_vfs_connect_to_server (const char 
 	g_free (id);
 	g_object_unref (client);
 }
+
+static void
+volume_set_gconf_string (GnomeVFSVolume *volume,
+			 const char     *key,
+			 const char     *value)
+{
+	GConfClient *client;
+	char *full_key;
+
+	client = gconf_client_get_default ();
+
+	full_key = g_strconcat (CONNECTED_SERVERS_DIR "/",
+				volume->priv->gconf_id,
+				"/", key, NULL);
+	gconf_client_set_string (client, full_key, value, NULL);
+	g_free (full_key);
+}
+
+/** 
+ * gnome_vfs_volume_connected_server_set_activation_uri
+ * @volume: a #GnomeVFSVolume for which to set the activation URI
+ * @activation_uri: the new activation URI to use for @volume.
+ *
+ * Sets the activation URI of the specified #GnomeVFSVolume.
+ *
+ * <note>
+ * <para>
+ * This function may only be called for connected servers, i.e.
+ * volumes with a #GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER
+ * volume type.You can query the volume type using
+ * gnome_vfs_volume_get_volume_type().
+ * </para>
+ * <para>
+ * There is no guarantee that the activation URI will actually change. You
+ * will be notified with the "volume-changed" signal of the 
+ * #GnomeVFSVolumeMonitor when a change took place.
+ * </para>
+ * </note>
+ *
+ * Since: 2.18
+ */
+void
+gnome_vfs_volume_connected_server_set_activation_uri (GnomeVFSVolume *volume,
+						      const char     *activation_uri)
+{
+	g_return_if_fail (volume != NULL);
+	g_return_if_fail (volume->priv->volume_type == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER);
+	g_return_if_fail (activation_uri != NULL);
+
+	volume_set_gconf_string (volume, "uri", activation_uri);
+	force_probe ();
+}
+
+/** 
+ * gnome_vfs_volume_connected_server_set_display_name
+ * @volume: a #GnomeVFSVolume for which to set the display name
+ * @display_name: the new display name to use for @volume.
+ *
+ * <note>
+ * <para>
+ * This function may only be called for connected servers, i.e.
+ * volumes with a #GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER
+ * volume type.You can query the volume type using
+ * gnome_vfs_volume_get_volume_type().
+ * </para>
+ * <para>
+ * There is no guarantee that the display name will actually change. You
+ * will be notified with the "volume-changed" signal of the 
+ * #GnomeVFSVolumeMonitor when a change took place.
+ * </para>
+ * </note>
+ *
+ * Since: 2.18
+ */
+void
+gnome_vfs_volume_connected_server_set_display_name (GnomeVFSVolume *volume,
+						    const char     *display_name)
+{
+	g_return_if_fail (volume != NULL);
+	g_return_if_fail (volume->priv->volume_type == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER);
+	g_return_if_fail (display_name != NULL);
+
+	volume_set_gconf_string (volume, "display_name", display_name);
+	force_probe ();
+}
+
+/** 
+ * gnome_vfs_volume_connected_server_set_icon
+ * @volume: a #GnomeVFSVolume for which to set the display name
+ * @icon: the new icon to use for @volume.
+ *
+ * <note>
+ * <para>
+ * This function may only be called for connected servers, i.e.
+ * volumes with a #GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER
+ * volume type.You can query the volume type using
+ * gnome_vfs_volume_get_volume_type().
+ * </para>
+ * <para>
+ * There is no guarantee that the volume icon will actually change. You
+ * will be notified with the "volume-changed" signal of the 
+ * #GnomeVFSVolumeMonitor when a change took place.
+ * </para>
+ * </note>
+ *
+ * Since: 2.18
+ */
+void
+gnome_vfs_volume_connected_server_set_icon (GnomeVFSVolume *volume,
+					    const char     *icon)
+{
+	g_return_if_fail (volume != NULL);
+	g_return_if_fail (volume->priv->volume_type == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER);
+	g_return_if_fail (icon != NULL);
+
+	volume_set_gconf_string (volume, "icon", icon);
+	force_probe ();
+}
Index: libgnomevfs/gnome-vfs-volume-monitor-client.c
===================================================================
--- libgnomevfs/gnome-vfs-volume-monitor-client.c	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume-monitor-client.c	(Arbeitskopie)
@@ -314,6 +314,26 @@ dbus_filter_func (DBusConnection *connec
 	}
 	else if (dbus_message_is_signal (message,
 					 DVD_DAEMON_INTERFACE,
+					 DVD_DAEMON_VOLUME_CHANGED_SIGNAL)) {
+		GnomeVFSVolume *new_volume;
+
+		dbus_message_iter_init (message, &iter);
+		new_volume = _gnome_vfs_volume_from_dbus (&iter, volume_monitor);
+		volume = gnome_vfs_volume_monitor_get_volume_by_id (volume_monitor, new_volume->priv->id);
+		if (volume != NULL) {
+			gnome_vfs_volume_update (volume,
+						 new_volume->priv->display_name,
+						 new_volume->priv->activation_uri,
+						 new_volume->priv->icon);
+			gnome_vfs_volume_monitor_emit_changed (volume_monitor, volume);
+			gnome_vfs_volume_unref (volume);
+		} else {
+			g_message ("received change request for volume with unknown ID %ld", new_volume->priv->id);
+		}
+		gnome_vfs_volume_unref (new_volume);
+	}
+	else if (dbus_message_is_signal (message,
+					 DVD_DAEMON_INTERFACE,
 					 DVD_DAEMON_VOLUME_PRE_UNMOUNT_SIGNAL)) {
 		if (dbus_message_get_args (message, NULL,
 					   DBUS_TYPE_INT32, &id,
Index: libgnomevfs/gnome-vfs-volume-monitor-private.h
===================================================================
--- libgnomevfs/gnome-vfs-volume-monitor-private.h	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume-monitor-private.h	(Arbeitskopie)
@@ -99,6 +99,10 @@ struct _GnomeVFSDrivePrivate {
 
 void gnome_vfs_volume_set_drive_private         (GnomeVFSVolume        *volume,
 						 GnomeVFSDrive         *drive);
+void gnome_vfs_volume_update                    (GnomeVFSVolume        *volume,
+						 const char            *display_name,
+						 const char            *activation_uri,
+						 const char            *icon);
 void gnome_vfs_drive_add_mounted_volume_private (GnomeVFSDrive         *drive,
 						 GnomeVFSVolume        *volume);
 void gnome_vfs_drive_remove_volume_private      (GnomeVFSDrive         *drive,
@@ -117,6 +121,8 @@ void _gnome_vfs_volume_monitor_disconnec
 void _gnome_vfs_volume_monitor_unmount_all      (GnomeVFSVolumeMonitor *volume_monitor);
 void gnome_vfs_volume_monitor_emit_pre_unmount (GnomeVFSVolumeMonitor *volume_monitor,
 						GnomeVFSVolume        *volume);
+void gnome_vfs_volume_monitor_emit_changed     (GnomeVFSVolumeMonitor *volume_monitor,
+						GnomeVFSVolume        *volume);
 void _gnome_vfs_volume_monitor_force_probe (GnomeVFSVolumeMonitor *volume_monitor);
 
 GnomeVFSVolumeMonitor *_gnome_vfs_get_volume_monitor_internal (gboolean create);
Index: libgnomevfs/gnome-vfs-volume.c
===================================================================
--- libgnomevfs/gnome-vfs-volume.c	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume.c	(Arbeitskopie)
@@ -307,9 +307,15 @@ gnome_vfs_volume_get_device_path (GnomeV
 char *
 gnome_vfs_volume_get_activation_uri (GnomeVFSVolume *volume)
 {
+	char *ret;
+
 	g_return_val_if_fail (volume != NULL, NULL);
 
-	return g_strdup (volume->priv->activation_uri);
+	G_LOCK (volumes);
+	ret = g_strdup (volume->priv->activation_uri);
+	G_UNLOCK (volumes);
+
+	return ret;
 }
 
 /** 
@@ -445,9 +451,15 @@ gnome_vfs_volume_get_filesystem_type (Gn
 char *
 gnome_vfs_volume_get_display_name (GnomeVFSVolume *volume)
 {
+	char *ret;
+
 	g_return_val_if_fail (volume != NULL, NULL);
 
-	return g_strdup (volume->priv->display_name);
+	G_LOCK (volumes);
+	ret = g_strdup (volume->priv->display_name);
+	G_UNLOCK (volumes);
+
+	return ret;
 }
 
 /** 
@@ -461,9 +473,15 @@ gnome_vfs_volume_get_display_name (Gnome
 char *
 gnome_vfs_volume_get_icon (GnomeVFSVolume *volume)
 {
+	char *ret;
+
 	g_return_val_if_fail (volume != NULL, NULL);
 
-	return g_strdup (volume->priv->icon);
+	G_LOCK (volumes);
+	ret = g_strdup (volume->priv->icon);
+	G_UNLOCK (volumes);
+
+	return ret;
 }
 
 /** 
@@ -774,7 +792,6 @@ _gnome_vfs_volume_from_dbus (DBusMessage
 	gint32                 i;
 
 	g_return_val_if_fail (iter != NULL, NULL);
-	g_return_val_if_fail (volume_monitor != NULL, NULL);
 	
 	g_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRUCT);
 
@@ -796,7 +813,7 @@ _gnome_vfs_volume_from_dbus (DBusMessage
 
 	dbus_message_iter_next (&struct_iter);
 	dbus_message_iter_get_basic (&struct_iter, &i);
-	if (i != 0) {
+	if (i != 0 && volume_monitor != NULL) {
 		priv->drive = gnome_vfs_volume_monitor_get_drive_by_id (
 			volume_monitor, i);
 		
@@ -853,3 +870,43 @@ _gnome_vfs_volume_from_dbus (DBusMessage
 }
 
 #endif
+
+void
+gnome_vfs_volume_update (GnomeVFSVolume *volume,
+			 const char     *display_name,
+			 const char     *activation_uri,
+			 const char     *icon)
+{
+	g_assert (volume != NULL);
+
+	G_LOCK (volumes);
+
+	if (volume->priv->display_name == NULL || display_name == NULL ||
+	    strcmp (volume->priv->display_name, display_name)) {
+		g_free (volume->priv->display_name);
+		volume->priv->display_name = g_strdup (display_name);
+
+		g_free (volume->priv->display_name_key);
+		if (volume->priv->display_name != NULL) {
+			char *tmp = g_utf8_casefold (volume->priv->display_name, -1);
+			volume->priv->display_name_key = g_utf8_collate_key (tmp, -1);
+			g_free (tmp);
+		} else {
+			volume->priv->display_name_key = NULL;
+		}
+	}
+
+	if (volume->priv->activation_uri == NULL || activation_uri == NULL ||
+	    strcmp (volume->priv->activation_uri, activation_uri)) {
+		g_free (volume->priv->activation_uri);
+		volume->priv->activation_uri = g_strdup (activation_uri);
+	}
+
+	if (volume->priv->icon == NULL || icon == NULL ||
+	    strcmp (volume->priv->icon, icon)) {
+		g_free (volume->priv->icon);
+		volume->priv->icon = g_strdup (icon);
+	}
+
+	G_UNLOCK (volumes);
+}
Index: libgnomevfs/gnome-vfs-volume.h
===================================================================
--- libgnomevfs/gnome-vfs-volume.h	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume.h	(Arbeitskopie)
@@ -178,6 +178,12 @@ gboolean           gnome_vfs_volume_hand
 gint               gnome_vfs_volume_compare             (GnomeVFSVolume *a,
 							 GnomeVFSVolume *b);
 
+void gnome_vfs_volume_connected_server_set_activation_uri (GnomeVFSVolume *volume,
+							   const char     *activation_uri);
+void gnome_vfs_volume_connected_server_set_display_name   (GnomeVFSVolume *volume,
+							   const char     *display_name);
+void gnome_vfs_volume_connected_server_set_icon           (GnomeVFSVolume *volume,
+							   const char     *icon);
 
 void gnome_vfs_volume_unmount    (GnomeVFSVolume           *volume,
 				  GnomeVFSVolumeOpCallback  callback,
Index: libgnomevfs/gnome-vfs-volume-monitor.c
===================================================================
--- libgnomevfs/gnome-vfs-volume-monitor.c	(Revision 5340)
+++ libgnomevfs/gnome-vfs-volume-monitor.c	(Arbeitskopie)
@@ -46,6 +46,7 @@ static void gnome_vfs_volume_monitor_fin
 enum
 {
 	VOLUME_MOUNTED,
+	VOLUME_CHANGED,
 	VOLUME_PRE_UNMOUNT,
 	VOLUME_UNMOUNTED,
 	DRIVE_CONNECTED,
@@ -118,6 +119,28 @@ gnome_vfs_volume_monitor_class_init (Gno
 			      GNOME_VFS_TYPE_VOLUME);
 
 	/**
+	 * GnomeVFSVolumeMonitor::volume-changed:
+	 * @volume_monitor: the #GnomeVFSVolumeMonitor which received the signal.
+	 * @volume: the #GnomeVFSVolume that has been changed.
+	 *
+	 * This signal is emitted after the #GnomeVFSVolume @volume has been changed.
+	 *
+	 * This is usually the result of a call to one of
+	 * gnome_vfs_volume_connected_server_set_activation_uri(),
+	 * gnome_vfs_volume_connected_server_set_display_name(),
+	 * gnome_vfs_volume_connected_server_set_icon().
+	 **/
+	volume_monitor_signals[VOLUME_CHANGED] =
+		g_signal_new ("volume_changed",
+			      G_TYPE_FROM_CLASS (o_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (GnomeVFSVolumeMonitorClass, volume_changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE, 1,
+			      GNOME_VFS_TYPE_VOLUME);
+
+	/**
 	 * GnomeVFSVolumeMonitor::volume-pre-unmount:
 	 * @volume_monitor: the #GnomeVFSVolumeMonitor which received the signal.
 	 * @volume: the #GnomeVFSVolume that is about to be unmounted.
@@ -873,6 +896,22 @@ gnome_vfs_volume_monitor_emit_pre_unmoun
 	g_signal_emit (volume_monitor, volume_monitor_signals[VOLUME_PRE_UNMOUNT], 0, volume);
 }
 
+/** 
+ * gnome_vfs_volume_monitor_emit_changed:
+ * @volume_monitor: a #GnomeVFSVolumeMonitor.
+ * @volume: a #GnomeVFSVolume.
+ *
+ * Emits the "changed" signal on @volume. 
+ *
+ * Since: 2.18
+ */
+void
+gnome_vfs_volume_monitor_emit_changed (GnomeVFSVolumeMonitor *volume_monitor,
+				       GnomeVFSVolume        *volume)
+{
+	g_signal_emit (volume_monitor, volume_monitor_signals[VOLUME_CHANGED], 0, volume);
+}
+
 void
 _gnome_vfs_volume_monitor_mounted (GnomeVFSVolumeMonitor *volume_monitor,
 				   GnomeVFSVolume        *volume)
Index: test/test-volumes.c
===================================================================
--- test/test-volumes.c	(Revision 5340)
+++ test/test-volumes.c	(Arbeitskopie)
@@ -69,6 +69,14 @@ volume_mounted (GnomeVFSVolumeMonitor *v
 }
 
 static void
+volume_changed (GnomeVFSVolumeMonitor *volume_monitor,
+		GnomeVFSVolume	      *volume)
+{
+	g_print ("Volume changed: ");
+	print_volume (volume);
+}
+
+static void
 volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
 		  GnomeVFSVolume	       *volume)
 {
@@ -104,6 +112,8 @@ main (int argc, char *argv[])
 
   g_signal_connect (monitor, "volume_mounted",
 		    G_CALLBACK (volume_mounted), NULL);
+  g_signal_connect (monitor, "volume_changed",
+		    G_CALLBACK (volume_changed), NULL);
   g_signal_connect (monitor, "volume_unmounted",
 		    G_CALLBACK (volume_unmounted), NULL);
   g_signal_connect (monitor, "drive_connected",
Index: test/Makefile.am
===================================================================
--- test/Makefile.am	(Revision 5340)
+++ test/Makefile.am	(Arbeitskopie)
@@ -5,6 +5,7 @@ INCLUDES =					\
 	-I$(top_builddir)			\
 	-I$(top_builddir)/libgnomevfs           \
 	$(TEST_CFLAGS)				\
+	$(GTK_CFLAGS)				\
 	$(VFS_CFLAGS)				\
 	-DG_DISABLE_DEPRECATED			\
 	-DMODULES_PATH=\"$(libdir)/vfs/modules\"
@@ -47,8 +48,14 @@ noinst_PROGRAMS =				\
 	test-callback				\
 	test-module-selftest			\
 	test-queue				\
-	$(platform_only_programs)		\
-	$(NULL)
+	$(platform_only_programs)
+
+if HAVE_GTK
+noinst_PROGRAMS += \
+		test-gtk-volume-editor
+endif
+
+noinst_PROGRAMS += $(NULL)
 
 test_files=		\
 	test.input	\
@@ -70,6 +77,7 @@ TESTS = test-acl	  \
 libraries =						\
 	$(top_builddir)/libgnomevfs/libgnomevfs-2.la	\
 	$(TEST_LIBS)					\
+	$(GTK_LIBS)					\
 	$(LIBEFS_LIBS)
 
 test_acl_SOURCES = test-acl.c
@@ -186,6 +194,12 @@ test_module_selftest_LDADD = $(libraries
 test_queue_SOURCES = test-queue.c
 test_queue_LDADD = $(libraries)
 
+if HAVE_GTK
+test_gtk_volume_editor_SOURCES = test-gtk-volume-editor.c
+test_gtk_volume_editor_LDADD = $(libraries)
+endif
+
+
 EXTRA_DIST =					\
 	$(test_files)				\
 	auto-test				\
Index: configure.in
===================================================================
--- configure.in	(Revision 5340)
+++ configure.in	(Arbeitskopie)
@@ -115,6 +115,14 @@ PKG_CHECK_MODULES(TEST, gconf-2.0 >= $GC
 AC_SUBST(TEST_LIBS)
 AC_SUBST(TEST_CFLAGS)
 
+PKG_CHECK_MODULES(GTK, gtk+-2.0, [have_gtk=yes],[have_gtk=no])
+if test x"$have_gtk" = "xyes" ; then
+  AC_DEFINE(HAVE_GTK, $have_gtk != no, [Define to 1 if GTK+ is available])
+fi
+AM_CONDITIONAL(HAVE_GTK, test $have_gtk = yes)
+AC_SUBST(GTK_LIBS)
+AC_SUBST(GTK_CFLAGS)
+
 cflags_set=yes
 GNOME_COMPILE_WARNINGS
 VFS_CFLAGS="$warnCFLAGS $complCFLAGS"
Index: daemon/vfs-daemon.c
===================================================================
--- daemon/vfs-daemon.c	(Revision 5340)
+++ daemon/vfs-daemon.c	(Arbeitskopie)
@@ -792,6 +792,31 @@ monitor_volume_mounted_cb (GnomeVFSVolum
 }
 
 static void
+monitor_volume_changed_cb (GnomeVFSVolumeMonitor *monitor,
+			   GnomeVFSVolume        *volume,
+			   gpointer               user_data)
+{
+	DBusConnection *conn;
+	DBusMessage    *signal;
+
+	d(g_print ("daemon got volume_changed\n"));
+
+	conn = daemon_get_connection (FALSE);
+	if (!conn) {
+		return;
+	}
+
+	signal = dbus_message_new_signal (DVD_DAEMON_OBJECT,
+					  DVD_DAEMON_INTERFACE,
+					  DVD_DAEMON_VOLUME_CHANGED_SIGNAL);
+
+	dbus_utils_message_append_volume (signal, volume);
+
+	dbus_connection_send (conn, signal, NULL);
+	dbus_message_unref (signal);
+}
+
+static void
 monitor_volume_unmounted_cb (GnomeVFSVolumeMonitor *monitor,
 			     GnomeVFSVolume        *volume,
 			     gpointer               user_data)
@@ -949,6 +974,10 @@ main (int argc, char *argv[])
 			  G_CALLBACK (monitor_volume_mounted_cb),
 			  NULL);
 	g_signal_connect (monitor,
+			  "volume_changed",
+			  G_CALLBACK (monitor_volume_changed_cb),
+			  NULL);
+	g_signal_connect (monitor,
 			  "volume_unmounted",
 			  G_CALLBACK (monitor_volume_unmounted_cb),
 			  NULL);
0a1,608
> #include <gtk/gtk.h>
> #include <libgnomevfs/gnome-vfs.h>
> 
> static GnomeVFSVolumeMonitor *monitor;
> 
> static int
> volume_iter_compare_func (GtkTreeModel *model,
> 			  GtkTreeIter  *a,
> 			  GtkTreeIter  *b,
> 			  gpointer      data)
> {
> 	GnomeVFSVolume *a_vol, *b_vol;
> 
> 	gtk_tree_model_get (model, a, 0, &a_vol, -1);
> 	gtk_tree_model_get (model, b, 0, &b_vol, -1);
> 
> 	return gnome_vfs_volume_compare (a_vol, b_vol);
> }
> 
> static GtkTreeModel *
> make_volume_tree_model (void)
> {
> 	GList *volumes, *l;
> 	GtkListStore *store;
> 
> 	store = gtk_list_store_new (1, GNOME_VFS_TYPE_VOLUME);
> 
> 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), 0,
> 					 volume_iter_compare_func, NULL, NULL);
> 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0, GTK_SORT_ASCENDING);
> 
> 	volumes = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
> 	for (l = volumes; l != NULL; l = l->next) {
> 		GtkTreeIter iter;
> 
> 		gtk_list_store_append (store, &iter);
> 		gtk_list_store_set (store, &iter, 0, l->data, -1);
> 	}
> 	g_list_free (volumes);
> 
> 	return GTK_TREE_MODEL (store);
> }
> 
> static void
> volume_name_data_func (GtkTreeViewColumn *col,
> 		       GtkCellRenderer   *renderer,
> 		       GtkTreeModel      *model,
> 		       GtkTreeIter       *iter,
> 		       gpointer           data)
> {
> 	GnomeVFSVolume *volume;
> 	char *name;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_object_set (G_OBJECT (renderer),
> 		      "text", name,
> 		      "editable", gnome_vfs_volume_get_volume_type (volume) == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER,
> 		      NULL);
> 	g_free (name);
> }
> 
> static void
> volume_uri_data_func (GtkTreeViewColumn *col,
> 		      GtkCellRenderer   *renderer,
> 		      GtkTreeModel      *model,
> 		      GtkTreeIter       *iter,
> 		      gpointer           data)
> {
> 	GnomeVFSVolume *volume;
> 	char *uri;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	uri = gnome_vfs_volume_get_activation_uri (volume);
> 	g_object_set (G_OBJECT (renderer),
> 		      "text", uri,
> 		      "editable", gnome_vfs_volume_get_volume_type (volume) == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER,
> 		      NULL);
> 	g_free (uri);
> }
> 
> static void
> volume_icon_data_func (GtkTreeViewColumn *col,
> 		       GtkCellRenderer   *renderer,
> 		       GtkTreeModel      *model,
> 		       GtkTreeIter       *iter,
> 		       gpointer           data)
> {
> 	GnomeVFSVolume *volume;
> 	char *icon;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	icon = gnome_vfs_volume_get_icon (volume);
> 	g_object_set (G_OBJECT (renderer),
> 		      "text", icon,
> 		      "editable", gnome_vfs_volume_get_volume_type (volume) == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER,
> 		      NULL);
> 	g_free (icon);
> }
> 
> static void
> name_renderer_edited (GtkCellRendererText *renderer,
> 		      char                *path,
> 		      char                *str,
> 		      GtkTreeView         *volume_view)
> {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter iter;
> 	gboolean success;
> 
> 	success = gtk_tree_model_get_iter_from_string (gtk_tree_view_get_model (volume_view), &iter, path);
> 	g_assert (success);
> 
> 	gtk_tree_model_get (gtk_tree_view_get_model (volume_view), &iter, 0, &volume, -1);
> 	gnome_vfs_volume_connected_server_set_display_name (volume, str);
> }
> 
> static void
> uri_renderer_edited (GtkCellRendererText *renderer,
> 		     char                *path,
> 		     char                *str,
> 		     GtkTreeView         *volume_view)
> {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter iter;
> 	gboolean success;
> 
> 	success = gtk_tree_model_get_iter_from_string (gtk_tree_view_get_model (volume_view), &iter, path);
> 	g_assert (success);
> 
> 	gtk_tree_model_get (gtk_tree_view_get_model (volume_view), &iter, 0, &volume, -1);
> 	gnome_vfs_volume_connected_server_set_activation_uri (volume, str);
> }
> 
> static void
> icon_renderer_edited (GtkCellRendererText *renderer,
> 		      char                *path,
> 		      char                *str,
> 		      GtkTreeView         *volume_view)
> {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter iter;
> 	gboolean success;
> 
> 	success = gtk_tree_model_get_iter_from_string (gtk_tree_view_get_model (volume_view), &iter, path);
> 	g_assert (success);
> 
> 	gtk_tree_model_get (gtk_tree_view_get_model (volume_view), &iter, 0, &volume, -1);
> 	gnome_vfs_volume_connected_server_set_icon (volume, str);
> }
> 
> static void
> setup_volume_view (GtkTreeView *volume_view)
> {
> 	GtkTreeViewColumn *col;
> 	GtkCellRenderer *renderer;
> 
> 	renderer = gtk_cell_renderer_text_new ();
> 	g_signal_connect (renderer, "edited", G_CALLBACK (name_renderer_edited), volume_view);
> 	col = gtk_tree_view_column_new_with_attributes ("Display Name", renderer, NULL);
> 	gtk_tree_view_append_column (volume_view, col);
> 	gtk_tree_view_column_set_cell_data_func (col, renderer, volume_name_data_func, NULL, NULL);
> 
> 	renderer = gtk_cell_renderer_text_new ();
> 	g_signal_connect (renderer, "edited", G_CALLBACK (uri_renderer_edited), volume_view);
> 	col = gtk_tree_view_column_new_with_attributes ("URI", renderer, NULL);
> 	gtk_tree_view_append_column (volume_view, col);
> 	gtk_tree_view_column_set_cell_data_func (col, renderer, volume_uri_data_func, NULL, NULL);
> 
> 	renderer = gtk_cell_renderer_text_new ();
> 	g_signal_connect (renderer, "edited", G_CALLBACK (icon_renderer_edited), volume_view);
> 	col = gtk_tree_view_column_new_with_attributes ("Icon", renderer, NULL);
> 	gtk_tree_view_append_column (volume_view, col);
> 	gtk_tree_view_column_set_cell_data_func (col, renderer, volume_icon_data_func, NULL, NULL);
> }
> 
> typedef struct {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter *ret;
> } ForeachFoo;
> 
> static gboolean
> foreach_compare_volume (GtkTreeModel *model,
> 			GtkTreePath  *path,
> 			GtkTreeIter  *iter,
> 			gpointer      data)
> {
> 	GnomeVFSVolume *volume;
> 	ForeachFoo *foreach = (ForeachFoo *) data;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	if (foreach->volume == volume) {
> 		foreach->ret = gtk_tree_iter_copy (iter);
> 		return TRUE;
> 	} else {
> 		return FALSE;
> 	}
> }
> 
> static GtkTreeIter *
> lookup_volume_iter (GtkTreeModel *model,
> 		    GnomeVFSVolume *volume)
> {
> 	ForeachFoo foreach = { volume, NULL };
> 
> 	gtk_tree_model_foreach (model, foreach_compare_volume, &foreach);
> 	g_assert (foreach.ret != NULL);
> 
> 	return foreach.ret;
> }
> 
> static void
> volume_mounted (GnomeVFSDrive  *drive,
> 		GnomeVFSVolume *volume,
> 		GtkTreeView    *volume_view)
> {
> 	GtkTreeIter iter;
> 	char *name;
> 
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_message ("%s mounted", name);
> 	g_free (name);
> 
> 	gtk_list_store_append (GTK_LIST_STORE (gtk_tree_view_get_model (volume_view)), &iter);
> 	gtk_list_store_set (GTK_LIST_STORE (gtk_tree_view_get_model (volume_view)), &iter,
> 			    0, gnome_vfs_volume_ref (volume), -1);
> }
> 
> static void
> volume_changed (GnomeVFSVolumeMonitor *monitor,
> 		GnomeVFSVolume        *volume,
> 		GtkTreeView           *volume_view)
> {
> 	GtkTreeIter *iter;
> 	GtkTreePath *path;
> 	char *name;
> 
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_warning ("%s changed", name);
> 	g_free (name);
> 
> 	iter = lookup_volume_iter (gtk_tree_view_get_model (volume_view), volume);
> 	path = gtk_tree_model_get_path (gtk_tree_view_get_model (volume_view), iter);
> 	gtk_tree_model_row_changed (gtk_tree_view_get_model (volume_view), path, iter);
> 	gtk_tree_path_free (path);
> 	gtk_tree_iter_free (iter);
> }
> 
> static void
> volume_unmounted (GnomeVFSVolumeMonitor *monitor,
> 		  GnomeVFSVolume        *volume,
> 		  GtkTreeView           *volume_view)
> {
> 	GtkTreeIter *iter;
> 	GtkTreePath *path;
> 	char *name;
> 	gboolean success;
> 
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_message ("%s unmounted", name);
> 	g_free (name);
> 
> 	iter = lookup_volume_iter (gtk_tree_view_get_model (volume_view), volume);
> 	path = gtk_tree_model_get_path (gtk_tree_view_get_model (volume_view), iter);
> 	success = gtk_list_store_remove (GTK_LIST_STORE (gtk_tree_view_get_model (volume_view)), iter);
> 	gtk_tree_iter_free (iter);
> }
> 
> int main (int argc, char **argv)
> {
> 	GtkWidget *window, *volume_view;
> 
> 	gnome_vfs_init ();
> 	gtk_init (&argc, &argv);
> 
> 	monitor = gnome_vfs_get_volume_monitor ();
> 
> 	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
> 	g_signal_connect (window, "destroy",
> 			  G_CALLBACK (gtk_main_quit), NULL);
> 
> 	volume_view = gtk_tree_view_new_with_model (make_volume_tree_model ());
> 	g_object_unref (G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (volume_view))));
> 	setup_volume_view (GTK_TREE_VIEW (volume_view));
> 	gtk_widget_show (GTK_WIDGET (volume_view));
> 	gtk_container_add (GTK_CONTAINER (window), volume_view);
> 
> 	g_signal_connect (monitor, "volume-mounted",
> 			  G_CALLBACK (volume_mounted),
> 			  volume_view);
> 
> 	g_signal_connect (monitor, "volume-changed",
> 			  G_CALLBACK (volume_changed),
> 			  volume_view);
> 
> 	g_signal_connect (monitor, "volume-unmounted",
> 			  G_CALLBACK (volume_unmounted),
> 			  volume_view);
> 
> 	gtk_window_present (GTK_WINDOW (window));
> 	gtk_main ();
> 
> 	gnome_vfs_shutdown ();
> }
> #include <gtk/gtk.h>
> #include <libgnomevfs/gnome-vfs.h>
> 
> static GnomeVFSVolumeMonitor *monitor;
> 
> static int
> volume_iter_compare_func (GtkTreeModel *model,
> 			  GtkTreeIter  *a,
> 			  GtkTreeIter  *b,
> 			  gpointer      data)
> {
> 	GnomeVFSVolume *a_vol, *b_vol;
> 
> 	gtk_tree_model_get (model, a, 0, &a_vol, -1);
> 	gtk_tree_model_get (model, b, 0, &b_vol, -1);
> 
> 	return gnome_vfs_volume_compare (a_vol, b_vol);
> }
> 
> static GtkTreeModel *
> make_volume_tree_model (void)
> {
> 	GList *volumes, *l;
> 	GtkListStore *store;
> 
> 	store = gtk_list_store_new (1, GNOME_VFS_TYPE_VOLUME);
> 
> 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), 0,
> 					 volume_iter_compare_func, NULL, NULL);
> 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0, GTK_SORT_ASCENDING);
> 
> 	volumes = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
> 	for (l = volumes; l != NULL; l = l->next) {
> 		GtkTreeIter iter;
> 
> 		gtk_list_store_append (store, &iter);
> 		gtk_list_store_set (store, &iter, 0, l->data, -1);
> 	}
> 	g_list_free (volumes);
> 
> 	return GTK_TREE_MODEL (store);
> }
> 
> static void
> volume_name_data_func (GtkTreeViewColumn *col,
> 		       GtkCellRenderer   *renderer,
> 		       GtkTreeModel      *model,
> 		       GtkTreeIter       *iter,
> 		       gpointer           data)
> {
> 	GnomeVFSVolume *volume;
> 	char *name;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_object_set (G_OBJECT (renderer),
> 		      "text", name,
> 		      "editable", gnome_vfs_volume_get_volume_type (volume) == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER,
> 		      NULL);
> 	g_free (name);
> }
> 
> static void
> volume_uri_data_func (GtkTreeViewColumn *col,
> 		      GtkCellRenderer   *renderer,
> 		      GtkTreeModel      *model,
> 		      GtkTreeIter       *iter,
> 		      gpointer           data)
> {
> 	GnomeVFSVolume *volume;
> 	char *uri;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	uri = gnome_vfs_volume_get_activation_uri (volume);
> 	g_object_set (G_OBJECT (renderer),
> 		      "text", uri,
> 		      "editable", gnome_vfs_volume_get_volume_type (volume) == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER,
> 		      NULL);
> 	g_free (uri);
> }
> 
> static void
> volume_icon_data_func (GtkTreeViewColumn *col,
> 		       GtkCellRenderer   *renderer,
> 		       GtkTreeModel      *model,
> 		       GtkTreeIter       *iter,
> 		       gpointer           data)
> {
> 	GnomeVFSVolume *volume;
> 	char *icon;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	icon = gnome_vfs_volume_get_icon (volume);
> 	g_object_set (G_OBJECT (renderer),
> 		      "text", icon,
> 		      "editable", gnome_vfs_volume_get_volume_type (volume) == GNOME_VFS_VOLUME_TYPE_CONNECTED_SERVER,
> 		      NULL);
> 	g_free (icon);
> }
> 
> static void
> name_renderer_edited (GtkCellRendererText *renderer,
> 		      char                *path,
> 		      char                *str,
> 		      GtkTreeView         *volume_view)
> {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter iter;
> 	gboolean success;
> 
> 	success = gtk_tree_model_get_iter_from_string (gtk_tree_view_get_model (volume_view), &iter, path);
> 	g_assert (success);
> 
> 	gtk_tree_model_get (gtk_tree_view_get_model (volume_view), &iter, 0, &volume, -1);
> 	gnome_vfs_volume_connected_server_set_display_name (volume, str);
> }
> 
> static void
> uri_renderer_edited (GtkCellRendererText *renderer,
> 		     char                *path,
> 		     char                *str,
> 		     GtkTreeView         *volume_view)
> {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter iter;
> 	gboolean success;
> 
> 	success = gtk_tree_model_get_iter_from_string (gtk_tree_view_get_model (volume_view), &iter, path);
> 	g_assert (success);
> 
> 	gtk_tree_model_get (gtk_tree_view_get_model (volume_view), &iter, 0, &volume, -1);
> 	gnome_vfs_volume_connected_server_set_activation_uri (volume, str);
> }
> 
> static void
> icon_renderer_edited (GtkCellRendererText *renderer,
> 		      char                *path,
> 		      char                *str,
> 		      GtkTreeView         *volume_view)
> {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter iter;
> 	gboolean success;
> 
> 	success = gtk_tree_model_get_iter_from_string (gtk_tree_view_get_model (volume_view), &iter, path);
> 	g_assert (success);
> 
> 	gtk_tree_model_get (gtk_tree_view_get_model (volume_view), &iter, 0, &volume, -1);
> 	gnome_vfs_volume_connected_server_set_icon (volume, str);
> }
> 
> static void
> setup_volume_view (GtkTreeView *volume_view)
> {
> 	GtkTreeViewColumn *col;
> 	GtkCellRenderer *renderer;
> 
> 	renderer = gtk_cell_renderer_text_new ();
> 	g_signal_connect (renderer, "edited", G_CALLBACK (name_renderer_edited), volume_view);
> 	col = gtk_tree_view_column_new_with_attributes ("Display Name", renderer, NULL);
> 	gtk_tree_view_append_column (volume_view, col);
> 	gtk_tree_view_column_set_cell_data_func (col, renderer, volume_name_data_func, NULL, NULL);
> 
> 	renderer = gtk_cell_renderer_text_new ();
> 	g_signal_connect (renderer, "edited", G_CALLBACK (uri_renderer_edited), volume_view);
> 	col = gtk_tree_view_column_new_with_attributes ("URI", renderer, NULL);
> 	gtk_tree_view_append_column (volume_view, col);
> 	gtk_tree_view_column_set_cell_data_func (col, renderer, volume_uri_data_func, NULL, NULL);
> 
> 	renderer = gtk_cell_renderer_text_new ();
> 	g_signal_connect (renderer, "edited", G_CALLBACK (icon_renderer_edited), volume_view);
> 	col = gtk_tree_view_column_new_with_attributes ("Icon", renderer, NULL);
> 	gtk_tree_view_append_column (volume_view, col);
> 	gtk_tree_view_column_set_cell_data_func (col, renderer, volume_icon_data_func, NULL, NULL);
> }
> 
> typedef struct {
> 	GnomeVFSVolume *volume;
> 	GtkTreeIter *ret;
> } ForeachFoo;
> 
> static gboolean
> foreach_compare_volume (GtkTreeModel *model,
> 			GtkTreePath  *path,
> 			GtkTreeIter  *iter,
> 			gpointer      data)
> {
> 	GnomeVFSVolume *volume;
> 	ForeachFoo *foreach = (ForeachFoo *) data;
> 
> 	gtk_tree_model_get (model, iter, 0, &volume, -1);
> 	if (foreach->volume == volume) {
> 		foreach->ret = gtk_tree_iter_copy (iter);
> 		return TRUE;
> 	} else {
> 		return FALSE;
> 	}
> }
> 
> static GtkTreeIter *
> lookup_volume_iter (GtkTreeModel *model,
> 		    GnomeVFSVolume *volume)
> {
> 	ForeachFoo foreach = { volume, NULL };
> 
> 	gtk_tree_model_foreach (model, foreach_compare_volume, &foreach);
> 	g_assert (foreach.ret != NULL);
> 
> 	return foreach.ret;
> }
> 
> static void
> volume_mounted (GnomeVFSDrive  *drive,
> 		GnomeVFSVolume *volume,
> 		GtkTreeView    *volume_view)
> {
> 	GtkTreeIter iter;
> 	char *name;
> 
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_message ("%s mounted", name);
> 	g_free (name);
> 
> 	gtk_list_store_append (GTK_LIST_STORE (gtk_tree_view_get_model (volume_view)), &iter);
> 	gtk_list_store_set (GTK_LIST_STORE (gtk_tree_view_get_model (volume_view)), &iter,
> 			    0, gnome_vfs_volume_ref (volume), -1);
> }
> 
> static void
> volume_changed (GnomeVFSVolumeMonitor *monitor,
> 		GnomeVFSVolume        *volume,
> 		GtkTreeView           *volume_view)
> {
> 	GtkTreeIter *iter;
> 	GtkTreePath *path;
> 	char *name;
> 
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_warning ("%s changed", name);
> 	g_free (name);
> 
> 	iter = lookup_volume_iter (gtk_tree_view_get_model (volume_view), volume);
> 	path = gtk_tree_model_get_path (gtk_tree_view_get_model (volume_view), iter);
> 	gtk_tree_model_row_changed (gtk_tree_view_get_model (volume_view), path, iter);
> 	gtk_tree_path_free (path);
> 	gtk_tree_iter_free (iter);
> }
> 
> static void
> volume_unmounted (GnomeVFSVolumeMonitor *monitor,
> 		  GnomeVFSVolume        *volume,
> 		  GtkTreeView           *volume_view)
> {
> 	GtkTreeIter *iter;
> 	GtkTreePath *path;
> 	char *name;
> 	gboolean success;
> 
> 	name = gnome_vfs_volume_get_display_name (volume);
> 	g_message ("%s unmounted", name);
> 	g_free (name);
> 
> 	iter = lookup_volume_iter (gtk_tree_view_get_model (volume_view), volume);
> 	path = gtk_tree_model_get_path (gtk_tree_view_get_model (volume_view), iter);
> 	success = gtk_list_store_remove (GTK_LIST_STORE (gtk_tree_view_get_model (volume_view)), iter);
> 	gtk_tree_iter_free (iter);
> }
> 
> int main (int argc, char **argv)
> {
> 	GtkWidget *window, *volume_view;
> 
> 	gnome_vfs_init ();
> 	gtk_init (&argc, &argv);
> 
> 	monitor = gnome_vfs_get_volume_monitor ();
> 
> 	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
> 	g_signal_connect (window, "destroy",
> 			  G_CALLBACK (gtk_main_quit), NULL);
> 
> 	volume_view = gtk_tree_view_new_with_model (make_volume_tree_model ());
> 	g_object_unref (G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (volume_view))));
> 	setup_volume_view (GTK_TREE_VIEW (volume_view));
> 	gtk_widget_show (GTK_WIDGET (volume_view));
> 	gtk_container_add (GTK_CONTAINER (window), volume_view);
> 
> 	g_signal_connect (monitor, "volume-mounted",
> 			  G_CALLBACK (volume_mounted),
> 			  volume_view);
> 
> 	g_signal_connect (monitor, "volume-changed",
> 			  G_CALLBACK (volume_changed),
> 			  volume_view);
> 
> 	g_signal_connect (monitor, "volume-unmounted",
> 			  G_CALLBACK (volume_unmounted),
> 			  volume_view);
> 
> 	gtk_window_present (GTK_WINDOW (window));
> 	gtk_main ();
> 
> 	gnome_vfs_shutdown ();
> }
