gio changes for GVolume and GDrive



Hi,

I've started working on writing a hal implementation for GVolumeMonitor
and have some suggestions making the volume monitor API better. First of
all it appears that the current GDrive and GVolume abstraction is more
or less a 1:1 copy of what was in GnomeVFS. 

There's a couple of problems with this approach. The main problem is
that GDrive doesn't really represent a drive. It represents a mountable
volume; typically such as partitions on a hard drive or entries in the
classic /etc/fstab file. This breaks down if you have media with
multiple partitions or mixed optical discs.

So part of this patch renames GDrive to GMountableVolume. Then we
reintroduce GDrive as a new interface that more precisely represents
what most people associate with the word ''drive'': a collection of
mountable volumes and the notion of media.

There's also API in the new GDrive so it's easy to make the UI cope with
edge cases like floppy drives and when the media isn't polled - the
latter is terribly popular these days and it does make sense. In fact I
plan to write a patch for gnome-power-manager so it can poke HAL to
disable polling while on battery.. part of the goal for the hal impl of
GVolumeMonitor is to cope nicely when polling of drives is disabled. 

(For example, if you poll an empty drive you don't need to show it in
the sidebar. However, if you don't poll it you need to show it in the
sidebar so the user can right click it and choose "Rescan". And if you
turn polling on and off, the drive show disappear resp. appear in the
sidebar. The Nautilus patch mentioned below implements both of these
things.)

So, the also patch includes a port of GUnixVolumeMonitor to this new
API. I've also implemented mount and unmount. One thing that remains to
be done is to make GUnixVolumeMonitor create GDrive object so eject will
start working again. That's on my TODO list (got it working in the hal
backend already) but haven't done it yet.. will follow up with that
soon.

There's also a some new API in gunixmounts.c that I needed for both
backends. Thoughts? Also, I'm wondering, with these additions, if we can
do away with GUnixMountType altogether; it's pretty much an eyesore.

I've also included patches for Nautilus and gvfs to use the new API;
they're pretty straightforward although the Nautilus one is rather
large. Sorry about that.

I plan to submit the hal backend sometime tomorrow; am sending these
patches early as they're breaking API so I wanted to get them in early.

Thanks for considering.

      David

Index: gunixmounts.c
===================================================================
--- gunixmounts.c	(revision 6093)
+++ gunixmounts.c	(working copy)
@@ -1,3 +1,5 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
 /* GIO - GLib Input, Output and Streaming Library
  * 
  * Copyright (C) 2006-2007 Red Hat, Inc.
@@ -46,9 +48,12 @@
 #include "gunixmounts.h"
 #include "gfile.h"
 #include "gfilemonitor.h"
+#include "glibintl.h"
 
 #include "gioalias.h"
 
+static const char *_resolve_dev_root (void);
+
 /**
  * SECTION:gunixmounts
  * @short_description: Unix Mounts
@@ -151,6 +156,63 @@
   return FALSE;
 }
 
+/**
+ * g_unix_is_mount_path_system_internal:
+ * @mount_path: a mount path, e.g. <literal>/media/disk</literal> or <literal>/usr</literal>
+ *
+ * Determines if @mount_path is considered an implementation of the
+ * OS. This is primarily used for hiding mountable and mounted volumes
+ * that only are used in the OS and has little to no relevance to the
+ * casual user.
+ *
+ * Returns; %TRUE if @mount_path is considered an implementation detail of the OS.
+ **/
+gboolean
+g_unix_is_mount_path_system_internal (const char *mount_path)
+{
+  const char *ignore_mountpoints[] = {
+    /* Includes all FHS 2.3 toplevel dirs and other specilized
+     * directories that we want to hide from the user.
+     */
+    "/",              /* we already have "Filesystem root" in Nautilus */ 
+    "/bin",
+    "/boot",
+    "/dev",
+    "/etc",
+    "/home",
+    "/lib",
+    "/lib64",
+    "/media",
+    "/mnt",
+    "/opt",
+    "/root",
+    "/sbin",
+    "/srv",
+    "/tmp",
+    "/usr",
+    "/var",
+    "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
+    "/var/tmp",       /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
+    "/proc",
+    "/sbin",
+    "/net",
+    NULL
+  };
+
+  if (is_in (mount_path, ignore_mountpoints))
+    return TRUE;
+  
+  if (g_str_has_prefix (mount_path, "/dev") ||
+      g_str_has_prefix (mount_path, "/proc") ||
+      g_str_has_prefix (mount_path, "/sys"))
+    return TRUE;
+
+  if (strstr (mount_path, "/.gvfs") != NULL)
+    return TRUE;
+
+  return FALSE;
+}
+
 static gboolean
 guess_system_internal (const char *mountpoint,
 		       const char *fs,
@@ -183,29 +245,6 @@
     "/dev/vn",
     NULL
   };
-  const char *ignore_mountpoints[] = {
-    /* Includes all FHS 2.3 toplevel dirs */
-    "/bin",
-    "/boot",
-    "/dev",
-    "/etc",
-    "/home",
-    "/lib",
-    "/lib64",
-    "/media",
-    "/mnt",
-    "/opt",
-    "/root",
-    "/sbin",
-    "/srv",
-    "/tmp",
-    "/usr",
-    "/var",
-    "/proc",
-    "/sbin",
-    "/net",
-    NULL
-  };
   
   if (is_in (fs, ignore_fs))
     return TRUE;
@@ -213,17 +252,9 @@
   if (is_in (device, ignore_devices))
     return TRUE;
 
-  if (is_in (mountpoint, ignore_mountpoints))
+  if (g_unix_is_mount_path_system_internal (mountpoint))
     return TRUE;
   
-  if (g_str_has_prefix (mountpoint, "/dev") ||
-      g_str_has_prefix (mountpoint, "/proc") ||
-      g_str_has_prefix (mountpoint, "/sys"))
-    return TRUE;
-
-  if (strstr (mountpoint, "/.gvfs") != NULL)
-    return TRUE;
-  
   return FALSE;
 }
 
@@ -291,11 +322,14 @@
       if (mntent->mnt_fsname != NULL &&
 	  mntent->mnt_fsname[0] == '/' &&
 	  g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
-	continue;
+        continue;
       
       mount_entry = g_new0 (GUnixMount, 1);
       mount_entry->mount_path = g_strdup (mntent->mnt_dir);
-      mount_entry->device_path = g_strdup (mntent->mnt_fsname);
+      if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
+        mount_entry->device_path = g_strdup (_resolve_dev_root ());
+      else
+        mount_entry->device_path = g_strdup (mntent->mnt_fsname);
       mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
       
 #if defined (HAVE_HASMNTOPT)
@@ -554,10 +588,13 @@
       if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
 	  (strcmp (mntent->mnt_dir, "swap") == 0))
 	continue;
-      
+
       mount_entry = g_new0 (GUnixMountPoint, 1);
       mount_entry->mount_path = g_strdup (mntent->mnt_dir);
-      mount_entry->device_path = g_strdup (mntent->mnt_fsname);
+      if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
+        mount_entry->device_path = g_strdup (_resolve_dev_root ());
+      else
+        mount_entry->device_path = g_strdup (mntent->mnt_fsname);
       mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
       
 #ifdef HAVE_HASMNTOPT
@@ -1594,5 +1631,388 @@
 			   mount_point->filesystem_type);
 }
 
+static char *
+type_to_icon (GUnixMountType type, gboolean is_mount_point)
+{
+  const char *icon_name = NULL;
+  
+  switch (type)
+    {
+    case G_UNIX_MOUNT_TYPE_HD:
+      if (is_mount_point)
+        icon_name = "drive-removable-media";
+      else
+        icon_name = "drive-harddisk";
+      break;
+    case G_UNIX_MOUNT_TYPE_FLOPPY:
+    case G_UNIX_MOUNT_TYPE_ZIP:
+    case G_UNIX_MOUNT_TYPE_JAZ:
+      if (is_mount_point)
+        icon_name = "drive-removable-media";
+      else
+        icon_name = "media-floppy";
+      break;
+    case G_UNIX_MOUNT_TYPE_CDROM:
+      if (is_mount_point)
+        icon_name = "drive-optical";
+      else
+        icon_name = "media-optical";
+      break;
+    case G_UNIX_MOUNT_TYPE_NFS:
+      /* TODO: Would like a better icon here... */
+      if (is_mount_point)
+        icon_name = "drive-removable-media";
+      else
+        icon_name = "drive-harddisk";
+      break;
+    case G_UNIX_MOUNT_TYPE_MEMSTICK:
+      if (is_mount_point)
+        icon_name = "drive-removable-media";
+      else
+        icon_name = "media-flash";
+      break;
+    case G_UNIX_MOUNT_TYPE_CAMERA:
+      if (is_mount_point)
+        icon_name = "drive-removable-media";
+      else
+        icon_name = "camera-photo";
+      break;
+    case G_UNIX_MOUNT_TYPE_IPOD:
+      if (is_mount_point)
+        icon_name = "drive-removable-media";
+      else
+        icon_name = "multimedia-player";
+      break;
+    case G_UNIX_MOUNT_TYPE_UNKNOWN:
+    default:
+      if (is_mount_point)
+        icon_name = "drive-removable-media";
+      else
+        icon_name = "drive-harddisk";
+      break;
+    }
+  return g_strdup (icon_name);
+}
+
+char *
+g_unix_mount_guess_name (GUnixMount *mount_entry)
+{
+  char *name;
+
+  if (strcmp (mount_entry->mount_path, "/") == 0)
+    name = g_strdup (_("Filesystem root"));
+  else
+    name = g_filename_display_basename (mount_entry->mount_path);
+
+  return name;
+}
+
+char *
+g_unix_mount_guess_icon_name (GUnixMount *mount_entry)
+{
+  return type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE);
+}
+
+char *
+g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
+{
+  char *name;
+
+  if (strcmp (mount_point->mount_path, "/") == 0)
+    name = g_strdup (_("Filesystem root"));
+  else
+    name = g_filename_display_basename (mount_point->mount_path);
+
+  return name;
+}
+
+char *
+g_unix_mount_point_guess_icon_name (GUnixMountPoint *mount_point)
+{
+  return type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE);
+}
+
+
+/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
+static void
+_canonicalize_filename (gchar *filename)
+{
+  gchar *p, *q;
+  gboolean last_was_slash = FALSE;
+  
+  p = filename;
+  q = filename;
+  
+  while (*p)
+    {
+      if (*p == G_DIR_SEPARATOR)
+        {
+          if (!last_was_slash)
+            *q++ = G_DIR_SEPARATOR;
+          
+          last_was_slash = TRUE;
+        }
+      else
+        {
+          if (last_was_slash && *p == '.')
+            {
+              if (*(p + 1) == G_DIR_SEPARATOR ||
+                  *(p + 1) == '\0')
+                {
+                  if (*(p + 1) == '\0')
+                    break;
+                  
+                  p += 1;
+                }
+              else if (*(p + 1) == '.' &&
+                       (*(p + 2) == G_DIR_SEPARATOR ||
+                        *(p + 2) == '\0'))
+                {
+                  if (q > filename + 1)
+                    {
+                      q--;
+                      while (q > filename + 1 &&
+                             *(q - 1) != G_DIR_SEPARATOR)
+                        q--;
+                    }
+                  
+                  if (*(p + 2) == '\0')
+                    break;
+                  
+                  p += 2;
+                }
+              else
+                {
+                  *q++ = *p;
+                  last_was_slash = FALSE;
+                }
+            }
+          else
+            {
+              *q++ = *p;
+              last_was_slash = FALSE;
+            }
+        }
+      
+      p++;
+    }
+  
+  if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
+    q--;
+  
+  *q = '\0';
+}
+
+static char *
+_resolve_symlink (const char *file)
+{
+  GError *error;
+  char *dir;
+  char *link;
+  char *f;
+  char *f1;
+  
+  f = g_strdup (file);
+  
+  while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) {
+    link = g_file_read_link (f, &error);
+    if (link == NULL) {
+      g_error_free (error);
+      g_free (f);
+      f = NULL;
+      goto out;
+    }
+    
+    dir = g_path_get_dirname (f);
+    f1 = g_strdup_printf ("%s/%s", dir, link);
+    g_free (dir);
+    g_free (link);
+    g_free (f);
+    f = f1;
+  }
+  
+ out:
+  if (f != NULL)
+    _canonicalize_filename (f);
+  return f;
+}
+
+static const char *
+_resolve_dev_root (void)
+{
+  static gboolean have_real_dev_root = FALSE;
+  static char real_dev_root[256];
+  struct stat statbuf;
+  
+  /* see if it's cached already */
+  if (have_real_dev_root)
+    goto found;
+  
+  /* otherwise we're going to find it right away.. */
+  have_real_dev_root = TRUE;
+  
+  if (stat ("/dev/root", &statbuf) == 0) {
+    if (! S_ISLNK (statbuf.st_mode)) {
+      dev_t root_dev = statbuf.st_dev;
+      FILE *f;
+      char buf[1024];
+      
+      /* see if device with similar major:minor as /dev/root is mention
+       * in /etc/mtab (it usually is) 
+       */
+      f = fopen ("/etc/mtab", "r");
+      if (f != NULL) {
+        struct mntent ent;
+        
+        while (getmntent_r (f, &ent, buf, sizeof (buf)) != NULL) {
+          
+          if (stat (ent.mnt_fsname, &statbuf) == 0 &&
+              statbuf.st_dev == root_dev) {
+            strncpy (real_dev_root, ent.mnt_fsname, sizeof (real_dev_root) - 1);
+            real_dev_root[sizeof (real_dev_root) - 1] = '\0';
+            fclose (f);
+            goto found;
+          }
+        }
+        fclose (f);
+      }                                        
+      
+      /* no, that didn't work.. next we could scan /dev ... but I digress.. */
+      
+    } else {
+      char *resolved;
+      resolved = _resolve_symlink ("/dev/root");
+      if (resolved != NULL) {
+        strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
+        real_dev_root[sizeof (real_dev_root) - 1] = '\0';
+        g_free (resolved);
+        goto found;
+      }
+    }
+  }
+  
+  /* bah sucks.. */
+  strcpy (real_dev_root, "/dev/root");
+  
+ found:
+  return real_dev_root;
+}
+
+static char *
+_encode_string (const char *str)
+{
+  int n, m;
+  char *res;
+  
+  /* worst case is that we need to encode everything */
+  res = g_new0 (char, strlen (str) * 4 + 1);
+  
+  for (n = 0, m = 0; str[n] != '\0'; n += 1) {
+    int c = str[n];
+    
+    if ((c >= '0' && c <= '9') ||
+        (c >= 'A' && c <= 'Z') ||
+        (c >= 'a' && c <= 'z') ||
+        strchr("#+-.:= _", c)) {
+      res[m++] = c;
+    } else {
+      int hn = c >> 4;
+      int ln = c & 0x0f;
+      res[m++] = '\\';
+      res[m++] = 'x';
+      res[m++] = (hn < 10) ? (hn + '0') : (hn - 10 + 'a');
+      res[m++] = (ln < 10) ? (ln + '0') : (ln - 10 + 'a');
+    }
+  }
+  res[m] = '\0';
+  res = g_realloc (res, strlen (res));
+  
+  return res;
+}
+
+/**
+ * g_unix_get_canonical_device_path:
+ * @device_path: device path
+ *
+ * A refernce to a device file (e.g. a file under the
+ * <literal>/dev</literal> tree) in UNIX-like operating systems can
+ * have several representations due to symlinks (such as
+ * <literal>/dev/disk/by-id/usb-Generic_STORAGE_DEVICE_000000009601-0:0-part1</literal>),
+ * aliasing (such as <literal>LABEL=fslabel</literal> or
+ * <literal>UUID=1234-5678</literal> constructs) and other mechanisms.
+ *
+ * Such representations of a device file are useful when adding
+ * entries to the file systems description file
+ * <literal>/etc/fstab</literal> since such a reference is in fact a
+ * persistent reference to a specific device and don't rely on
+ * specific transient kernel names such as
+ * <literal>/dev/sda1</literal>. As a consequence, one should expect
+ * device files of this form from functions such as
+ * g_unix_mount_point_get_device_path() that returns information read
+ * from the <literal>/etc/fstab</literal> file.
+ *
+ * This function returns the path to an existing device file given
+ * either a <literal>LABEL=abc</literal>, <literal>UUID=1234</literal>
+ * or a symlink. If the representation points to a non-existing device
+ * or cannot be resolved (this can easily happen; an example would be
+ * the entry "<literal>LABEL=Camera /mnt/camera defaults,users 0
+ * 0</literal>" in the <literal>/etc/fstab</literal> without the
+ * device actually connected) %NULL is returned.
+ * 
+ * Returns: the resolved device path or #NULL if @device_path isn't a
+ * device path or couldn't be resolved.
+ */
+char *
+g_unix_get_canonical_device_path (const char *device_path)
+{
+  char *encoded;
+  char *result;
+  char *attempt_resolve;
+  struct stat statbuf;
+
+  g_return_val_if_fail (device_path != NULL, NULL);
+
+  result = NULL;
+
+  if (strcmp (device_path, "/dev/root") == 0)
+    {
+      result = g_strdup (_resolve_dev_root ());
+    } 
+  else if (strncmp (device_path, "LABEL=", 6) == 0)
+    {
+      encoded = _encode_string (device_path + 6);
+      attempt_resolve = g_strdup_printf ("/dev/disk/by-label/%s", encoded);
+      result = _resolve_symlink (attempt_resolve);
+      g_free (attempt_resolve);
+      g_free (encoded);
+    } 
+  else if (strncmp (device_path, "UUID=", 5) == 0)
+    {
+      encoded = _encode_string (device_path + 5);
+      attempt_resolve = g_strdup_printf ("/dev/disk/by-uuid/%s", encoded);
+      result = _resolve_symlink (attempt_resolve);
+      g_free (attempt_resolve);
+      g_free (encoded);
+    } 
+  else if (strncmp (device_path, "/dev/", 5) == 0)
+    {
+      if (stat (device_path, &statbuf) == 0)
+        {
+          if (S_ISLNK (statbuf.st_mode))
+            {
+              attempt_resolve = g_strdup (device_path);
+            } 
+          else
+            {
+              result = g_strdup (device_path);
+            }
+        }
+    }
+
+  return result;
+}
+
+
+
 #define __G_UNIX_MOUNTS_C__
 #include "gioaliasdef.c"
Index: gunixmounts.h
===================================================================
--- gunixmounts.h	(revision 6093)
+++ gunixmounts.h	(working copy)
@@ -100,6 +100,8 @@
 gboolean       g_unix_mount_is_readonly             (GUnixMount         *mount_entry);
 gboolean       g_unix_mount_is_system_internal      (GUnixMount         *mount_entry);
 GUnixMountType g_unix_mount_guess_type              (GUnixMount         *mount_entry);
+char *         g_unix_mount_guess_name              (GUnixMount         *mount_entry);
+char *         g_unix_mount_guess_icon_name         (GUnixMount         *mount_entry);
 
 gint           g_unix_mount_point_compare           (GUnixMountPoint    *mount1,
 						     GUnixMountPoint    *mount2);
@@ -110,6 +112,8 @@
 gboolean       g_unix_mount_point_is_user_mountable (GUnixMountPoint    *mount_point);
 gboolean       g_unix_mount_point_is_loopback       (GUnixMountPoint    *mount_point);
 GUnixMountType g_unix_mount_point_guess_type        (GUnixMountPoint    *mount_point);
+char *         g_unix_mount_point_guess_name        (GUnixMountPoint    *mount_point);
+char *         g_unix_mount_point_guess_icon_name   (GUnixMountPoint    *mount_point);
 
 GList *        g_get_unix_mount_points              (guint64            *time_read);
 GList *        g_get_unix_mounts                    (guint64            *time_read);
@@ -121,6 +125,12 @@
 GType              g_unix_mount_monitor_get_type (void) G_GNUC_CONST;
 GUnixMountMonitor *g_unix_mount_monitor_new      (void);
 
+
+
+char *g_unix_get_canonical_device_path (const char *device_path);
+
+gboolean g_unix_is_mount_path_system_internal (const char *mount_path);
+
 G_END_DECLS
 
 #endif /* __G_UNIX_MOUNTS_H__ */
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 6093)
+++ ChangeLog	(working copy)
@@ -1,3 +1,64 @@
+2007-12-11  David Zeuthen  <davidz redhat com>
+
+	Rename GDrive to GMountableVolume and introduce a new interface
+	called GDrive that more adequately represents what a drive is. Also
+	provide some more utility in gunixmounts.
+
+	* Makefile.am:
+	* gdrive.c: (g_drive_has_mountable_volumes),
+	(g_drive_get_mountable_volumes),
+	(g_drive_is_media_check_automatic), (g_drive_is_media_removable),
+	(g_drive_has_media), (g_drive_can_poll_for_media), (g_drive_eject),
+	(g_drive_eject_finish), (g_drive_poll_for_media),
+	(g_drive_poll_for_media_finish):
+	* gdrive.h:
+	* gio.symbols:
+	* gunionvolumemonitor.c: (get_mounted_volumes),
+	(get_mountable_volumes), (get_connected_drives),
+	(g_union_volume_monitor_class_init),
+	(child_mountable_volume_added), (child_mountable_volume_removed),
+	(child_mountable_volume_changed), (child_volume_unmounted),
+	(child_volume_changed), (child_drive_changed),
+	(g_union_volume_monitor_add_monitor),
+	(g_union_volume_monitor_remove_monitor):
+	* gunixmounts.c: (g_unix_is_mount_path_system_internal),
+	(guess_system_internal), (_g_get_unix_mounts),
+	(_g_get_unix_mount_points), (type_to_icon),
+	(g_unix_mount_guess_name), (g_unix_mount_guess_icon_name),
+	(g_unix_mount_point_guess_name),
+	(g_unix_mount_point_guess_icon_name), (_canonicalize_filename),
+	(_resolve_symlink), (_resolve_dev_root), (_encode_string),
+	(g_unix_get_canonical_device_path):
+	* gunixmounts.h:
+	* gunixvolume.c: (g_unix_volume_finalize), (_g_unix_volume_new),
+	(_g_unix_volume_unmounted),
+	(_g_unix_volume_unset_mountable_volume), (g_unix_volume_get_root),
+	(_g_unix_volume_has_mount_path), (g_unix_volume_get_drive),
+	(g_unix_volume_get_mountable_volume), (g_unix_volume_can_unmount),
+	(unmount_cb), (unmount_read_error), (g_unix_volume_unmount),
+	(g_unix_volume_unmount_finish), (g_unix_volume_volume_iface_init):
+	* gunixvolume.h:
+	* gunixvolumemonitor.c: (g_unix_volume_monitor_finalize),
+	(get_mountable_volumes), (get_connected_drives),
+	(get_volume_for_mount_path), (g_unix_volume_monitor_class_init),
+	(mountpoints_changed), (mounts_changed),
+	(g_unix_volume_monitor_init),
+	(_g_unix_volume_monitor_lookup_mountable_volume_for_mount_path),
+	(find_volume_by_mountpath), (update_mountable_volumes),
+	(update_volumes):
+	* gunixvolumemonitor.h:
+	* gvolume.c: (g_volume_get_mountable_volume), (g_volume_get_drive),
+	(g_volume_can_unmount):
+	* gvolume.h:
+	* gvolumemonitor.c: (g_volume_monitor_class_init),
+	(g_volume_monitor_get_connected_drives),
+	(g_volume_monitor_get_mountable_volumes),
+	(g_volume_monitor_get_mounted_volumes):
+	* gvolumemonitor.h:
+
+	* gmountablevolume.[ch] : New files
+	* gunixmountablevolume.[ch] : New files
+
 2007-12-10  Matthias Clasen  <mclasen redhat com>
 
 	* gmountoperation.h (GPasswordFlags): Close the gap
Index: gdrive.c
===================================================================
--- gdrive.c	(revision 6093)
+++ gdrive.c	(working copy)
@@ -145,15 +145,15 @@
 }
 
 /**
- * g_drive_has_volumes:
+ * g_drive_has_mountable_volumes:
  * @drive: a #GDrive.
  * 
- * Checks if a drive has any volumes.
+ * Check if @drive has any mountable volumes.
  * 
- * Returns: %TRUE if @drive contains volumes, %FALSE otherwise.
+ * Returns: %TRUE if the @drive contains volumes, %FALSE otherwise.
  **/
 gboolean
-g_drive_has_volumes (GDrive *drive)
+g_drive_has_mountable_volumes (GDrive *drive)
 {
   GDriveIface *iface;
 
@@ -161,20 +161,19 @@
 
   iface = G_DRIVE_GET_IFACE (drive);
 
-  return (* iface->has_volumes) (drive);
+  return (* iface->has_mountable_volumes) (drive);
 }
 
 /**
- * g_drive_get_volumes:
+ * g_drive_get_mountable_volumes:
  * @drive: a #GDrive.
  * 
- * Gets a list of volumes for a drive.
+ * Get a list of mountable volumes for @drive.
  * 
- * Returns: #GList containing any #GVolume<!---->s on the given @drive.
- * <!-- NOTE: Fact-check this. -->
+ * Returns: #GList containing any #GMountableVolume<!---->s on the given @drive.
  **/
 GList *
-g_drive_get_volumes (GDrive *drive)
+g_drive_get_mountable_volumes (GDrive *drive)
 {
   GDriveIface *iface;
 
@@ -182,19 +181,19 @@
 
   iface = G_DRIVE_GET_IFACE (drive);
 
-  return (* iface->get_volumes) (drive);
+  return (* iface->get_mountable_volumes) (drive);
 }
 
 /**
- * g_drive_is_automounted:
+ * g_drive_is_media_check_automatic:
  * @drive: a #GDrive.
  * 
- * Checks if a drive was automatically mounted, e.g. by HAL.
+ * Checks if @drive is capabable of automatically detecting media changes.
  * 
- * Returns: %TRUE if the drive was automounted. %FALSE otherwise.
+ * Returns: %TRUE if the @drive is capabable of automatically detecting media changes, %FALSE otherwise.
  **/
 gboolean
-g_drive_is_automounted (GDrive *drive)
+g_drive_is_media_check_automatic (GDrive *drive)
 {
   GDriveIface *iface;
 
@@ -202,19 +201,19 @@
 
   iface = G_DRIVE_GET_IFACE (drive);
 
-  return (* iface->is_automounted) (drive);
+  return (* iface->is_media_check_automatic) (drive);
 }
 
 /**
- * g_drive_can_mount:
+ * g_drive_is_media_removable:
  * @drive: a #GDrive.
  * 
- * Checks if a drive can be mounted.
+ * Checks if the @drive supports removable media.
  * 
- * Returns: %TRUE if the @drive can be mounted. %FALSE otherwise.
+ * Returns: %TRUE if @drive supports removable media, %FALSE otherwise.
  **/
 gboolean
-g_drive_can_mount (GDrive *drive)
+g_drive_is_media_removable (GDrive *drive)
 {
   GDriveIface *iface;
 
@@ -222,10 +221,29 @@
 
   iface = G_DRIVE_GET_IFACE (drive);
 
-  if (iface->can_mount == NULL)
-    return FALSE;
+  return (* iface->is_media_removable) (drive);
+}
 
-  return (* iface->can_mount) (drive);
+/**
+ * g_drive_has_media:
+ * @drive: a #GDrive.
+ * 
+ * Checks if the @drive has media. Note that the OS may not be polling
+ * the drive for media changes; see g_drive_is_media_check_automatic()
+ * for more details.
+ * 
+ * Returns: %TRUE if @drive has media, %FALSE otherwise.
+ **/
+gboolean
+g_drive_has_media (GDrive *drive)
+{
+  GDriveIface *iface;
+
+  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
+
+  iface = G_DRIVE_GET_IFACE (drive);
+
+  return (* iface->has_media) (drive);
 }
 
 /**
@@ -252,18 +270,40 @@
 }
 
 /**
- * g_drive_mount:
+ * g_drive_can_poll_for_media:
  * @drive: a #GDrive.
- * @mount_operation: a #GMountOperation.
+ * 
+ * Checks if a drive can be polled for media changes.
+ * 
+ * Returns: %TRUE if the @drive can be polled for media changes. %FALSE otherwise.
+ **/
+gboolean
+g_drive_can_poll_for_media (GDrive *drive)
+{
+  GDriveIface *iface;
+
+  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
+
+  iface = G_DRIVE_GET_IFACE (drive);
+
+  if (iface->poll_for_media == NULL)
+    return FALSE;
+
+  return (* iface->can_poll_for_media) (drive);
+}
+
+/**
+ * g_drive_eject:
+ * @drive: a #GDrive.
  * @cancellable: optional #GCancellable object, %NULL to ignore.
  * @callback: a #GAsyncReadyCallback.
  * @user_data: a #gpointer.
  * 
- * Mounts a drive.
+ * Ejects a drive.
+ * 
  **/
 void
-g_drive_mount (GDrive              *drive,
-	       GMountOperation     *mount_operation,
+g_drive_eject (GDrive              *drive,
 	       GCancellable        *cancellable,
 	       GAsyncReadyCallback  callback,
 	       gpointer             user_data)
@@ -271,38 +311,34 @@
   GDriveIface *iface;
 
   g_return_if_fail (G_IS_DRIVE (drive));
-  g_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
 
   iface = G_DRIVE_GET_IFACE (drive);
 
-  if (iface->mount_fn == NULL)
+  if (iface->eject == NULL)
     {
       g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data,
 					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-					   _("drive doesn't implement mount"));
+					   _("drive doesn't implement eject"));
       
       return;
     }
   
-  (* iface->mount_fn) (drive, mount_operation, cancellable, callback, user_data);
+  (* iface->eject) (drive, cancellable, callback, user_data);
 }
 
 /**
- * g_drive_mount_finish:
+ * g_drive_eject_finish
  * @drive: a #GDrive.
  * @result: a #GAsyncResult.
  * @error: a #GError.
  * 
- * Finishes mounting a drive. 
- *
- * If the @drive's interface does not implement the mount operation, @error will 
- * be set to %G_IO_ERROR_NOT_SUPPORTED and %FALSE will be returned.
+ * Finishes ejecting a drive.
  * 
- * Returns: %TRUE if the mount was finished successfully, 
- *     %FALSE if operation failed.
+ * Returns: %TRUE if the drive has been ejected successfully,
+ * %FALSE otherwise.
  **/
 gboolean
-g_drive_mount_finish (GDrive        *drive,
+g_drive_eject_finish (GDrive        *drive,
 		      GAsyncResult  *result,
 		      GError       **error)
 {
@@ -319,24 +355,25 @@
     }
   
   iface = G_DRIVE_GET_IFACE (drive);
-  return (* iface->mount_finish) (drive, result, error);
+  
+  return (* iface->eject_finish) (drive, result, error);
 }
 
 /**
- * g_drive_eject:
+ * g_drive_poll_for_media:
  * @drive: a #GDrive.
  * @cancellable: optional #GCancellable object, %NULL to ignore.
  * @callback: a #GAsyncReadyCallback.
  * @user_data: a #gpointer.
  * 
- * Ejects a drive.
+ * Polls @drive to see if media has been inserted or removed.
  * 
  **/
 void
-g_drive_eject (GDrive              *drive,
-	       GCancellable        *cancellable,
-	       GAsyncReadyCallback  callback,
-	       gpointer             user_data)
+g_drive_poll_for_media (GDrive              *drive,
+                        GCancellable        *cancellable,
+                        GAsyncReadyCallback  callback,
+                        gpointer             user_data)
 {
   GDriveIface *iface;
 
@@ -344,36 +381,33 @@
 
   iface = G_DRIVE_GET_IFACE (drive);
 
-  if (iface->eject == NULL)
+  if (iface->poll_for_media == NULL)
     {
       g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data,
 					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-					   _("drive doesn't implement eject"));
+					   _("drive doesn't implement polling for media"));
       
       return;
     }
   
-  (* iface->eject) (drive, cancellable, callback, user_data);
+  (* iface->poll_for_media) (drive, cancellable, callback, user_data);
 }
 
 /**
- * g_drive_eject_finish
+ * g_drive_poll_for_media_finish
  * @drive: a #GDrive.
  * @result: a #GAsyncResult.
  * @error: a #GError.
  * 
- * Finishes ejecting a drive.
- *
- * If @drive's interface does not implement the eject operation, @error will 
- * be set to %G_IO_ERROR_NOT_SUPPORTED and %FALSE will be returned.
+ * Finishes poll_for_mediaing a drive.
  * 
- * Returns: %TRUE if the drive has been ejected successfully,
+ * Returns: %TRUE if the drive has been poll_for_mediaed successfully,
  * %FALSE otherwise.
  **/
 gboolean
-g_drive_eject_finish (GDrive        *drive,
-		      GAsyncResult  *result,
-		      GError       **error)
+g_drive_poll_for_media_finish (GDrive        *drive,
+                               GAsyncResult  *result,
+                               GError       **error)
 {
   GDriveIface *iface;
 
@@ -389,7 +423,7 @@
   
   iface = G_DRIVE_GET_IFACE (drive);
   
-  return (* iface->mount_finish) (drive, result, error);
+  return (* iface->poll_for_media_finish) (drive, result, error);
 }
 
 #define __G_DRIVE_C__
Index: gdrive.h
===================================================================
--- gdrive.h	(revision 6093)
+++ gdrive.h	(working copy)
@@ -40,15 +40,17 @@
  * @changed: Signal emitted when the drive is changed.
  * @get_name: Returns the name for the given #GDrive.
  * @get_icon: Returns a #GIcon for the given #GDrive.
- * @has_volumes: Returns %TRUE if the #GDrive has mountable volumes.
- * @get_volumes: Returns a #GList of volumes for the #GDrive.
- * @is_automounted: returns %TRUE if the #GDrive was automounted.
- * @can_mount: Returns %TRUE if the #GDrive can be mounted.
- * @can_eject: Returns %TRUE if the #GDrive can be ejected.
- * @mount_fn: Mounts a given #GDrive.
- * @mount_finish: Finishes a mount operation.
+ * @has_mountable_volumes: Returns %TRUE if the #GDrive has mountable volumes.
+ * @get_mountable_volumes: Returns a list #GList of #GMountableVolume for the #GDrive.
+ * @is_media_removable: Returns %TRUE if the #GDrive supports removal and insertion of media.
+ * @has_media: Returns %TRUE if the #GDrive has media inserted.
+ * @is_media_check_automatic: Returns %TRUE if the #GDrive is capabable of automatically detecting media changes.
+ * @can_poll_for_media: Returns %TRUE if the #GDrive is capable of manually polling for media change.
+ * @can_eject: Returns %TRUE if the #GDrive can eject media.
  * @eject: Ejects a #GDrive.
  * @eject_finish: Finishes an eject operation.
+ * @poll_for_media: Poll for media insertion/removal on a #GDrive.
+ * @poll_for_media_finish: Finishes a media poll operation.
  * 
  * Interface for creating #GDrive implementations.
  */ 
@@ -59,58 +61,59 @@
   GTypeInterface g_iface;
 
   /* signals */
-  void (*changed)            (GVolume *volume);
+  void (*changed)                      (GDrive              *drive);
   
   /* Virtual Table */
-  
-  char *   (*get_name)    (GDrive         *drive);
-  GIcon *  (*get_icon)    (GDrive         *drive);
-  gboolean (*has_volumes) (GDrive         *drive);
-  GList *  (*get_volumes) (GDrive         *drive);
-  gboolean (*is_automounted)(GDrive       *drive);
-  gboolean (*can_mount)   (GDrive         *drive);
-  gboolean (*can_eject)   (GDrive         *drive);
-  void     (*mount_fn)    (GDrive         *drive,
-			   GMountOperation *mount_operation,
-			   GCancellable   *cancellable,
-			   GAsyncReadyCallback callback,
-			   gpointer        user_data);
-  gboolean (*mount_finish)(GDrive         *drive,
-			   GAsyncResult   *result,
-			   GError        **error);
-  void     (*eject)       (GDrive         *drive,
-			   GCancellable   *cancellable,
-			   GAsyncReadyCallback callback,
-			   gpointer        user_data);
-  gboolean (*eject_finish)(GDrive         *drive,
-			   GAsyncResult   *result,
-			   GError        **error);
+  char *   (*get_name)                 (GDrive              *drive);
+  GIcon *  (*get_icon)                 (GDrive              *drive);
+  gboolean (*has_mountable_volumes)    (GDrive              *drive);
+  GList *  (*get_mountable_volumes)    (GDrive              *drive);
+  gboolean (*is_media_removable)       (GDrive              *drive);
+  gboolean (*has_media)                (GDrive              *drive);
+  gboolean (*is_media_check_automatic) (GDrive              *drive);
+  gboolean (*can_eject)                (GDrive              *drive);
+  gboolean (*can_poll_for_media)       (GDrive              *drive);
+  void     (*eject)                    (GDrive              *drive,
+                                        GCancellable        *cancellable,
+                                        GAsyncReadyCallback  callback,
+                                        gpointer             user_data);
+  gboolean (*eject_finish)             (GDrive              *drive,
+                                        GAsyncResult        *result,
+                                        GError             **error);
+  void     (*poll_for_media)           (GDrive              *drive,
+                                        GCancellable        *cancellable,
+                                        GAsyncReadyCallback  callback,
+                                        gpointer             user_data);
+  gboolean (*poll_for_media_finish)    (GDrive              *drive,
+                                        GAsyncResult        *result,
+                                        GError             **error);
 };
 
-GType g_drive_get_type (void) G_GNUC_CONST;
+GType g_drive_get_type                    (void) G_GNUC_CONST;
 
-char *   g_drive_get_name       (GDrive               *drive);
-GIcon *  g_drive_get_icon       (GDrive               *drive);
-gboolean g_drive_has_volumes    (GDrive               *drive);
-GList  * g_drive_get_volumes    (GDrive               *drive);
-gboolean g_drive_is_automounted (GDrive               *drive);
-gboolean g_drive_can_mount      (GDrive               *drive);
-gboolean g_drive_can_eject      (GDrive               *drive);
-void     g_drive_mount          (GDrive               *drive,
-				 GMountOperation      *mount_operation,
-				 GCancellable         *cancellable,
-				 GAsyncReadyCallback   callback,
-				 gpointer              user_data);
-gboolean g_drive_mount_finish   (GDrive               *drive,
-				 GAsyncResult         *result,
-				 GError              **error);
-void     g_drive_eject          (GDrive               *drive,
-				 GCancellable         *cancellable,
-				 GAsyncReadyCallback   callback,
-				 gpointer              user_data);
-gboolean g_drive_eject_finish   (GDrive               *drive,
-				 GAsyncResult         *result,
-				 GError              **error);
+char *   g_drive_get_name                 (GDrive               *drive);
+GIcon *  g_drive_get_icon                 (GDrive               *drive);
+gboolean g_drive_has_mountable_volumes    (GDrive               *drive);
+GList *  g_drive_get_mountable_volumes    (GDrive               *drive);
+gboolean g_drive_is_media_removable       (GDrive               *drive);
+gboolean g_drive_has_media                (GDrive               *drive);
+gboolean g_drive_is_media_check_automatic (GDrive               *drive);
+gboolean g_drive_can_poll_for_media       (GDrive               *drive);
+gboolean g_drive_can_eject                (GDrive               *drive);
+void     g_drive_eject                    (GDrive               *drive,
+                                           GCancellable         *cancellable,
+                                           GAsyncReadyCallback   callback,
+                                           gpointer              user_data);
+gboolean g_drive_eject_finish             (GDrive               *drive,
+                                           GAsyncResult         *result,
+                                           GError              **error);
+void     g_drive_poll_for_media           (GDrive               *drive,
+                                           GCancellable         *cancellable,
+                                           GAsyncReadyCallback   callback,
+                                           gpointer              user_data);
+gboolean g_drive_poll_for_media_finish    (GDrive               *drive,
+                                           GAsyncResult         *result,
+                                           GError              **error);
 
 G_END_DECLS
 
Index: gvolumemonitor.c
===================================================================
--- gvolumemonitor.c	(revision 6093)
+++ gvolumemonitor.c	(working copy)
@@ -37,11 +37,16 @@
 G_DEFINE_TYPE (GVolumeMonitor, g_volume_monitor, G_TYPE_OBJECT);
 
 enum {
+  MOUNTABLE_VOLUME_ADDED,
+  MOUNTABLE_VOLUME_REMOVED,
+  MOUNTABLE_VOLUME_CHANGED,
   VOLUME_MOUNTED,
+  VOLUME_UNMOUNTED,
   VOLUME_PRE_UNMOUNT,
-  VOLUME_UNMOUNTED,
+  VOLUME_CHANGED,
   DRIVE_CONNECTED,
   DRIVE_DISCONNECTED,
+  DRIVE_CHANGED,
   LAST_SIGNAL
 };
 
@@ -67,20 +72,81 @@
   gobject_class->finalize = g_volume_monitor_finalize;
 
   /**
-   * GVolumeMonitor::volume-mounted:   
+   * GVolumeMonitor::mountable-volume-added:
    * @volume_monitor: The volume monitor emitting the signal.
-   * @volume: the volume that was mounted.
-   *
+   * @mountable_volume: a #GMountableVolume that was added.
+   * 
+   * Emitted when a mountable volume is added to the system.
+   **/
+  signals[MOUNTABLE_VOLUME_ADDED] = g_signal_new (I_("mountable_volume_added"),
+                                                  G_TYPE_VOLUME_MONITOR,
+                                                  G_SIGNAL_RUN_LAST,
+                                                  G_STRUCT_OFFSET (GVolumeMonitorClass, mountable_volume_added),
+                                                  NULL, NULL,
+                                                  g_cclosure_marshal_VOID__OBJECT,
+                                                  G_TYPE_NONE, 1, G_TYPE_MOUNTABLE_VOLUME);
+  
+  /**
+   * GVolumeMonitor::mountable-volume-removed:
+   * @volume_monitor: The volume monitor emitting the signal.
+   * @mountable_volume: a #GMountableVolume that was removed.
+   * 
+   * Emitted when a mountable volume is removed from the system.
+   **/  
+  signals[MOUNTABLE_VOLUME_REMOVED] = g_signal_new (I_("mountable_volume_removed"),
+                                                    G_TYPE_VOLUME_MONITOR,
+                                                    G_SIGNAL_RUN_LAST,
+                                                    G_STRUCT_OFFSET (GVolumeMonitorClass, mountable_volume_removed),
+                                                    NULL, NULL,
+                                                    g_cclosure_marshal_VOID__OBJECT,
+                                                    G_TYPE_NONE, 1, G_TYPE_MOUNTABLE_VOLUME);
+
+  /**
+   * GVolumeMonitor::mountable-volume-changed:
+   * @volume_monitor: The volume monitor emitting the signal.
+   * @mountable_volume: a #GMountableVolume that changed.
+   * 
+   * Emitted when mountable volume is changed.
+   **/  
+  signals[MOUNTABLE_VOLUME_CHANGED] = g_signal_new (I_("mountable_volume_changed"),
+                                                    G_TYPE_VOLUME_MONITOR,
+                                                    G_SIGNAL_RUN_LAST,
+                                                    G_STRUCT_OFFSET (GVolumeMonitorClass, mountable_volume_changed),
+                                                    NULL, NULL,
+                                                    g_cclosure_marshal_VOID__OBJECT,
+                                                    G_TYPE_NONE, 1, G_TYPE_MOUNTABLE_VOLUME);
+
+  /**
+   * GVolumeMonitor::volume-mounted:
+   * @volume_monitor: The volume monitor emitting the signal.
+   * @volume: a #GVolume that was mounted.
+   * 
    * Emitted when a volume is mounted.
    **/
   signals[VOLUME_MOUNTED] = g_signal_new (I_("volume_mounted"),
-					  G_TYPE_VOLUME_MONITOR,
-					  G_SIGNAL_RUN_LAST,
-					  G_STRUCT_OFFSET (GVolumeMonitorClass, volume_mounted),
-					  NULL, NULL,
-					  g_cclosure_marshal_VOID__OBJECT,
-					  G_TYPE_NONE, 1, G_TYPE_VOLUME);
+                                          G_TYPE_VOLUME_MONITOR,
+                                          G_SIGNAL_RUN_LAST,
+                                          G_STRUCT_OFFSET (GVolumeMonitorClass, volume_mounted),
+                                          NULL, NULL,
+                                          g_cclosure_marshal_VOID__OBJECT,
+                                          G_TYPE_NONE, 1, G_TYPE_VOLUME);
+
   /**
+   * GVolumeMonitor::volume-unmounted:
+   * @volume_monitor: The volume monitor emitting the signal.
+   * @volume: a #GVolume that was unmounted.
+   * 
+   * Emitted when a volume is unmounted.
+   **/
+  signals[VOLUME_UNMOUNTED] = g_signal_new (I_("volume_unmounted"),
+                                            G_TYPE_VOLUME_MONITOR,
+                                            G_SIGNAL_RUN_LAST,
+                                            G_STRUCT_OFFSET (GVolumeMonitorClass, volume_unmounted),
+                                            NULL, NULL,
+                                            g_cclosure_marshal_VOID__OBJECT,
+                                            G_TYPE_NONE, 1, G_TYPE_VOLUME);
+
+  /**
    * GVolumeMonitor::volume-pre-unmount:
    * @volume_monitor: The volume monitor emitting the signal.
    * @volume: the volume that is being unmounted.
@@ -94,20 +160,22 @@
 					      NULL, NULL,
 					      g_cclosure_marshal_VOID__OBJECT,
 					      G_TYPE_NONE, 1, G_TYPE_VOLUME);
+
   /**
-   * GVolumeMonitor::volume-unmounted:
+   * GVolumeMonitor::volume-changed:
    * @volume_monitor: The volume monitor emitting the signal.
-   * @volume: the volume that was unmounted.
-   * 
-   * Emitted when a volume is unmounted.
-   **/  
-  signals[VOLUME_UNMOUNTED] = g_signal_new (I_("volume_unmounted"),
-					    G_TYPE_VOLUME_MONITOR,
-					    G_SIGNAL_RUN_LAST,
-					    G_STRUCT_OFFSET (GVolumeMonitorClass, volume_unmounted),
-					    NULL, NULL,
-					    g_cclosure_marshal_VOID__OBJECT,
-					    G_TYPE_NONE, 1, G_TYPE_VOLUME);
+   * @volume: the volume that changed
+   *
+   * Emitted when a volume changes.
+   **/ 
+  signals[VOLUME_CHANGED] = g_signal_new (I_("volume_changed"),
+                                          G_TYPE_VOLUME_MONITOR,
+                                          G_SIGNAL_RUN_LAST,
+                                          G_STRUCT_OFFSET (GVolumeMonitorClass, volume_changed),
+                                          NULL, NULL,
+                                          g_cclosure_marshal_VOID__OBJECT,
+                                          G_TYPE_NONE, 1, G_TYPE_VOLUME);
+
   /**
    * GVolumeMonitor::drive-connected:
    * @volume_monitor: The volume monitor emitting the signal.
@@ -137,6 +205,22 @@
 					      NULL, NULL,
 					      g_cclosure_marshal_VOID__OBJECT,
 					      G_TYPE_NONE, 1, G_TYPE_DRIVE);
+
+  /**
+   * GVolumeMonitor::drive-changed:
+   * @volume_monitor: The volume monitor emitting the signal.
+   * @drive: the drive that changed
+   *
+   * Emitted when a drive changes.
+   **/ 
+  signals[DRIVE_CHANGED] = g_signal_new (I_("drive_changed"),
+                                         G_TYPE_VOLUME_MONITOR,
+                                         G_SIGNAL_RUN_LAST,
+                                         G_STRUCT_OFFSET (GVolumeMonitorClass, drive_changed),
+                                         NULL, NULL,
+                                         g_cclosure_marshal_VOID__OBJECT,
+                                         G_TYPE_NONE, 1, G_TYPE_DRIVE);
+
 }
 
 static void
@@ -144,16 +228,17 @@
 {
 }
 
+
 /**
- * g_volume_monitor_get_mounted_volumes:
+ * g_volume_monitor_get_drives:
  * @volume_monitor: a #GVolumeMonitor.
  * 
- * Gets a list of volumes mounted on the computer.
+ * Gets a list of drives connected to the system.
  * 
- * Returns: a #GList of mounted #GVolumes.
+ * Returns: a #GList of connected #GDrives. 
  **/
 GList *
-g_volume_monitor_get_mounted_volumes (GVolumeMonitor *volume_monitor)
+g_volume_monitor_get_connected_drives (GVolumeMonitor *volume_monitor)
 {
   GVolumeMonitorClass *class;
 
@@ -161,19 +246,19 @@
 
   class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor);
 
-  return class->get_mounted_volumes (volume_monitor);
+  return class->get_connected_drives (volume_monitor);
 }
 
 /**
- * g_volume_monitor_get_connected_drives:
+ * g_volume_monitor_get_mountable_volumes:
  * @volume_monitor: a #GVolumeMonitor.
  * 
- * Gets a list of drives connected to the computer.
+ * Gets a list of the mountable volumes on the system.
  * 
- * Returns: a #GList of connected #GDrives. 
+ * Returns: a #GList of #GMountableVolume.
  **/
 GList *
-g_volume_monitor_get_connected_drives (GVolumeMonitor *volume_monitor)
+g_volume_monitor_get_mountable_volumes (GVolumeMonitor *volume_monitor)
 {
   GVolumeMonitorClass *class;
 
@@ -181,8 +266,28 @@
 
   class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor);
 
-  return class->get_connected_drives (volume_monitor);
+  return class->get_mountable_volumes (volume_monitor);
 }
 
+/**
+ * g_volume_monitor_get_mounted_volumes:
+ * @volume_monitor: a #GVolumeMonitor.
+ * 
+ * Gets a list of the mounted volumes on the system.
+ * 
+ * Returns: a #GList of #GVolume.
+ **/
+GList *
+g_volume_monitor_get_mounted_volumes (GVolumeMonitor *volume_monitor)
+{
+  GVolumeMonitorClass *class;
+
+  g_return_val_if_fail (G_IS_VOLUME_MONITOR (volume_monitor), NULL);
+
+  class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor);
+
+  return class->get_mounted_volumes (volume_monitor);
+}
+
 #define __G_VOLUME_MONITOR_C__
 #include "gioaliasdef.c"
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 6093)
+++ Makefile.am	(working copy)
@@ -90,8 +90,8 @@
 appinfo_sources += gdesktopappinfo.c gdesktopappinfo.h
 platform_libadd += xdgmime/libxdgmime.la
 unix_sources = \
-	gunixdrive.c 		\
-	gunixdrive.h 		\
+	gunixmountablevolume.c 	\
+	gunixmountablevolume.h 	\
 	gunixmounts.c 		\
 	gunixmounts.h 		\
 	gunixvolume.c 		\
@@ -150,6 +150,7 @@
 	giomodule-priv.h	\
 	gioscheduler.c 		\
 	gloadableicon.c 	\
+	gmountablevolume.c 	\
 	gmemoryinputstream.c 	\
 	gmemoryoutputstream.c 	\
 	gmountoperation.c 	\
@@ -222,6 +223,7 @@
 	giomodule.h 		\
 	gioscheduler.h 		\
 	gloadableicon.h 	\
+	gmountablevolume.h 	\
 	gmemoryinputstream.h 	\
 	gmemoryoutputstream.h 	\
 	gmountoperation.h 	\
Index: gvolumemonitor.h
===================================================================
--- gvolumemonitor.h	(revision 6093)
+++ gvolumemonitor.h	(working copy)
@@ -25,6 +25,7 @@
 
 #include <glib-object.h>
 #include <gio/gvolume.h>
+#include <gio/gmountablevolume.h>
 #include <gio/gdrive.h>
 
 G_BEGIN_DECLS
@@ -57,21 +58,34 @@
 
   /*< public >*/
   /* signals */
-  void (* volume_mounted)	(GVolumeMonitor *volume_monitor,
+  void (* mountable_volume_added)     (GVolumeMonitor   *volume_monitor,
+                                       GMountableVolume *mountable_volume);
+  void (* mountable_volume_removed)   (GVolumeMonitor   *volume_monitor,
+                                       GMountableVolume *mountable_volume);
+  void (* mountable_volume_changed)   (GVolumeMonitor   *volume_monitor,
+                                       GMountableVolume *mountable_volume);
+
+  void (* volume_mounted)       (GVolumeMonitor *volume_monitor,
 				 GVolume        *volume);
-  void (* volume_pre_unmount)	(GVolumeMonitor *volume_monitor,
-				 GVolume	*volume);
-  void (* volume_unmounted)	(GVolumeMonitor *volume_monitor,
+  void (* volume_unmounted)     (GVolumeMonitor *volume_monitor,
 				 GVolume        *volume);
-  void (* drive_connected) 	(GVolumeMonitor *volume_monitor,
+  void (* volume_pre_unmount)   (GVolumeMonitor *volume_monitor,
+				 GVolume        *volume);
+  void (* volume_changed)       (GVolumeMonitor *volume_monitor,
+				 GVolume        *volume);
+
+  void (* drive_connected)      (GVolumeMonitor *volume_monitor,
 				 GDrive	        *drive);
-  void (* drive_disconnected)	(GVolumeMonitor *volume_monitor,
+  void (* drive_disconnected)   (GVolumeMonitor *volume_monitor,
 				 GDrive         *drive);
+  void (* drive_changed)        (GVolumeMonitor *volume_monitor,
+				 GDrive         *drive);
 
   /* Vtable */
 
-  GList * (*get_mounted_volumes)  (GVolumeMonitor *volume_monitor);
-  GList * (*get_connected_drives) (GVolumeMonitor *volume_monitor);
+  GList * (*get_connected_drives)   (GVolumeMonitor *volume_monitor);
+  GList * (*get_mountable_volumes)  (GVolumeMonitor *volume_monitor);
+  GList * (*get_mounted_volumes)    (GVolumeMonitor *volume_monitor);
 
   /*< private >*/
   /* Padding for future expansion */
@@ -87,9 +101,10 @@
 
 GType g_volume_monitor_get_type (void) G_GNUC_CONST;
 
-GVolumeMonitor *g_volume_monitor_get                  (void);
-GList *         g_volume_monitor_get_mounted_volumes  (GVolumeMonitor *volume_monitor);
-GList *         g_volume_monitor_get_connected_drives (GVolumeMonitor *volume_monitor);
+GVolumeMonitor *g_volume_monitor_get          (void);
+GList *         g_volume_monitor_get_connected_drives   (GVolumeMonitor *volume_monitor);
+GList *         g_volume_monitor_get_mountable_volumes  (GVolumeMonitor *volume_monitor);
+GList *         g_volume_monitor_get_mounted_volumes    (GVolumeMonitor *volume_monitor);
 
 G_END_DECLS
 
Index: gunixvolume.c
===================================================================
--- gunixvolume.c	(revision 6093)
+++ gunixvolume.c	(working copy)
@@ -1,3 +1,5 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
 /* GIO - GLib Input, Output and Streaming Library
  * 
  * Copyright (C) 2006-2007 Red Hat, Inc.
@@ -23,14 +25,17 @@
 #include <config.h>
 
 #include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
 #include <glib.h>
 #include "gunixvolumemonitor.h"
 #include "gunixvolume.h"
-#include "gunixdrive.h"
+#include "gunixmountablevolume.h"
 #include "gvolumeprivate.h"
 #include "gvolumemonitor.h"
 #include "gthemedicon.h"
+#include "gsimpleasyncresult.h"
 #include "glibintl.h"
 
 #include "gioalias.h"
@@ -38,10 +43,13 @@
 struct _GUnixVolume {
   GObject parent;
 
-  GUnixDrive *drive; /* owned by volume monitor */
+  GVolumeMonitor       *volume_monitor;
+  GUnixMountableVolume *mountable_volume; /* owned by volume monitor */
+
   char *name;
   char *icon;
-  char *mountpoint;
+  char *device_path;
+  char *mount_path;
 };
 
 static void g_unix_volume_volume_iface_init (GVolumeIface *iface);
@@ -59,13 +67,17 @@
   
   volume = G_UNIX_VOLUME (object);
 
-  if (volume->drive)
-    _g_unix_drive_unset_volume (volume->drive, volume);
+  if (volume->volume_monitor != NULL)
+    g_object_unref (volume->volume_monitor);
+
+  if (volume->mountable_volume)
+    _g_unix_mountable_volume_unset_volume (volume->mountable_volume, volume);
     
-  g_warn_if_fail (volume->drive == NULL);
+  //TODO DZE:g_warn_if_fail (volume->mountable_volume == NULL);
   g_free (volume->name);
   g_free (volume->icon);
-  g_free (volume->mountpoint);
+  g_free (volume->device_path);
+  g_free (volume->mount_path);
   
   if (G_OBJECT_CLASS (g_unix_volume_parent_class)->finalize)
     (*G_OBJECT_CLASS (g_unix_volume_parent_class)->finalize) (object);
@@ -84,97 +96,28 @@
 {
 }
 
-static char *
-get_filesystem_volume_name (const char *fs_type)
-{
-  /* TODO: add translation table from gnome-vfs */
-  return g_strdup_printf (_("%s volume"), fs_type);
-}
-
-static char *
-type_to_icon (GUnixMountType type)
-{
-  const char *icon_name = NULL;
-  
-  switch (type)
-    {
-    case G_UNIX_MOUNT_TYPE_HD:
-      icon_name = "drive-harddisk";
-      break;
-    case G_UNIX_MOUNT_TYPE_FLOPPY:
-    case G_UNIX_MOUNT_TYPE_ZIP:
-    case G_UNIX_MOUNT_TYPE_JAZ:
-      icon_name = "media-floppy";
-      break;
-    case G_UNIX_MOUNT_TYPE_CDROM:
-      icon_name = "media-optical";
-      break;
-    case G_UNIX_MOUNT_TYPE_NFS:
-      /* TODO: Would like a better icon here... */
-      icon_name = "drive-harddisk";
-      break;
-    case G_UNIX_MOUNT_TYPE_MEMSTICK:
-      icon_name = "media-flash";
-      break;
-    case G_UNIX_MOUNT_TYPE_CAMERA:
-      icon_name = "camera-photo";
-      break;
-    case G_UNIX_MOUNT_TYPE_IPOD:
-      icon_name = "multimedia-player";
-      break;
-    case G_UNIX_MOUNT_TYPE_UNKNOWN:
-    default:
-      icon_name = "drive-harddisk";
-      break;
-    }
-  return g_strdup (icon_name);
-}
-
 GUnixVolume *
-_g_unix_volume_new (GUnixMount *mount,
-		    GUnixDrive *drive)
+_g_unix_volume_new (GVolumeMonitor        *volume_monitor,
+                    GUnixMount            *mount,
+		    GUnixMountableVolume  *mountable_volume)
 {
   GUnixVolume *volume;
-  GUnixMountType type;
-  const char *mount_path;
-  char *volume_name;
   
-  mount_path = g_unix_mount_get_mount_path (mount);
-  
-  /* No drive for volume. Ignore internal things */
-  if (drive == NULL && g_unix_mount_is_system_internal (mount))
+  /* No mountable volume for volume: Ignore internal things */
+  if (mountable_volume == NULL && g_unix_mount_is_system_internal (mount))
     return NULL;
-  
+
   volume = g_object_new (G_TYPE_UNIX_VOLUME, NULL);
-  volume->drive = drive;
-  if (drive)
-    _g_unix_drive_set_volume (drive, volume);
-  volume->mountpoint = g_strdup (mount_path);
+  volume->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL;
+  volume->device_path = g_strdup (g_unix_mount_get_device_path (mount));
+  volume->mount_path = g_strdup (g_unix_mount_get_mount_path (mount));
+  volume->name = g_unix_mount_guess_name (mount);
+  volume->icon = g_unix_mount_guess_icon_name (mount);
 
-  type = g_unix_mount_guess_type (mount);
-  
-  volume->icon = type_to_icon (type);
-					  
-  volume_name = NULL;
-  if (mount_path)
-    {
-      if (strcmp (mount_path, "/") == 0)
-	volume_name = g_strdup (_("Filesystem root"));
-      else
-	volume_name = g_filename_display_basename (mount_path);
-    }
-      
-  if (volume_name == NULL)
-    {
-      if (g_unix_mount_get_fs_type (mount) != NULL)
-	volume_name = g_strdup (get_filesystem_volume_name (g_unix_mount_get_fs_type (mount)));
-    }
-  
-  if (volume_name == NULL)
-    /* TODO: Use volume size as name? */
-    volume_name = g_strdup (_("Unknown volume"));
-  
-  volume->name = volume_name;
+  /* need to do this last */
+  volume->mountable_volume = mountable_volume;
+  if (mountable_volume != NULL)
+    _g_unix_mountable_volume_set_volume (mountable_volume, volume);
 
   return volume;
 }
@@ -182,23 +125,27 @@
 void
 _g_unix_volume_unmounted (GUnixVolume *volume)
 {
-  if (volume->drive)
+  if (volume->mountable_volume != NULL)
     {
-      _g_unix_drive_unset_volume (volume->drive, volume);
-      volume->drive = NULL;
+      _g_unix_mountable_volume_unset_volume (volume->mountable_volume, volume);
+      volume->mountable_volume = NULL;
       g_signal_emit_by_name (volume, "changed");
+      /* there's really no need to emit volume_changed on the volume monitor 
+       * as we're going to be deleted.. */
     }
 }
 
 void
-_g_unix_volume_unset_drive (GUnixVolume *volume,
-			    GUnixDrive  *drive)
+_g_unix_volume_unset_mountable_volume (GUnixVolume *volume,
+                                       GUnixMountableVolume  *mountable_volume)
 {
-  if (volume->drive == drive)
+  if (volume->mountable_volume == mountable_volume)
     {
-      volume->drive = NULL;
+      volume->mountable_volume = NULL;
       /* TODO: Emit changed in idle to avoid locking issues */
       g_signal_emit_by_name (volume, "changed");
+      if (volume->volume_monitor != NULL)
+        g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume);
     }
 }
 
@@ -207,7 +154,7 @@
 {
   GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
 
-  return g_file_new_for_path (unix_volume->mountpoint);
+  return g_file_new_for_path (unix_volume->mount_path);
 }
 
 static GIcon *
@@ -227,10 +174,10 @@
 }
 
 gboolean
-_g_unix_volume_has_mountpoint (GUnixVolume *volume,
-			       const char  *mountpoint)
+_g_unix_volume_has_mount_path (GUnixVolume *volume,
+			       const char  *mount_path)
 {
-  return strcmp (volume->mountpoint, mountpoint) == 0;
+  return strcmp (volume->mount_path, mount_path) == 0;
 }
 
 static GDrive *
@@ -238,8 +185,19 @@
 {
   GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
 
-  if (unix_volume->drive)
-    return G_DRIVE (g_object_ref (unix_volume->drive));
+  if (unix_volume->mountable_volume != NULL)
+    return g_mountable_volume_get_drive (G_MOUNTABLE_VOLUME (unix_volume->mountable_volume));
+
+  return NULL;
+}
+
+static GMountableVolume *
+g_unix_volume_get_mountable_volume (GVolume *volume)
+{
+  GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
+
+  if (unix_volume->mountable_volume)
+    return G_MOUNTABLE_VOLUME (g_object_ref (unix_volume->mountable_volume));
   
   return NULL;
 }
@@ -247,15 +205,71 @@
 static gboolean
 g_unix_volume_can_unmount (GVolume *volume)
 {
-  /* TODO */
-  return FALSE;
+  return TRUE;
 }
 
+
+typedef struct {
+  GUnixVolume *unix_volume;
+  GAsyncReadyCallback callback;
+  gpointer user_data;
+  GCancellable *cancellable;
+  int error_fd;
+  GIOChannel *error_channel;
+  guint error_channel_source_id;
+  GString *error_string;
+} UnmountOp;
+
+static void 
+unmount_cb (GPid pid, gint status, gpointer user_data)
+{
+  UnmountOp *data = user_data;
+  GSimpleAsyncResult *simple;
+  
+  if (WEXITSTATUS (status) != 0)
+    {
+      GError *error;
+      error = g_error_new_literal (G_IO_ERROR, 
+                                   G_IO_ERROR_FAILED,
+                                   data->error_string->str);
+      simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_volume),
+                                                     data->callback,
+                                                     data->user_data,
+                                                     error);
+      g_error_free (error);
+    }
+  else
+    {
+      simple = g_simple_async_result_new (G_OBJECT (data->unix_volume),
+                                          data->callback,
+                                          data->user_data,
+                                          NULL);
+    }
+
+  g_simple_async_result_complete (simple);
+  g_object_unref (simple);
+
+  g_source_remove (data->error_channel_source_id);
+  g_io_channel_unref (data->error_channel);
+  g_string_free (data->error_string, TRUE);
+  close (data->error_fd);
+  g_spawn_close_pid (pid);
+  g_free (data);
+}
+
 static gboolean
-g_unix_volume_can_eject (GVolume *volume)
+unmount_read_error (GIOChannel *channel,
+                  GIOCondition condition,
+                  gpointer user_data)
 {
-  /* TODO */
-  return FALSE;
+  char *str;
+  gsize str_len;
+  UnmountOp *data = user_data;
+
+  g_io_channel_read_to_end (channel, &str, &str_len, NULL);
+  g_string_append (data->error_string, str);
+  g_free (str);
+  return TRUE;
 }
 
 static void
@@ -264,7 +278,50 @@
 		       GAsyncReadyCallback  callback,
 		       gpointer             user_data)
 {
-  /* TODO */
+  GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
+  UnmountOp *data;
+  GPid child_pid;
+  GError *error;
+  char *argv[] = {"umount", NULL, NULL};
+
+  if (unix_volume->mount_path != NULL)
+    argv[1] = unix_volume->mount_path;
+  else
+    argv[1] = unix_volume->device_path;
+  
+  data = g_new0 (UnmountOp, 1);
+  data->unix_volume = unix_volume;
+  data->callback = callback;
+  data->user_data = user_data;
+  data->cancellable = cancellable;
+  
+  error = NULL;
+  if (!g_spawn_async_with_pipes (NULL,         /* working dir */
+                                 argv,
+                                 NULL,         /* envp */
+                                 G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH,
+                                 NULL,         /* child_setup */
+                                 NULL,         /* user_data for child_setup */
+                                 &child_pid,
+                                 NULL,           /* standard_input */
+                                 NULL,           /* standard_output */
+                                 &(data->error_fd),
+                                 &error)) {
+    GSimpleAsyncResult *simple;
+    simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_volume),
+                                                   data->callback,
+                                                   data->user_data,
+                                                   error);
+    g_simple_async_result_complete (simple);
+    g_object_unref (simple);
+    g_error_free (error);
+    g_free (data);
+    return;
+  }
+  data->error_string = g_string_new ("");
+  data->error_channel = g_io_channel_unix_new (data->error_fd);
+  data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, unmount_read_error, data);
+  g_child_watch_add (child_pid, unmount_cb, data);
 }
 
 static gboolean
@@ -276,33 +333,14 @@
 }
 
 static void
-g_unix_volume_eject (GVolume         *volume,
-		     GCancellable    *cancellable,
-		     GAsyncReadyCallback callback,
-		     gpointer         user_data)
-{
-  /* TODO */
-}
-
-static gboolean
-g_unix_volume_eject_finish (GVolume *volume,
-			    GAsyncResult *result,
-			    GError **error)
-{
-  return TRUE;
-}
-
-static void
 g_unix_volume_volume_iface_init (GVolumeIface *iface)
 {
   iface->get_root = g_unix_volume_get_root;
   iface->get_name = g_unix_volume_get_name;
   iface->get_icon = g_unix_volume_get_icon;
   iface->get_drive = g_unix_volume_get_drive;
+  iface->get_mountable_volume = g_unix_volume_get_mountable_volume;
   iface->can_unmount = g_unix_volume_can_unmount;
-  iface->can_eject = g_unix_volume_can_eject;
   iface->unmount = g_unix_volume_unmount;
   iface->unmount_finish = g_unix_volume_unmount_finish;
-  iface->eject = g_unix_volume_eject;
-  iface->eject_finish = g_unix_volume_eject_finish;
 }
Index: gunixvolume.h
===================================================================
--- gunixvolume.h	(revision 6093)
+++ gunixvolume.h	(working copy)
@@ -44,13 +44,14 @@
 
 GType _g_unix_volume_get_type (void) G_GNUC_CONST;
 
-GUnixVolume *_g_unix_volume_new            (GUnixMount     *mount,
-					    GUnixDrive     *drive);
-gboolean     _g_unix_volume_has_mountpoint (GUnixVolume    *volume,
-					    const char     *mountpoint);
-void         _g_unix_volume_unset_drive    (GUnixVolume    *volume,
-					    GUnixDrive     *drive);
-void         _g_unix_volume_unmounted      (GUnixVolume    *volume);
+GUnixVolume *_g_unix_volume_new                    (GVolumeMonitor        *volume_monitor,
+                                                    GUnixMount            *mount,
+                                                    GUnixMountableVolume  *mountable_volume);
+gboolean     _g_unix_volume_has_mount_path         (GUnixVolume           *volume,
+                                                    const char            *mount_path);
+void         _g_unix_volume_unset_mountable_volume (GUnixVolume           *volume,
+                                                    GUnixMountableVolume  *mountable_volume);
+void         _g_unix_volume_unmounted              (GUnixVolume           *volume);
 
 G_END_DECLS
 
Index: gunixvolumemonitor.c
===================================================================
--- gunixvolumemonitor.c	(revision 6093)
+++ gunixvolumemonitor.c	(working copy)
@@ -1,3 +1,5 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
 /* GIO - GLib Input, Output and Streaming Library
  * 
  * Copyright (C) 2006-2007 Red Hat, Inc.
@@ -27,8 +29,8 @@
 #include <glib.h>
 #include "gunixvolumemonitor.h"
 #include "gunixmounts.h"
+#include "gunixmountablevolume.h"
 #include "gunixvolume.h"
-#include "gunixdrive.h"
 #include "gvolumeprivate.h"
 #include "glibintl.h"
 
@@ -42,16 +44,16 @@
   GList *last_mountpoints;
   GList *last_mounts;
 
-  GList *drives;
+  GList *mountable_volumes;
   GList *volumes;
 };
 
-static void mountpoints_changed (GUnixMountMonitor  *mount_monitor,
-				 gpointer            user_data);
-static void mounts_changed      (GUnixMountMonitor  *mount_monitor,
-				 gpointer            user_data);
-static void update_drives       (GUnixVolumeMonitor *monitor);
-static void update_volumes      (GUnixVolumeMonitor *monitor);
+static void mountpoints_changed      (GUnixMountMonitor  *mount_monitor,
+                                      gpointer            user_data);
+static void mounts_changed           (GUnixMountMonitor  *mount_monitor,
+                                      gpointer            user_data);
+static void update_mountable_volumes (GUnixVolumeMonitor *monitor);
+static void update_volumes           (GUnixVolumeMonitor *monitor);
 
 #define g_unix_volume_monitor_get_type _g_unix_volume_monitor_get_type
 G_DEFINE_TYPE (GUnixVolumeMonitor, g_unix_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR);
@@ -68,13 +70,15 @@
 					
   g_object_unref (monitor->mount_monitor);
 
+  g_list_foreach (monitor->last_mountpoints, (GFunc)g_unix_mount_point_free, NULL);
+  g_list_free (monitor->last_mountpoints);
   g_list_foreach (monitor->last_mounts, (GFunc)g_unix_mount_free, NULL);
   g_list_free (monitor->last_mounts);
 
   g_list_foreach (monitor->volumes, (GFunc)g_object_unref, NULL);
   g_list_free (monitor->volumes);
-  g_list_foreach (monitor->drives, (GFunc)g_object_unref, NULL);
-  g_list_free (monitor->drives);
+  g_list_foreach (monitor->mountable_volumes, (GFunc)g_object_unref, NULL);
+  g_list_free (monitor->mountable_volumes);
   
   if (G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize)
     (*G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize) (object);
@@ -95,29 +99,35 @@
 }
 
 static GList *
-get_connected_drives (GVolumeMonitor *volume_monitor)
+get_mountable_volumes (GVolumeMonitor *volume_monitor)
 {
   GUnixVolumeMonitor *monitor;
   GList *l;
   
   monitor = G_UNIX_VOLUME_MONITOR (volume_monitor);
 
-  l = g_list_copy (monitor->drives);
+  l = g_list_copy (monitor->mountable_volumes);
   g_list_foreach (l, (GFunc)g_object_ref, NULL);
 
   return l;
 }
 
+static GList *
+get_connected_drives (GVolumeMonitor *volume_monitor)
+{
+  return NULL;
+}
+
 static GVolume *
-get_volume_for_mountpoint (const char *mountpoint)
+get_volume_for_mount_path (const char *mount_path)
 {
   GUnixMount *mount;
   GUnixVolume *volume;
 
-  mount = g_get_unix_mount_at (mountpoint, NULL);
+  mount = g_get_unix_mount_at (mount_path, NULL);
   
-  /* TODO: Set drive? */
-  volume = _g_unix_volume_new (mount, NULL);
+  /* TODO: Set mountable volume? */
+  volume = _g_unix_volume_new (NULL, mount, NULL);
 
   return G_VOLUME (volume);
 }
@@ -132,10 +142,11 @@
   gobject_class->finalize = g_unix_volume_monitor_finalize;
 
   monitor_class->get_mounted_volumes = get_mounted_volumes;
+  monitor_class->get_mountable_volumes = get_mountable_volumes;
   monitor_class->get_connected_drives = get_connected_drives;
 
   native_class->priority = 0;
-  native_class->get_volume_for_mountpoint = get_volume_for_mountpoint;
+  native_class->get_volume_for_mountpoint = get_volume_for_mount_path;
 }
 
 static void
@@ -144,8 +155,8 @@
 {
   GUnixVolumeMonitor *unix_monitor = user_data;
 
-  /* Update both to make sure drives are created before volumes */
-  update_drives (unix_monitor);
+  /* Update both to make sure mountable volumes are created before volumes */
+  update_mountable_volumes (unix_monitor);
   update_volumes (unix_monitor);
 }
 
@@ -155,8 +166,8 @@
 {
   GUnixVolumeMonitor *unix_monitor = user_data;
 
-  /* Update both to make sure drives are created before volumes */
-  update_drives (unix_monitor);
+  /* Update both to make sure mountable volumes are created before volumes */
+  update_mountable_volumes (unix_monitor);
   update_volumes (unix_monitor);
 }
 
@@ -174,7 +185,7 @@
 		    "mountpoints_changed", G_CALLBACK (mountpoints_changed),
 		    unix_monitor);
 		    
-  update_drives (unix_monitor);
+  update_mountable_volumes (unix_monitor);
   update_volumes (unix_monitor);
 
 }
@@ -239,32 +250,32 @@
 }
 
 /**
- * g_unix_volume_lookup_drive_for_mountpoint: 
+ * _g_unix_volume_monitor_lookup_mountable_volume_for_mount_path: 
  * @monitor:
- * @mountpoint:
+ * @mount_path:
  * 
- * Returns:  #GUnixDrive for the given @mountpoint.
+ * Returns:  #GUnixMountableVolume for the given @mount_path.
  **/
-GUnixDrive *
-_g_unix_volume_monitor_lookup_drive_for_mountpoint (GUnixVolumeMonitor *monitor,
-						    const char         *mountpoint)
+GUnixMountableVolume *
+_g_unix_volume_monitor_lookup_mountable_volume_for_mount_path (GUnixVolumeMonitor *monitor,
+                                                               const char         *mount_path)
 {
   GList *l;
 
-  for (l = monitor->drives; l != NULL; l = l->next)
+  for (l = monitor->mountable_volumes; l != NULL; l = l->next)
     {
-      GUnixDrive *drive = l->data;
+      GUnixMountableVolume *mountable_volume = l->data;
 
-      if (_g_unix_drive_has_mountpoint (drive, mountpoint))
-	return drive;
+      if (_g_unix_mountable_volume_has_mount_path (mountable_volume, mount_path))
+	return mountable_volume;
     }
   
   return NULL;
 }
 
 static GUnixVolume *
-find_volume_by_mountpoint (GUnixVolumeMonitor *monitor,
-			   const char *mountpoint)
+find_volume_by_mountpath (GUnixVolumeMonitor *monitor,
+			   const char *mount_path)
 {
   GList *l;
 
@@ -272,7 +283,7 @@
     {
       GUnixVolume *volume = l->data;
 
-      if (_g_unix_volume_has_mountpoint (volume, mountpoint))
+      if (_g_unix_volume_has_mount_path (volume, mount_path))
 	return volume;
     }
   
@@ -280,12 +291,12 @@
 }
 
 static void
-update_drives (GUnixVolumeMonitor *monitor)
+update_mountable_volumes (GUnixVolumeMonitor *monitor)
 {
   GList *new_mountpoints;
   GList *removed, *added;
   GList *l;
-  GUnixDrive *drive;
+  GUnixMountableVolume *mountable_volume;
   
   new_mountpoints = g_get_unix_mount_points (NULL);
   
@@ -299,14 +310,14 @@
     {
       GUnixMountPoint *mountpoint = l->data;
       
-      drive = _g_unix_volume_monitor_lookup_drive_for_mountpoint (monitor,
-								  g_unix_mount_point_get_mount_path (mountpoint));
-      if (drive)
+      mountable_volume = _g_unix_volume_monitor_lookup_mountable_volume_for_mount_path (monitor,
+                                                                                        g_unix_mount_point_get_mount_path (mountpoint));
+      if (mountable_volume)
 	{
-	  _g_unix_drive_disconnected (drive);
-	  monitor->drives = g_list_remove (monitor->drives, drive);
-	  g_signal_emit_by_name (monitor, "drive_disconnected", drive);
-	  g_object_unref (drive);
+	  _g_unix_mountable_volume_disconnected (mountable_volume);
+	  monitor->mountable_volumes = g_list_remove (monitor->mountable_volumes, mountable_volume);
+	  g_signal_emit_by_name (monitor, "mountable_volume_removed", mountable_volume);
+	  g_object_unref (mountable_volume);
 	}
     }
   
@@ -314,11 +325,11 @@
     {
       GUnixMountPoint *mountpoint = l->data;
       
-      drive = _g_unix_drive_new (G_VOLUME_MONITOR (monitor), mountpoint);
-      if (drive)
+      mountable_volume = _g_unix_mountable_volume_new (G_VOLUME_MONITOR (monitor), mountpoint);
+      if (mountable_volume)
 	{
-	  monitor->drives = g_list_prepend (monitor->drives, drive);
-	  g_signal_emit_by_name (monitor, "drive_connected", drive);
+	  monitor->mountable_volumes = g_list_prepend (monitor->mountable_volumes, mountable_volume);
+	  g_signal_emit_by_name (monitor, "mountable_volume_added", mountable_volume);
 	}
     }
   
@@ -337,7 +348,7 @@
   GList *removed, *added;
   GList *l;
   GUnixVolume *volume;
-  GUnixDrive *drive;
+  GUnixMountableVolume *mountable_volume;
   const char *mount_path;
   
   new_mounts = g_get_unix_mounts (NULL);
@@ -352,7 +363,7 @@
     {
       GUnixMount *mount = l->data;
       
-      volume = find_volume_by_mountpoint (monitor, g_unix_mount_get_mount_path (mount));
+      volume = find_volume_by_mountpath (monitor, g_unix_mount_get_mount_path (mount));
       if (volume)
 	{
 	  _g_unix_volume_unmounted (volume);
@@ -368,9 +379,8 @@
 
       mount_path = g_unix_mount_get_mount_path (mount);
       
-      drive = _g_unix_volume_monitor_lookup_drive_for_mountpoint (monitor,
-								 mount_path);
-      volume = _g_unix_volume_new (mount, drive);
+      mountable_volume = _g_unix_volume_monitor_lookup_mountable_volume_for_mount_path (monitor, mount_path);
+      volume = _g_unix_volume_new (G_VOLUME_MONITOR (monitor), mount, mountable_volume);
       if (volume)
 	{
 	  monitor->volumes = g_list_prepend (monitor->volumes, volume);
Index: gunixvolumemonitor.h
===================================================================
--- gunixvolumemonitor.h	(revision 6093)
+++ gunixvolumemonitor.h	(working copy)
@@ -39,7 +39,7 @@
 
 /* Forward definitions */
 typedef struct _GUnixVolume GUnixVolume;
-typedef struct _GUnixDrive GUnixDrive;
+typedef struct _GUnixMountableVolume GUnixMountableVolume;
 
 struct _GUnixVolumeMonitorClass {
   GNativeVolumeMonitorClass parent_class;
@@ -49,8 +49,8 @@
 GType _g_unix_volume_monitor_get_type (void) G_GNUC_CONST;
 
 GVolumeMonitor *_g_unix_volume_monitor_new                         (void);
-GUnixDrive *    _g_unix_volume_monitor_lookup_drive_for_mountpoint (GUnixVolumeMonitor *monitor,
-								    const char         *mountpoint);
+GUnixMountableVolume * _g_unix_volume_monitor_lookup_mountable_volume_for_mount_path (GUnixVolumeMonitor *monitor,
+                                                                                      const char         *mountpoint);
 
 G_END_DECLS
 
Index: gunionvolumemonitor.c
===================================================================
--- gunionvolumemonitor.c	(revision 6093)
+++ gunionvolumemonitor.c	(working copy)
@@ -102,8 +102,7 @@
     {
       child_monitor = l->data;
 
-      res = g_list_concat (res,
-			   g_volume_monitor_get_mounted_volumes (child_monitor));
+      res = g_list_concat (res, g_volume_monitor_get_mounted_volumes (child_monitor));
     }
   
   G_UNLOCK (the_volume_monitor);
@@ -112,6 +111,32 @@
 }
 
 static GList *
+get_mountable_volumes (GVolumeMonitor *volume_monitor)
+{
+  GUnionVolumeMonitor *monitor;
+  GVolumeMonitor *child_monitor;
+  GList *res;
+  GList *l;
+  
+  monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
+
+  res = NULL;
+  
+  G_LOCK (the_volume_monitor);
+
+  for (l = monitor->monitors; l != NULL; l = l->next)
+    {
+      child_monitor = l->data;
+
+      res = g_list_concat (res, g_volume_monitor_get_mountable_volumes (child_monitor));
+    }
+  
+  G_UNLOCK (the_volume_monitor);
+
+  return res;
+}
+
+static GList *
 get_connected_drives (GVolumeMonitor *volume_monitor)
 {
   GUnionVolumeMonitor *monitor;
@@ -129,8 +154,7 @@
     {
       child_monitor = l->data;
 
-      res = g_list_concat (res,
-			   g_volume_monitor_get_connected_drives (child_monitor));
+      res = g_list_concat (res, g_volume_monitor_get_connected_drives (child_monitor));
     }
   
   G_UNLOCK (the_volume_monitor);
@@ -147,11 +171,42 @@
   gobject_class->finalize = g_union_volume_monitor_finalize;
   gobject_class->dispose = g_union_volume_monitor_dispose;
 
+  monitor_class->get_connected_drives = get_connected_drives;
+  monitor_class->get_mountable_volumes = get_mountable_volumes;
   monitor_class->get_mounted_volumes = get_mounted_volumes;
-  monitor_class->get_connected_drives = get_connected_drives;
 }
 
 static void
+child_mountable_volume_added (GVolumeMonitor      *child_monitor,
+                              GMountableVolume    *child_mountable_volume,
+                              GUnionVolumeMonitor *union_monitor)
+{
+  g_signal_emit_by_name (union_monitor,
+			 "mountable_volume_added",
+			 child_mountable_volume);
+}
+
+static void
+child_mountable_volume_removed (GVolumeMonitor      *child_monitor,
+                                GMountableVolume    *child_mountable_volume,
+                                GUnionVolumeMonitor *union_monitor)
+{
+  g_signal_emit_by_name (union_monitor,
+			 "mountable_volume_removed",
+			 child_mountable_volume);
+}
+
+static void
+child_mountable_volume_changed (GVolumeMonitor      *child_monitor,
+                                GMountableVolume    *child_mountable_volume,
+                                GUnionVolumeMonitor *union_monitor)
+{
+  g_signal_emit_by_name (union_monitor,
+			 "mountable_volume_changed",
+			 child_mountable_volume);
+}
+
+static void
 child_volume_mounted (GVolumeMonitor      *child_monitor,
                       GVolume             *child_volume,
                       GUnionVolumeMonitor *union_monitor)
@@ -162,6 +217,16 @@
 }
 
 static void
+child_volume_unmounted (GVolumeMonitor      *child_monitor,
+                        GVolume             *child_volume,
+                        GUnionVolumeMonitor *union_monitor)
+{
+  g_signal_emit_by_name (union_monitor,
+			 "volume_unmounted",
+			 child_volume);
+}
+
+static void
 child_volume_pre_unmount (GVolumeMonitor      *child_monitor,
                           GVolume             *child_volume,
                           GUnionVolumeMonitor *union_monitor)
@@ -171,13 +236,14 @@
 			 child_volume);
 }
 
+
 static void
-child_volume_unmounted (GVolumeMonitor      *child_monitor,
-                        GVolume             *child_volume,
-                        GUnionVolumeMonitor *union_monitor)
+child_volume_changed (GVolumeMonitor      *child_monitor,
+                      GVolume             *child_volume,
+                      GUnionVolumeMonitor *union_monitor)
 {
   g_signal_emit_by_name (union_monitor,
-			 "volume_unmounted",
+			 "volume_changed",
 			 child_volume);
 }
 
@@ -202,6 +268,16 @@
 }
 
 static void
+child_drive_changed (GVolumeMonitor      *child_monitor,
+                     GDrive             *child_drive,
+                     GUnionVolumeMonitor *union_monitor)
+{
+  g_signal_emit_by_name (union_monitor,
+                         "drive_changed",
+                         child_drive);
+}
+
+static void
 g_union_volume_monitor_add_monitor (GUnionVolumeMonitor *union_monitor,
                                     GVolumeMonitor      *volume_monitor)
 {
@@ -212,11 +288,16 @@
     g_list_prepend (union_monitor->monitors,
 		    g_object_ref (volume_monitor));
 
+  g_signal_connect (volume_monitor, "mountable_volume_added", (GCallback)child_mountable_volume_added, union_monitor);
+  g_signal_connect (volume_monitor, "mountable_volume_removed", (GCallback)child_mountable_volume_removed, union_monitor);
+  g_signal_connect (volume_monitor, "mountable_volume_changed", (GCallback)child_mountable_volume_changed, union_monitor);
   g_signal_connect (volume_monitor, "volume_mounted", (GCallback)child_volume_mounted, union_monitor);
+  g_signal_connect (volume_monitor, "volume_unmounted", (GCallback)child_volume_unmounted, union_monitor);
   g_signal_connect (volume_monitor, "volume_pre_unmount", (GCallback)child_volume_pre_unmount, union_monitor);
-  g_signal_connect (volume_monitor, "volume_unmounted", (GCallback)child_volume_unmounted, union_monitor);
+  g_signal_connect (volume_monitor, "volume_changed", (GCallback)child_volume_changed, union_monitor);
   g_signal_connect (volume_monitor, "drive_connected", (GCallback)child_drive_connected, union_monitor);
   g_signal_connect (volume_monitor, "drive_disconnected", (GCallback)child_drive_disconnected, union_monitor);
+  g_signal_connect (volume_monitor, "drive_changed", (GCallback)child_drive_changed, union_monitor);
 }
 
 static void
@@ -231,11 +312,16 @@
 
   union_monitor->monitors = g_list_delete_link (union_monitor->monitors, l);
 
+  g_signal_handlers_disconnect_by_func (child_monitor, child_mountable_volume_added, union_monitor);
+  g_signal_handlers_disconnect_by_func (child_monitor, child_mountable_volume_removed, union_monitor);
+  g_signal_handlers_disconnect_by_func (child_monitor, child_mountable_volume_changed, union_monitor);
   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_mounted, union_monitor);
+  g_signal_handlers_disconnect_by_func (child_monitor, child_volume_unmounted, union_monitor);
   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_pre_unmount, union_monitor);
-  g_signal_handlers_disconnect_by_func (child_monitor, child_volume_unmounted, union_monitor);
+  g_signal_handlers_disconnect_by_func (child_monitor, child_volume_changed, union_monitor);
   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_connected, union_monitor);
   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_disconnected, union_monitor);
+  g_signal_handlers_disconnect_by_func (child_monitor, child_drive_changed, union_monitor);
 }
 
 static gpointer
Index: gvolume.c
===================================================================
--- gvolume.c	(revision 6093)
+++ gvolume.c	(working copy)
@@ -181,15 +181,15 @@
 }
   
 /**
- * g_volume_get_drive:
+ * g_volume_get_mountable_volume:
  * @volume: a #GVolume.
  * 
- * Gets the drive for the @volume.
+ * Gets the mountable volume for the @volume.
  * 
- * Returns: a #GDrive.
+ * Returns: a #GMountableVolume or %NULL if @volume is not associated with a mountable volume.
  **/
-GDrive *
-g_volume_get_drive (GVolume *volume)
+GMountableVolume *
+g_volume_get_mountable_volume (GVolume *volume)
 {
   GVolumeIface *iface;
 
@@ -197,39 +197,42 @@
 
   iface = G_VOLUME_GET_IFACE (volume);
 
-  return (* iface->get_drive) (volume);
+  return (* iface->get_mountable_volume) (volume);
 }
 
 /**
- * g_volume_can_unmount: 
+ * g_volume_get_drive:
  * @volume: a #GVolume.
  * 
- * Checks if @volume can be mounted.
+ * Gets the drive for the @volume.
+ *
+ * This is a convenience method for getting the #GMountableVolume and
+ * the using that object to get the #GDrive.
  * 
- * Returns: %TRUE if the @volume can be unmounted.
+ * Returns: a #GDrive or %NULL if @volume is not associated with a mountable volume or a drive.
  **/
-gboolean
-g_volume_can_unmount (GVolume *volume)
+GDrive *
+g_volume_get_drive (GVolume *volume)
 {
   GVolumeIface *iface;
 
-  g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
+  g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
 
   iface = G_VOLUME_GET_IFACE (volume);
 
-  return (* iface->can_unmount) (volume);
+  return (* iface->get_drive) (volume);
 }
 
 /**
- * g_volume_can_eject:
+ * g_volume_can_unmount: 
  * @volume: a #GVolume.
  * 
- * Checks if @volume can be ejected.
+ * Checks if @volume can be mounted.
  * 
- * Returns: %TRUE if the @volume can be ejected.
+ * Returns: %TRUE if the @volume can be unmounted.
  **/
 gboolean
-g_volume_can_eject (GVolume *volume)
+g_volume_can_unmount (GVolume *volume)
 {
   GVolumeIface *iface;
 
@@ -237,7 +240,7 @@
 
   iface = G_VOLUME_GET_IFACE (volume);
 
-  return (* iface->can_eject) (volume);
+  return (* iface->can_unmount) (volume);
 }
 
 /**
@@ -309,74 +312,5 @@
   return (* iface->unmount_finish) (volume, result, error);
 }
 
-/**
- * g_volume_eject:
- * @volume: a #GVolume.
- * @cancellable: optional #GCancellable object, %NULL to ignore. 
- * @callback: a #GAsyncReadyCallback.
- * @user_data: user data passed to @callback.
- * 
- * Ejects a volume. This is an asynchronous operation, and is 
- * finished by calling g_volume_eject_finish() from the @callback 
- * with the @volume and #GAsyncResults returned in the callback.
- **/
-void
-g_volume_eject (GVolume             *volume,
-		GCancellable        *cancellable,
-		GAsyncReadyCallback  callback,
-		gpointer             user_data)
-{
-  GVolumeIface *iface;
-
-  g_return_if_fail (G_IS_VOLUME (volume));
-
-  iface = G_VOLUME_GET_IFACE (volume);
-
-  if (iface->eject == NULL)
-    {
-      g_simple_async_report_error_in_idle (G_OBJECT (volume),
-					   callback, user_data,
-					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-					   _("volume doesn't implement eject"));
-      
-      return;
-    }
-  
-  (* iface->eject) (volume, cancellable, callback, user_data);
-}
-
-/**
- * g_volume_eject_finish:
- * @volume: a #GVolume.
- * @result: a #GAsyncResult.
- * @error: a #GError location to store the error occuring, or %NULL to 
- * ignore.
- * 
- * Finishes ejecting the volume. If any errors occured during the operation, 
- * @error will be set to contain the errors and %FALSE will be returned.
- * 
- * Returns: %TRUE if the volume was successfully ejected. %FALSE otherwise.
- **/
-gboolean
-g_volume_eject_finish (GVolume       *volume,
-		       GAsyncResult  *result,
-		       GError       **error)
-{
-  GVolumeIface *iface;
-
-  g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
-  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
-
-  if (G_IS_SIMPLE_ASYNC_RESULT (result))
-    {
-      GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
-      if (g_simple_async_result_propagate_error (simple, error))
-	return FALSE;
-    }
-  
-  iface = G_VOLUME_GET_IFACE (volume);
-  return (* iface->eject_finish) (volume, result, error);
-}
-
 #define __G_VOLUME_C__
 #include "gioaliasdef.c"
Index: gvolume.h
===================================================================
--- gvolume.h	(revision 6093)
+++ gvolume.h	(working copy)
@@ -35,11 +35,19 @@
 
 /* GVolume typedef is in gfile.h due to include order issues */
 /**
+ * GMountableVolume:
+ * 
+ * Opaque mountable volume object.
+ **/
+typedef struct _GMountableVolume GMountableVolume; /* Dummy typedef */
+
+/**
  * GDrive:
  * 
  * Opaque drive object.
  **/
 typedef struct _GDrive          GDrive; /* Dummy typedef */
+
 typedef struct _GVolumeIface    GVolumeIface;
 
 /**
@@ -49,13 +57,11 @@
  * @get_root: Gets a #GFile to the root directory of the #GVolume.
  * @get_name: Gets a string containing the name of the #GVolume.
  * @get_icon: Gets a #GIcon for the #GVolume.
- * @get_drive: Gets a #GDrive the volume is located on.
+ * @get_mountable_volume: Gets a #GMountableVolume the volume is located on. Returns %NULL if the #GVolume is not associated with a #GMountableVolume.
+ * @get_drive: Gets a #GDrive the mountable volume of the volume is located on. Returns %NULL if the #GVolume is not associated with a #GDrive or a #GMountableVolume. This is convenience method for getting the #GMountableVolume and using that to get the #GDrive.
  * @can_unmount: Checks if a #GVolume can be unmounted.
- * @can_eject: Checks if a #GVolume can be ejected.
  * @unmount: Starts unmounting a #GVolume.
  * @unmount_finish: Finishes an unmounting operation.
- * @eject: Starts ejecting a #GVolume.
- * @eject_finish: Finishes an eject operation.
  * 
  * Interface for implementing operations for mounted volumes.
  **/
@@ -69,50 +75,36 @@
   
   /* Virtual Table */
 
-  GFile *  (*get_root)       (GVolume         *volume);
-  char *   (*get_name)       (GVolume         *volume);
-  GIcon *  (*get_icon)       (GVolume         *volume);
-  GDrive * (*get_drive)      (GVolume         *volume);
-  gboolean (*can_unmount)    (GVolume         *volume);
-  gboolean (*can_eject)      (GVolume         *volume);
-  void     (*unmount)        (GVolume         *volume,
-			      GCancellable    *cancellable,
-			      GAsyncReadyCallback callback,
-			      gpointer         user_data);
-  gboolean (*unmount_finish) (GVolume         *volume,
-			      GAsyncResult    *result,
-			      GError         **error);
-  void     (*eject)          (GVolume         *volume,
-			      GCancellable    *cancellable,
-			      GAsyncReadyCallback callback,
-			      gpointer         user_data);
-  gboolean (*eject_finish)   (GVolume         *volume,
-			      GAsyncResult    *result,
-			      GError         **error);
+  GFile *            (*get_root)             (GVolume         *volume);
+  char *             (*get_name)             (GVolume         *volume);
+  GIcon *            (*get_icon)             (GVolume         *volume);
+  GMountableVolume * (*get_mountable_volume) (GVolume         *volume);
+  GDrive *           (*get_drive)            (GVolume         *volume);
+  gboolean           (*can_unmount)          (GVolume         *volume);
+  void               (*unmount)              (GVolume         *volume,
+                                              GCancellable    *cancellable,
+                                              GAsyncReadyCallback callback,
+                                              gpointer         user_data);
+  gboolean           (*unmount_finish)       (GVolume         *volume,
+                                              GAsyncResult    *result,
+                                              GError         **error);
 };
 
 GType g_volume_get_type (void) G_GNUC_CONST;
 
-GFile   *g_volume_get_root       (GVolume              *volume);
-char *   g_volume_get_name       (GVolume              *volume);
-GIcon *  g_volume_get_icon       (GVolume              *volume);
-GDrive * g_volume_get_drive      (GVolume              *volume);
-gboolean g_volume_can_unmount    (GVolume              *volume);
-gboolean g_volume_can_eject      (GVolume              *volume);
-void     g_volume_unmount        (GVolume              *volume,
-				  GCancellable         *cancellable,
-				  GAsyncReadyCallback   callback,
-				  gpointer              user_data);
-gboolean g_volume_unmount_finish (GVolume              *volume,
-				  GAsyncResult         *result,
-				  GError              **error);
-void     g_volume_eject          (GVolume              *volume,
-				  GCancellable         *cancellable,
-				  GAsyncReadyCallback   callback,
-				  gpointer              user_data);
-gboolean g_volume_eject_finish   (GVolume              *volume,
-				  GAsyncResult         *result,
-				  GError              **error);
+GFile *            g_volume_get_root             (GVolume              *volume);
+char *             g_volume_get_name             (GVolume              *volume);
+GIcon *            g_volume_get_icon             (GVolume              *volume);
+GMountableVolume * g_volume_get_mountable_volume (GVolume              *volume);
+GDrive *           g_volume_get_drive            (GVolume              *volume);
+gboolean           g_volume_can_unmount          (GVolume              *volume);
+void               g_volume_unmount              (GVolume              *volume,
+                                                  GCancellable         *cancellable,
+                                                  GAsyncReadyCallback   callback,
+                                                  gpointer              user_data);
+gboolean           g_volume_unmount_finish       (GVolume              *volume,
+                                                  GAsyncResult         *result,
+                                                  GError              **error);
 
 G_END_DECLS
 
Index: gio.symbols
===================================================================
--- gio.symbols	(revision 6093)
+++ gio.symbols	(working copy)
@@ -188,15 +188,17 @@
 g_drive_get_type G_GNUC_CONST
 g_drive_get_name
 g_drive_get_icon
-g_drive_has_volumes
-g_drive_get_volumes
-g_drive_is_automounted
-g_drive_can_mount
+g_drive_has_mountable_volumes
+g_drive_get_mountable_volumes
+g_drive_is_media_removable
+g_drive_has_media
+g_drive_is_media_check_automatic
+g_drive_can_poll_for_media
 g_drive_can_eject
-g_drive_mount
-g_drive_mount_finish
 g_drive_eject
 g_drive_eject_finish
+g_drive_poll_for_media
+g_drive_poll_for_media_finish
 #endif
 #endif
 
@@ -651,6 +653,8 @@
 g_unix_mount_is_readonly 
 g_unix_mount_is_system_internal 
 g_unix_mount_guess_type 
+g_unix_mount_guess_name 
+g_unix_mount_guess_icon_name
 g_unix_mount_point_compare 
 g_unix_mount_point_get_mount_path 
 g_unix_mount_point_get_device_path 
@@ -659,6 +663,8 @@
 g_unix_mount_point_is_user_mountable 
 g_unix_mount_point_is_loopback 
 g_unix_mount_point_guess_type 
+g_unix_mount_point_guess_name 
+g_unix_mount_point_guess_icon_name
 g_get_unix_mount_points 
 g_get_unix_mounts 
 g_get_unix_mount_at 
@@ -666,6 +672,8 @@
 g_unix_mount_points_changed_since 
 g_unix_mount_monitor_get_type  G_GNUC_CONST
 g_unix_mount_monitor_new 
+g_unix_get_canonical_device_path
+g_unix_is_mount_path_system_internal
 #endif /* G_OS_UNIX */
 #endif
 #endif
@@ -694,21 +702,33 @@
 g_volume_get_root 
 g_volume_get_name 
 g_volume_get_icon 
+g_volume_get_mountable_volume
 g_volume_get_drive 
 g_volume_can_unmount 
-g_volume_can_eject 
 g_volume_unmount 
 g_volume_unmount_finish 
-g_volume_eject 
-g_volume_eject_finish 
 #endif
 #endif
 
+#if IN_HEADER(__G_MOUNTABLE_VOLUME_H__)
+#if IN_FILE(__G_MOUNTABLE_VOLUME_C__)
+g_mountable_volume_get_type  G_GNUC_CONST
+g_mountable_volume_get_name 
+g_mountable_volume_get_icon 
+g_mountable_volume_get_drive 
+g_mountable_volume_get_volume
+g_mountable_volume_can_mount
+g_mountable_volume_mount 
+g_mountable_volume_mount_finish 
+#endif
+#endif
+
 #if IN_HEADER(__G_VOLUME_MONITOR_H__)
 #if IN_FILE(__G_VOLUME_MONITOR_C__)
 g_volume_monitor_get_type  G_GNUC_CONST
+g_volume_monitor_get_connected_drives 
+g_volume_monitor_get_mountable_volumes 
 g_volume_monitor_get_mounted_volumes 
-g_volume_monitor_get_connected_drives 
 #endif
 #if IN_FILE(__G_UNION_VOLUME_MONITOR_C__)
 g_volume_monitor_get 
--- /dev/null	2007-12-10 22:43:26.582095961 -0500
+++ gmountablevolume.h	2007-12-10 13:23:03.000000000 -0500
@@ -0,0 +1,96 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#ifndef __G_MOUNTABLE_VOLUME_H__
+#define __G_MOUNTABLE_VOLUME_H__
+
+#include <glib-object.h>
+#include <gio/gfile.h>
+#include <gio/gdrive.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_MOUNTABLE_VOLUME            (g_mountable_volume_get_type ())
+#define G_MOUNTABLE_VOLUME(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_MOUNTABLE_VOLUME, GMountableVolume))
+#define G_IS_MOUNTABLE_VOLUME(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_MOUNTABLE_VOLUME))
+#define G_MOUNTABLE_VOLUME_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_MOUNTABLE_VOLUME, GMountableVolumeIface))
+
+/**
+ * GMountableVolumeIface:
+ * @g_iface: The parent interface.
+ * @changed: Changed signal that is emitted when the volume's state has changed.
+ * @get_name: Gets a string containing the name of the #GMountableVolume.
+ * @get_icon: Gets a #GIcon for the #GMountableVolume.
+ * @get_drive: Gets a #GDrive the volume is located on. Returns %NULL if the #GMountableVolume is not associated with a #GDrive.
+ * @get_volume: Gets a #GVolume representing the mount volume. Returns %NULL if the #GMountableVolume is not mounted.
+ * @can_mount: Returns %TRUE if the #GMountableVolume can be mounted.
+ * @mount: Mounts a given #GMountableVolume.
+ * @mount_finish: Finishes a mount operation.
+ * 
+ * Interface for implementing operations for mountable volumes.
+ **/
+typedef struct _GMountableVolumeIface    GMountableVolumeIface;
+
+struct _GMountableVolumeIface
+{
+  GTypeInterface g_iface;
+
+  /* signals */
+
+  void (*changed) (GMountableVolume *mountable_volume);
+  
+  /* Virtual Table */
+
+  char *    (*get_name)       (GMountableVolume    *mountable_volume);
+  GIcon *   (*get_icon)       (GMountableVolume    *mountable_volume);
+  GDrive *  (*get_drive)      (GMountableVolume    *mountable_volume);
+  GVolume * (*get_volume)     (GMountableVolume    *mountable_volume);
+  gboolean  (*can_mount)      (GMountableVolume    *mountable_volume);
+  void      (*mount_fn)       (GMountableVolume    *mountable_volume,
+                               GMountOperation     *mount_operation,
+                               GCancellable        *cancellable,
+                               GAsyncReadyCallback  callback,
+                               gpointer             user_data);
+  gboolean  (*mount_finish)   (GMountableVolume    *mountable_volume,
+                               GAsyncResult        *result,
+                               GError             **error);
+};
+
+GType     g_mountable_volume_get_type       (void) G_GNUC_CONST;
+
+char *    g_mountable_volume_get_name       (GMountableVolume     *mountable_volume);
+GIcon *   g_mountable_volume_get_icon       (GMountableVolume     *mountable_volume);
+GDrive *  g_mountable_volume_get_drive      (GMountableVolume     *mountable_volume);
+GVolume * g_mountable_volume_get_volume     (GMountableVolume     *mountable_volume);
+gboolean  g_mountable_volume_can_mount      (GMountableVolume     *mountable_volume);
+void      g_mountable_volume_mount          (GMountableVolume     *mountable_volume,
+                                             GMountOperation      *mount_operation,
+                                             GCancellable         *cancellable,
+                                             GAsyncReadyCallback   callback,
+                                             gpointer              user_data);
+gboolean g_mountable_volume_mount_finish    (GMountableVolume     *mountable_volume,
+                                             GAsyncResult         *result,
+                                             GError              **error);
+
+G_END_DECLS
+
+#endif /* __G_MOUNTABLE_VOLUME_H__ */
--- /dev/null	2007-12-10 22:43:26.582095961 -0500
+++ gmountablevolume.c	2007-12-10 15:09:15.000000000 -0500
@@ -0,0 +1,277 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#include <config.h>
+#include "gmountablevolume.h"
+#include "gsimpleasyncresult.h"
+#include "glibintl.h"
+
+#include "gioalias.h"
+
+/**
+ * SECTION:gmountablevolume
+ * @short_description: mountable volume management
+ * 
+ * Class for managing mountable volumes.
+ * 
+ * TODO
+ *
+ **/
+
+static void g_mountable_volume_base_init (gpointer g_class);
+static void g_mountable_volume_class_init (gpointer g_class,
+                                           gpointer class_data);
+
+GType
+g_mountable_volume_get_type (void)
+{
+  static GType mountable_volume_type = 0;
+
+  if (! mountable_volume_type)
+    {
+      static const GTypeInfo mountable_volume_info =
+      {
+        sizeof (GMountableVolumeIface), /* class_size */
+	g_mountable_volume_base_init,   /* base_init */
+	NULL,		/* base_finalize */
+	g_mountable_volume_class_init,
+	NULL,		/* class_finalize */
+	NULL,		/* class_data */
+	0,
+	0,              /* n_preallocs */
+	NULL
+      };
+
+      mountable_volume_type =
+	g_type_register_static (G_TYPE_INTERFACE, I_("GMountableVolume"),
+				&mountable_volume_info, 0);
+
+      g_type_interface_add_prerequisite (mountable_volume_type, G_TYPE_OBJECT);
+    }
+
+  return mountable_volume_type;
+}
+
+static void
+g_mountable_volume_class_init (gpointer g_class,
+		   gpointer class_data)
+{
+}
+
+static void
+g_mountable_volume_base_init (gpointer g_class)
+{
+  static gboolean initialized = FALSE;
+
+  if (! initialized)
+    {
+     /**
+      * GMountableVolume::changed:
+      * 
+      * Emitted when the volume has been changed.
+      **/
+      g_signal_new (I_("changed"),
+                    G_TYPE_MOUNTABLE_VOLUME,
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (GMountableVolumeIface, changed),
+                    NULL, NULL,
+                    g_cclosure_marshal_VOID__VOID,
+                    G_TYPE_NONE, 0);
+
+      initialized = TRUE;
+    }
+}
+
+/**
+ * g_mountable_volume_get_name:
+ * @mountable_volume: a #GMountableVolume.
+ * 
+ * Gets the name of @mountable_volume.
+ * 
+ * Returns: the name for the given @mountable_volume. The returned string should 
+ * be freed when no longer needed.
+ **/
+char *
+g_mountable_volume_get_name (GMountableVolume *mountable_volume)
+{
+  GMountableVolumeIface *iface;
+
+  g_return_val_if_fail (G_IS_MOUNTABLE_VOLUME (mountable_volume), NULL);
+
+  iface = G_MOUNTABLE_VOLUME_GET_IFACE (mountable_volume);
+
+  return (* iface->get_name) (mountable_volume);
+}
+
+/**
+ * g_mountable_volume_get_icon:
+ * @mountable_volume: a #GMountableVolume.
+ * 
+ * Gets the icon for @mountable_volume.
+ * 
+ * Returns: a #GIcon.
+ **/
+GIcon *
+g_mountable_volume_get_icon (GMountableVolume *mountable_volume)
+{
+  GMountableVolumeIface *iface;
+
+  g_return_val_if_fail (G_IS_MOUNTABLE_VOLUME (mountable_volume), NULL);
+
+  iface = G_MOUNTABLE_VOLUME_GET_IFACE (mountable_volume);
+
+  return (* iface->get_icon) (mountable_volume);
+}
+  
+/**
+ * g_mountable_volume_get_drive:
+ * @mountable_volume: a #GMountableVolume.
+ * 
+ * Gets the drive for the @mountable_volume.
+ * 
+ * Returns: a #GDrive.
+ **/
+GDrive *
+g_mountable_volume_get_drive (GMountableVolume *mountable_volume)
+{
+  GMountableVolumeIface *iface;
+
+  g_return_val_if_fail (G_IS_MOUNTABLE_VOLUME (mountable_volume), NULL);
+
+  iface = G_MOUNTABLE_VOLUME_GET_IFACE (mountable_volume);
+
+  return (* iface->get_drive) (mountable_volume);
+}
+
+/**
+ * g_mountable_volume_get_volume:
+ * @mountable_volume: a #GMountableVolume.
+ * 
+ * Gets the drive for the @mountable_volume.
+ * 
+ * Returns: a #GVolume or %NULL if @mountable_volume isn't mounted.
+ **/
+GVolume *
+g_mountable_volume_get_volume (GMountableVolume *mountable_volume)
+{
+  GMountableVolumeIface *iface;
+
+  g_return_val_if_fail (G_IS_MOUNTABLE_VOLUME (mountable_volume), NULL);
+
+  iface = G_MOUNTABLE_VOLUME_GET_IFACE (mountable_volume);
+
+  return (* iface->get_volume) (mountable_volume);
+}
+
+
+/**
+ * g_mountable_volume_can_mount:
+ * @mountable_volume: a #GMountableVolume.
+ * 
+ * Checks if a volume can be mounted.
+ * 
+ * Returns: %TRUE if the @mountable_volume can be mounted. %FALSE otherwise.
+ **/
+gboolean
+g_mountable_volume_can_mount (GMountableVolume *mountable_volume)
+{
+  GMountableVolumeIface *iface;
+
+  g_return_val_if_fail (G_IS_MOUNTABLE_VOLUME (mountable_volume), FALSE);
+
+  iface = G_MOUNTABLE_VOLUME_GET_IFACE (mountable_volume);
+
+  if (iface->can_mount == NULL)
+    return FALSE;
+
+  return (* iface->can_mount) (mountable_volume);
+}
+
+/**
+ * g_mountable_volume_mount:
+ * @mountable_volume: a #GMountableVolume.
+ * @mount_operation: a #GMountOperation.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback.
+ * @user_data: a #gpointer.
+ * 
+ * Mounts a volume.
+ **/
+void
+g_mountable_volume_mount (GMountableVolume    *mountable_volume,
+                          GMountOperation     *mount_operation,
+                          GCancellable        *cancellable,
+                          GAsyncReadyCallback  callback,
+                          gpointer             user_data)
+{
+  GMountableVolumeIface *iface;
+
+  g_return_if_fail (G_IS_MOUNTABLE_VOLUME (mountable_volume));
+  g_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
+
+  iface = G_MOUNTABLE_VOLUME_GET_IFACE (mountable_volume);
+
+  if (iface->mount_fn == NULL)
+    {
+      g_simple_async_report_error_in_idle (G_OBJECT (mountable_volume), callback, user_data,
+					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+					   _("volume doesn't implement mount"));
+      
+      return;
+    }
+  
+  (* iface->mount_fn) (mountable_volume, mount_operation, cancellable, callback, user_data);
+}
+
+/**
+ * g_mountable_volume_mount_finish:
+ * @mountable_volume: pointer to a #GMountableVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError.
+ * 
+ * Finishes mounting a volume.
+ * 
+ * Returns: %TRUE, %FALSE if operation failed.
+ **/
+gboolean
+g_mountable_volume_mount_finish (GMountableVolume  *mountable_volume,
+                                 GAsyncResult      *result,
+                                 GError           **error)
+{
+  GMountableVolumeIface *iface;
+
+  g_return_val_if_fail (G_IS_MOUNTABLE_VOLUME (mountable_volume), FALSE);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+  if (G_IS_SIMPLE_ASYNC_RESULT (result))
+    {
+      GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+      if (g_simple_async_result_propagate_error (simple, error))
+	return FALSE;
+    }
+  
+  iface = G_MOUNTABLE_VOLUME_GET_IFACE (mountable_volume);
+  return (* iface->mount_finish) (mountable_volume, result, error);
+}
+
+#define __G_MOUNTABLE_VOLUME_C__
+#include "gioaliasdef.c"
--- /dev/null	2007-12-10 22:43:26.582095961 -0500
+++ gunixmountablevolume.h	2007-12-10 18:10:27.000000000 -0500
@@ -0,0 +1,59 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#ifndef __G_UNIX_MOUNTABLE_VOLUME_H__
+#define __G_UNIX_MOUNTABLE_VOLUME_H__
+
+#include <glib-object.h>
+#include <gio/gmountablevolume.h>
+#include <gio/gunixmounts.h>
+#include <gio/gunixvolumemonitor.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_UNIX_MOUNTABLE_VOLUME        (_g_unix_mountable_volume_get_type ())
+#define G_UNIX_MOUNTABLE_VOLUME(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_UNIX_MOUNTABLE_VOLUME, GUnixMountableVolume))
+#define G_UNIX_MOUNTABLE_VOLUME_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_UNIX_MOUNTABLE_VOLUME, GUnixMountableVolumeClass))
+#define G_IS_UNIX_MOUNTABLE_VOLUME(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_UNIX_MOUNTABLE_VOLUME))
+#define G_IS_UNIX_MOUNTABLE_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_UNIX_MOUNTABLE_VOLUME))
+
+typedef struct _GUnixMountableVolumeClass GUnixMountableVolumeClass;
+
+struct _GUnixMountableVolumeClass {
+   GObjectClass parent_class;
+};
+
+GType _g_unix_mountable_volume_get_type (void) G_GNUC_CONST;
+
+GUnixMountableVolume *_g_unix_mountable_volume_new  (GVolumeMonitor        *volume_monitor,
+                                                     GUnixMountPoint       *mountpoint);
+gboolean    _g_unix_mountable_volume_has_mount_path (GUnixMountableVolume  *mountable_volume,
+                                                     const char            *mount_path);
+void        _g_unix_mountable_volume_set_volume     (GUnixMountableVolume  *mountable_volume,
+                                                     GUnixVolume           *volume);
+void        _g_unix_mountable_volume_unset_volume   (GUnixMountableVolume  *mountable_volume,
+                                                     GUnixVolume           *volume);
+void        _g_unix_mountable_volume_disconnected   (GUnixMountableVolume  *mountable_volume);
+
+G_END_DECLS
+
+#endif /* __G_UNIX_MOUNTABLE_VOLUME_H__ */
--- /dev/null	2007-12-10 22:43:26.582095961 -0500
+++ gunixmountablevolume.c	2007-12-10 18:10:45.000000000 -0500
@@ -0,0 +1,363 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include "gunixmountablevolume.h"
+#include "gunixvolume.h"
+#include "gthemedicon.h"
+#include "gvolumemonitor.h"
+#include "gsimpleasyncresult.h"
+#include "glibintl.h"
+
+#include "gioalias.h"
+
+struct _GUnixMountableVolume {
+  GObject parent;
+
+  GVolumeMonitor *volume_monitor;
+  GUnixVolume    *volume; /* owned by volume monitor */
+  char *device_path;
+  char *mount_path;
+  char *name;
+  char *icon;
+};
+
+static void g_unix_volume_mountable_mountable_volume_iface_init (GMountableVolumeIface *iface);
+
+#define g_unix_mountable_volume_get_type _g_unix_mountable_volume_get_type
+G_DEFINE_TYPE_WITH_CODE (GUnixMountableVolume, g_unix_mountable_volume, G_TYPE_OBJECT,
+			 G_IMPLEMENT_INTERFACE (G_TYPE_MOUNTABLE_VOLUME,
+						g_unix_volume_mountable_mountable_volume_iface_init))
+
+static void
+g_unix_mountable_volume_finalize (GObject *object)
+{
+  GUnixMountableVolume *mountable_volume;
+  
+  mountable_volume = G_UNIX_MOUNTABLE_VOLUME (object);
+
+  if (mountable_volume->volume_monitor != NULL)
+    g_object_unref (mountable_volume->volume_monitor);
+
+  if (mountable_volume->volume)
+    _g_unix_volume_unset_mountable_volume (mountable_volume->volume, mountable_volume);
+  
+  g_free (mountable_volume->name);
+  g_free (mountable_volume->icon);
+  g_free (mountable_volume->mount_path);
+  g_free (mountable_volume->device_path);
+
+  if (G_OBJECT_CLASS (g_unix_mountable_volume_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_unix_mountable_volume_parent_class)->finalize) (object);
+}
+
+static void
+g_unix_mountable_volume_class_init (GUnixMountableVolumeClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = g_unix_mountable_volume_finalize;
+}
+
+static void
+g_unix_mountable_volume_init (GUnixMountableVolume *unix_mountable_volume)
+{
+}
+
+/**
+ * g_unix_mountable_volume_new:
+ * @volume_monitor: a #GVolumeMonitor.
+ * @mountpoint: a #GUnixMountPoint.
+ * 
+ * Returns: a #GUnixMountableVolume for the given #GUnixMountPoint.
+ **/
+GUnixMountableVolume *
+_g_unix_mountable_volume_new (GVolumeMonitor  *volume_monitor,
+                              GUnixMountPoint *mountpoint)
+{
+  GUnixMountableVolume *mountable_volume;
+  
+  if (!(g_unix_mount_point_is_user_mountable (mountpoint) ||
+	g_str_has_prefix (g_unix_mount_point_get_device_path (mountpoint), "/vol/")) ||
+      g_unix_mount_point_is_loopback (mountpoint))
+    return NULL;
+  
+  mountable_volume = g_object_new (G_TYPE_UNIX_MOUNTABLE_VOLUME, NULL);
+  mountable_volume->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL;
+  mountable_volume->mount_path = g_strdup (g_unix_mount_point_get_mount_path (mountpoint));
+  mountable_volume->device_path = g_strdup (g_unix_mount_point_get_device_path (mountpoint));
+
+  mountable_volume->name = g_unix_mount_point_guess_name (mountpoint);
+  mountable_volume->icon = g_unix_mount_point_guess_icon_name (mountpoint);
+  return mountable_volume;
+}
+
+/**
+ * g_unix_mountable_volume_disconnected:
+ * @mountable_volume:
+ * 
+ **/
+void
+_g_unix_mountable_volume_disconnected (GUnixMountableVolume *mountable_volume)
+{
+  if (mountable_volume->volume)
+    {
+      _g_unix_volume_unset_mountable_volume (mountable_volume->volume, mountable_volume);
+      mountable_volume->volume = NULL;
+    }
+}
+
+/**
+ * g_unix_mountable_volume_set_volume:
+ * @mountable_volume:
+ * @volume:
+ *  
+ **/
+void
+_g_unix_mountable_volume_set_volume (GUnixMountableVolume  *mountable_volume,
+                                     GUnixVolume *volume)
+{
+  if (mountable_volume->volume == volume)
+    return;
+  
+  if (mountable_volume->volume)
+    _g_unix_volume_unset_mountable_volume (mountable_volume->volume, mountable_volume);
+  
+  mountable_volume->volume = volume;
+  
+  /* TODO: Emit changed in idle to avoid locking issues */
+  g_signal_emit_by_name (mountable_volume, "changed");
+  if (mountable_volume->volume_monitor != NULL)
+    g_signal_emit_by_name (mountable_volume->volume_monitor, "mountable_volume_changed", mountable_volume);
+}
+
+/**
+ * g_unix_mountable_volume_unset_volume:
+ * @mountable_volume:
+ * @volume:
+ *
+ **/
+void
+_g_unix_mountable_volume_unset_volume (GUnixMountableVolume  *mountable_volume,
+                                       GUnixVolume *volume)
+{
+  if (mountable_volume->volume == volume)
+    {
+      mountable_volume->volume = NULL;
+      /* TODO: Emit changed in idle to avoid locking issues */
+      g_signal_emit_by_name (mountable_volume, "changed");
+      if (mountable_volume->volume_monitor != NULL)
+        g_signal_emit_by_name (mountable_volume->volume_monitor, "mountable_volume_changed", mountable_volume);
+    }
+}
+
+static GIcon *
+g_unix_mountable_volume_get_icon (GMountableVolume *mountable_volume)
+{
+  GUnixMountableVolume *unix_mountable_volume = G_UNIX_MOUNTABLE_VOLUME (mountable_volume);
+  return g_themed_icon_new (unix_mountable_volume->icon);
+}
+
+static char *
+g_unix_mountable_volume_get_name (GMountableVolume *mountable_volume)
+{
+  GUnixMountableVolume *unix_mountable_volume = G_UNIX_MOUNTABLE_VOLUME (mountable_volume);
+  return g_strdup (unix_mountable_volume->name);
+}
+
+static gboolean
+g_unix_mountable_volume_can_mount (GMountableVolume *mountable_volume)
+{
+  return TRUE;
+}
+
+static GDrive *
+g_unix_mountable_volume_get_drive (GMountableVolume *mountable_volume)
+{
+  /* TODO */
+  return NULL;
+}
+
+static GVolume *
+g_unix_mountable_volume_get_volume (GMountableVolume *mountable_volume)
+{
+  GUnixMountableVolume *unix_mountable_volume = G_UNIX_MOUNTABLE_VOLUME (mountable_volume);
+
+  if (unix_mountable_volume->volume != NULL)
+    return g_object_ref (unix_mountable_volume->volume);
+
+  return NULL;
+}
+
+
+gboolean
+_g_unix_mountable_volume_has_mount_path (GUnixMountableVolume *mountable_volume,
+                                         const char  *mount_path)
+{
+  return strcmp (mountable_volume->mount_path, mount_path) == 0;
+}
+
+
+typedef struct {
+  GUnixMountableVolume *unix_mountable_volume;
+  GAsyncReadyCallback callback;
+  gpointer user_data;
+  GCancellable *cancellable;
+  int error_fd;
+  GIOChannel *error_channel;
+  guint error_channel_source_id;
+  GString *error_string;
+} MountOp;
+
+static void 
+mount_cb (GPid pid, gint status, gpointer user_data)
+{
+  MountOp *data = user_data;
+  GSimpleAsyncResult *simple;
+  
+  if (WEXITSTATUS (status) != 0)
+    {
+      GError *error;
+      error = g_error_new_literal (G_IO_ERROR, 
+                                   G_IO_ERROR_FAILED,
+                                   data->error_string->str);
+      simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_mountable_volume),
+                                                     data->callback,
+                                                     data->user_data,
+                                                     error);
+      g_error_free (error);
+    }
+  else
+    {
+      simple = g_simple_async_result_new (G_OBJECT (data->unix_mountable_volume),
+                                          data->callback,
+                                          data->user_data,
+                                          NULL);
+    }
+
+  g_simple_async_result_complete (simple);
+  g_object_unref (simple);
+
+  g_source_remove (data->error_channel_source_id);
+  g_io_channel_unref (data->error_channel);
+  g_string_free (data->error_string, TRUE);
+  close (data->error_fd);
+  g_spawn_close_pid (pid);
+  g_free (data);
+}
+
+static gboolean
+mount_read_error (GIOChannel *channel,
+                  GIOCondition condition,
+                  gpointer user_data)
+{
+  char *str;
+  gsize str_len;
+  MountOp *data = user_data;
+
+  g_io_channel_read_to_end (channel, &str, &str_len, NULL);
+  g_string_append (data->error_string, str);
+  g_free (str);
+  return TRUE;
+}
+
+static void
+g_unix_mountable_volume_mount (GMountableVolume    *mountable_volume,
+                               GMountOperation     *mount_operation,
+                               GCancellable        *cancellable,
+                               GAsyncReadyCallback  callback,
+                               gpointer             user_data)
+{
+  GUnixMountableVolume *unix_mountable_volume = G_UNIX_MOUNTABLE_VOLUME (mountable_volume);
+  MountOp *data;
+  GPid child_pid;
+  GError *error;
+  char *argv[] = {"mount", NULL, NULL};
+
+  if (unix_mountable_volume->mount_path != NULL)
+    argv[1] = unix_mountable_volume->mount_path;
+  else
+    argv[1] = unix_mountable_volume->device_path;
+  
+  data = g_new0 (MountOp, 1);
+  data->unix_mountable_volume = unix_mountable_volume;
+  data->callback = callback;
+  data->user_data = user_data;
+  data->cancellable = cancellable;
+  
+  error = NULL;
+  if (!g_spawn_async_with_pipes (NULL,         /* working dir */
+                                 argv,
+                                 NULL,         /* envp */
+                                 G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH,
+                                 NULL,         /* child_setup */
+                                 NULL,         /* user_data for child_setup */
+                                 &child_pid,
+                                 NULL,           /* standard_input */
+                                 NULL,           /* standard_output */
+                                 &(data->error_fd),
+                                 &error)) {
+    GSimpleAsyncResult *simple;
+    simple = g_simple_async_result_new_from_error (G_OBJECT (data->unix_mountable_volume),
+                                                   data->callback,
+                                                   data->user_data,
+                                                   error);
+    g_simple_async_result_complete (simple);
+    g_object_unref (simple);
+    g_error_free (error);
+    g_free (data);
+    return;
+  }
+  data->error_string = g_string_new ("");
+  data->error_channel = g_io_channel_unix_new (data->error_fd);
+  data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, mount_read_error, data);
+  g_child_watch_add (child_pid, mount_cb, data);
+}
+
+
+static gboolean
+g_unix_mountable_volume_mount_finish (GMountableVolume        *mountable_volume,
+                           GAsyncResult  *result,
+                           GError       **error)
+{
+  return TRUE;
+}
+
+static void
+g_unix_volume_mountable_mountable_volume_iface_init (GMountableVolumeIface *iface)
+{
+  iface->get_name = g_unix_mountable_volume_get_name;
+  iface->get_icon = g_unix_mountable_volume_get_icon;
+  iface->get_drive = g_unix_mountable_volume_get_drive;
+  iface->get_volume = g_unix_mountable_volume_get_volume;
+  iface->can_mount = g_unix_mountable_volume_can_mount;
+  iface->mount_fn = g_unix_mountable_volume_mount;
+  iface->mount_finish = g_unix_mountable_volume_mount_finish;
+}
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 1036)
+++ ChangeLog	(working copy)
@@ -1,3 +1,12 @@
+2007-12-11  David Zeuthen  <davidz redhat com>
+
+	Update for API changes in gio trunk.
+
+	* client/gdaemonvolume.c: (g_daemon_volume_get_mountable_volume),
+	(g_daemon_volume_volume_iface_init):
+	* client/gdaemonvolumemonitor.c: (get_mountable_volumes),
+	(g_daemon_volume_monitor_class_init):
+
 2007-12-05  Alexander Larsson  <alexl redhat com>
 
         * client/gdaemonvfs.c:
Index: client/gdaemonvolume.c
===================================================================
--- client/gdaemonvolume.c	(revision 1036)
+++ client/gdaemonvolume.c	(working copy)
@@ -114,6 +114,12 @@
   return g_strdup (daemon_volume->mount_info->display_name);
 }
 
+static GMountableVolume *
+g_daemon_volume_get_mountable_volume (GVolume *volume)
+{
+  return NULL;
+}
+
 static GDrive *
 g_daemon_volume_get_drive (GVolume *volume)
 {
@@ -126,12 +132,6 @@
   return TRUE;
 }
 
-static gboolean
-g_daemon_volume_can_eject (GVolume *volume)
-{
-  return FALSE;
-}
-
 static void
 unmount_reply (DBusMessage *reply,
 	       DBusConnection *connection,
@@ -192,9 +192,9 @@
   iface->get_root = g_daemon_volume_get_root;
   iface->get_name = g_daemon_volume_get_name;
   iface->get_icon = g_daemon_volume_get_icon;
+  iface->get_mountable_volume = g_daemon_volume_get_mountable_volume;
   iface->get_drive = g_daemon_volume_get_drive;
   iface->can_unmount = g_daemon_volume_can_unmount;
-  iface->can_eject = g_daemon_volume_can_eject;
   iface->unmount = g_daemon_volume_unmount;
   iface->unmount_finish = g_daemon_volume_unmount_finish;
 }
Index: client/gdaemonvolumemonitor.c
===================================================================
--- client/gdaemonvolumemonitor.c	(revision 1036)
+++ client/gdaemonvolumemonitor.c	(working copy)
@@ -54,6 +54,13 @@
 }
 
 static GList *
+get_mountable_volumes (GVolumeMonitor *volume_monitor)
+{
+  /* TODO: Can daemon mounts have mountable volumes? */
+  return NULL;
+}
+
+static GList *
 get_connected_drives (GVolumeMonitor *volume_monitor)
 {
   /* TODO: Can daemon mounts have drives? */
@@ -184,6 +191,7 @@
   gobject_class->finalize = g_daemon_volume_monitor_finalize;
 
   monitor_class->get_mounted_volumes = get_mounted_volumes;
+  monitor_class->get_mountable_volumes = get_mountable_volumes;
   monitor_class->get_connected_drives = get_connected_drives;
 }
 
Index: src/file-manager/fm-tree-view.c
===================================================================
--- src/file-manager/fm-tree-view.c	(revision 13516)
+++ src/file-manager/fm-tree-view.c	(working copy)
@@ -745,8 +745,20 @@
 		
 		volume = fm_tree_model_get_volume_for_root_node_file (view->details->child_model, view->details->popup_file);
 		if (volume) {
-			show_unmount = g_volume_can_unmount (volume) || g_volume_can_eject (volume);
-			unmount_is_eject = g_volume_can_eject (volume);
+			GDrive *drive;
+			gboolean can_eject = FALSE;
+
+			drive = g_volume_get_drive (volume);
+			if (drive != NULL) {
+				can_eject = g_drive_can_eject (drive);
+				g_object_unref (drive);
+			}
+
+			show_unmount = g_volume_can_unmount (volume) || can_eject;
+			/* TODO: show both unmount and eject if there are more than one mountable
+			 * volume for the drive 
+			 */
+			unmount_is_eject = can_eject;
 		} 
 		
 		gtk_label_set_text (GTK_LABEL (GTK_BIN (GTK_MENU_ITEM (view->details->popup_unmount))->child),
@@ -1096,9 +1108,18 @@
 	volume = fm_tree_model_get_volume_for_root_node_file (view->details->child_model, file);
 	
 	if (volume != NULL) {
+		GDrive *drive;
+		gboolean can_eject = FALSE;
+
+		drive = g_volume_get_drive (volume);
+		if (drive != NULL) {
+			can_eject = g_drive_can_eject (drive);
+			g_object_unref (drive);
+		}
+
 		nautilus_file_operations_unmount_volume (fm_tree_view_get_containing_window (view),
 							 volume,
-							 g_volume_can_eject (volume));
+							 can_eject);
 	}
 }
 
Index: src/nautilus-places-sidebar.c
===================================================================
--- src/nautilus-places-sidebar.c	(revision 13516)
+++ src/nautilus-places-sidebar.c	(working copy)
@@ -88,6 +88,7 @@
 	GtkWidget *popup_menu_mount_item;
 	GtkWidget *popup_menu_unmount_item;
 	GtkWidget *popup_menu_eject_item;
+	GtkWidget *popup_menu_rescan_item;
 	GtkWidget *popup_menu_format_item;
 	GtkWidget *popup_menu_empty_trash_item;
 } NautilusPlacesSidebar;
@@ -108,6 +109,7 @@
 	PLACES_SIDEBAR_COLUMN_ROW_TYPE,
 	PLACES_SIDEBAR_COLUMN_URI,
 	PLACES_SIDEBAR_COLUMN_DRIVE,
+	PLACES_SIDEBAR_COLUMN_MOUNTABLE_VOLUME,
 	PLACES_SIDEBAR_COLUMN_VOLUME,
 	PLACES_SIDEBAR_COLUMN_NAME,
 	PLACES_SIDEBAR_COLUMN_ICON,
@@ -185,7 +187,6 @@
 			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR_PROVIDER,
 						sidebar_provider_iface_init));
 
-
 static GtkTreeIter
 add_place (NautilusPlacesSidebar *sidebar,
 	   PlaceType place_type,
@@ -193,6 +194,7 @@
 	   GIcon *icon,
 	   const char *uri,
 	   GDrive *drive,
+	   GMountableVolume *mountable_volume,
 	   GVolume *volume,
 	   const int index)
 {
@@ -212,6 +214,7 @@
 			    PLACES_SIDEBAR_COLUMN_NAME, name,
 			    PLACES_SIDEBAR_COLUMN_URI, uri,
 			    PLACES_SIDEBAR_COLUMN_DRIVE, drive,
+			    PLACES_SIDEBAR_COLUMN_MOUNTABLE_VOLUME, mountable_volume,
 			    PLACES_SIDEBAR_COLUMN_VOLUME, volume,
 			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, place_type,
 			    PLACES_SIDEBAR_COLUMN_INDEX, index,
@@ -237,6 +240,8 @@
 	GVolume *volume;
 	GList *drives;
 	GDrive *drive;
+	GList *mountable_volumes;
+	GMountableVolume *mountable_volume;
 	int bookmark_count, index;
 	char *location, *mount_uri, *name, *desktop_path;
 	GIcon *icon;
@@ -258,7 +263,7 @@
 		icon = g_themed_icon_new ("gnome-fs-home");
 		last_iter = add_place (sidebar, PLACES_BUILT_IN,
 				       display_name, icon,
-				       mount_uri, NULL, NULL, 0);
+				       mount_uri, NULL, NULL, NULL, 0);
 		g_object_unref (icon);
 		g_free (display_name);
 		if (strcmp (location, mount_uri) == 0) {
@@ -271,7 +276,7 @@
 	icon = g_themed_icon_new ("gnome-fs-desktop");
 	last_iter = add_place (sidebar, PLACES_BUILT_IN,
 			       _("Desktop"), icon,
-			       mount_uri, NULL, NULL, 0);
+			       mount_uri, NULL, NULL, NULL, 0);
 	g_object_unref (icon);
 	if (strcmp (location, mount_uri) == 0) {
 		gtk_tree_selection_select_iter (selection, &last_iter);
@@ -283,65 +288,131 @@
 	icon = g_themed_icon_new ("gnome-dev-harddisk");
 	last_iter = add_place (sidebar, PLACES_BUILT_IN,
 			       _("File System"), icon,
-			       mount_uri, NULL, NULL, 0);
+			       mount_uri, NULL, NULL, NULL, 0);
 	g_object_unref (icon);
 	if (strcmp (location, mount_uri) == 0) {
 		gtk_tree_selection_select_iter (selection, &last_iter);
 	}
 
-	/* for all drives add all its volumes */
+	volume_monitor = sidebar->volume_monitor;
 
-	volume_monitor = sidebar->volume_monitor;
+	/* first go through all connected drives */
 	drives = g_volume_monitor_get_connected_drives (volume_monitor);
 	for (l = drives; l != NULL; l = l->next) {
 		drive = l->data;
-		if (g_drive_has_volumes (drive)) {
-			/* The drive is mounted, add all its volumes */
-			volumes = g_drive_get_volumes (drive);
-			for (ll = volumes; ll != NULL; ll = ll->next) {
-				volume = ll->data;
-				icon = g_volume_get_icon (volume);
 
-				root = g_volume_get_root (volume);
-				mount_uri = g_file_get_uri (root);
-				g_object_unref (root);
-				name = g_volume_get_name (volume);
-				last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
-						       name, icon, mount_uri,
-						       drive, volume, 0);
-				if (strcmp (location, mount_uri) == 0) {
-					gtk_tree_selection_select_iter (selection, &last_iter);
+		mountable_volumes = g_drive_get_mountable_volumes (drive);
+		if (mountable_volumes != NULL) {
+			for (ll = mountable_volumes; ll != NULL; ll = ll->next) {
+				mountable_volume = ll->data;
+				volume = g_mountable_volume_get_volume (mountable_volume);
+				if (volume != NULL) {
+					/* Show mounted volume in the sidebar */
+					icon = g_volume_get_icon (volume);
+					root = g_volume_get_root (volume);
+					mount_uri = g_file_get_uri (root);
+					g_object_unref (root);
+					name = g_volume_get_name (volume);
+					last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
+							       name, icon, mount_uri,
+							       drive, mountable_volume, volume, 0);
+					if (strcmp (location, mount_uri) == 0) {
+						gtk_tree_selection_select_iter (selection, &last_iter);
+					}
+					g_object_unref (volume);
+					g_object_unref (icon);
+					g_free (name);
+					g_free (mount_uri);
+				} else {
+					/* Do show the unmounted mountable volume in the sidebar;
+					 * this is so the user can mount it (in case automounting
+					 * is off).
+					 *
+					 * Also, even if automounting is enabled, this gives a visual
+					 * cue that the user should remember to yank out the media if
+					 * he just unmounted it.
+					 */
+					icon = g_mountable_volume_get_icon (mountable_volume);
+					name = g_mountable_volume_get_name (mountable_volume);
+					last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
+							       name, icon, NULL,
+							       drive, mountable_volume, NULL, 0);
+					g_object_unref (icon);
+					g_free (name);
 				}
-				g_object_unref (volume);
+				g_object_unref (mountable_volume);
+			}
+		} else {
+			if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive)) {
+				/* If the drive has no mountable volumes and we cannot detect media change.. we
+				 * display the drive in the sidebar so the user can manually poll the drive by
+				 * right clicking and selecting "Rescan..."
+				 *
+				 * This is mainly for drives like floppies where media detection doesn't
+				 * work.. but it's also for human beings who like to turn off media detection
+				 * in the OS to save battery juice.
+				 */
+				icon = g_drive_get_icon (drive);
+				name = g_drive_get_name (drive);
+				last_iter = add_place (sidebar, PLACES_BUILT_IN,
+						       name, icon, NULL,
+						       drive, NULL, NULL, 0);
 				g_object_unref (icon);
 				g_free (name);
-				g_free (mount_uri);
 			}
-			g_list_free (volumes);
+		}
+		g_object_unref (drive);
+	}
+	g_list_free (drives);
+
+	/* add all mountable volumes that is not associated with a drive */
+	mountable_volumes = g_volume_monitor_get_mountable_volumes (volume_monitor);
+	for (l = mountable_volumes; l != NULL; l = l->next) {
+		mountable_volume = l->data;
+		drive = g_mountable_volume_get_drive (mountable_volume);
+		if (drive != NULL) {
+		    	g_object_unref (mountable_volume);
+			g_object_unref (drive);
+			continue;
+		}
+		volume = g_mountable_volume_get_volume (mountable_volume);
+		if (volume != NULL) {
+			icon = g_volume_get_icon (volume);
+			root = g_volume_get_root (volume);
+			mount_uri = g_file_get_uri (root);
+			g_object_unref (root);
+			name = g_volume_get_name (volume);
+			last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
+					       name, icon, mount_uri,
+					       NULL, mountable_volume, volume, 0);
+			if (strcmp (location, mount_uri) == 0) {
+				gtk_tree_selection_select_iter (selection, &last_iter);
+			}
+			g_object_unref (volume);
+			g_object_unref (icon);
+			g_free (name);
+			g_free (mount_uri);
 		} else {
-			/* The drive is unmounted but visible, add it.
-			 * This is for drives like floppy that can't be
-			 * auto-mounted */
-			icon = g_drive_get_icon (drive);
-			name = g_drive_get_name (drive);
-			last_iter = add_place (sidebar, PLACES_BUILT_IN,
+			/* see comment above in why we add an icon for an unmounted mountable volume */
+			icon = g_mountable_volume_get_icon (mountable_volume);
+			name = g_mountable_volume_get_name (mountable_volume);
+			last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
 					       name, icon, NULL,
-					       drive, NULL, 0);
+					       NULL, mountable_volume, NULL, 0);
 			g_object_unref (icon);
 			g_free (name);
-		}		
-		g_object_unref (drive);
+		}
+		g_object_unref (mountable_volume);
 	}
-	g_list_free (drives);
+	g_list_free (mountable_volumes);
 
-	/* add mounted volumes that has no drive (ftp, sftp,...) */
-
+	/* add mounted volumes that has no mountable volume (/etc/mtab volumes, ftp, sftp,...) */
 	volumes = g_volume_monitor_get_mounted_volumes (volume_monitor);
 	for (l = volumes; l != NULL; l = l->next) {
 		volume = l->data;
-		drive = g_volume_get_drive (volume);
-		if (drive != NULL) {
-		    	g_object_unref (drive);
+		mountable_volume = g_volume_get_mountable_volume (volume);
+		if (mountable_volume != NULL) {
+		    	g_object_unref (mountable_volume);
 			g_object_unref (volume);
 			continue;
 		}
@@ -352,7 +423,7 @@
 		name = g_volume_get_name (volume);
 		last_iter = add_place (sidebar, PLACES_MOUNTED_VOLUME,
 				       name, icon, mount_uri,
-				       NULL, volume, 0);
+				       NULL, NULL, volume, 0);
 		if (strcmp (location, mount_uri) == 0) {
 			gtk_tree_selection_select_iter (selection, &last_iter);
 		}
@@ -367,7 +438,7 @@
 	icon = nautilus_trash_monitor_get_icon ();
 	last_iter = add_place (sidebar, PLACES_BUILT_IN,
 			       _("Trash"), icon, mount_uri,
-			       NULL, NULL, 0);
+			       NULL, NULL, NULL, 0);
 	if (strcmp (location, mount_uri) == 0) {
 		gtk_tree_selection_select_iter (selection, &last_iter);
 	}
@@ -395,7 +466,7 @@
 		mount_uri = nautilus_bookmark_get_uri (bookmark);
 		last_iter = add_place (sidebar, PLACES_BOOKMARK,
 				       name, icon, mount_uri,
-				       NULL, NULL, index);
+				       NULL, NULL, NULL, index);
 		if (strcmp (location, mount_uri) == 0) {
 			gtk_tree_selection_select_iter (selection, &last_iter);
 		}
@@ -407,13 +478,6 @@
 }
 
 static gboolean
-update_places_cb (gpointer data)
-{
-	update_places (NAUTILUS_PLACES_SIDEBAR (data));
-	return FALSE;
-}
-
-static gboolean
 nautilus_shortcuts_row_separator_func (GtkTreeModel *model,
 				       GtkTreeIter  *iter,
 				       gpointer      data)
@@ -429,7 +493,6 @@
   	return FALSE;
 }
 
-
 static void
 volume_mounted_callback (GVolumeMonitor *volume_monitor,
 			 GVolume *volume,
@@ -443,14 +506,42 @@
 			   GVolume *volume,
 			   NautilusPlacesSidebar *sidebar)
 {
-	/* At this point the volume still appears to be mounted.
-	 * GnomeVFS will update its list after the signal finished
-	 * to emit, so we delay the update.
-	 */
-	g_idle_add (update_places_cb, sidebar);
+	update_places (sidebar);
 }
 
 static void
+volume_changed_callback (GVolumeMonitor *volume_monitor,
+			 GVolume *volume,
+			 NautilusPlacesSidebar *sidebar)
+{
+	update_places (sidebar);
+}
+
+static void
+mountable_volume_added_callback (GVolumeMonitor *volume_monitor,
+				 GMountableVolume *mountable_volume,
+				 NautilusPlacesSidebar *sidebar)
+{
+	update_places (sidebar);
+}
+
+static void
+mountable_volume_removed_callback (GVolumeMonitor *volume_monitor,
+				   GMountableVolume *mountable_volume,
+				   NautilusPlacesSidebar *sidebar)
+{
+	update_places (sidebar);
+}
+
+static void
+mountable_volume_changed_callback (GVolumeMonitor *volume_monitor,
+				   GMountableVolume *mountable_volume,
+				   NautilusPlacesSidebar *sidebar)
+{
+	update_places (sidebar);
+}
+
+static void
 drive_disconnected_callback (GVolumeMonitor *volume_monitor,
 			     GDrive         *drive,
 			     NautilusPlacesSidebar *sidebar)
@@ -467,6 +558,14 @@
 }
 
 static void
+drive_changed_callback (GVolumeMonitor *volume_monitor,
+			GDrive         *drive,
+			NautilusPlacesSidebar *sidebar)
+{
+	update_places (sidebar);
+}
+
+static void
 row_activated_callback (GtkTreeView *tree_view,
 			GtkTreePath *path,
 			GtkTreeViewColumn *column,
@@ -1053,42 +1152,50 @@
 	sidebar->popup_menu_mount_item = NULL;
 	sidebar->popup_menu_unmount_item = NULL;
 	sidebar->popup_menu_eject_item = NULL;
+	sidebar->popup_menu_rescan_item = NULL;
 	sidebar->popup_menu_format_item = NULL;
 	sidebar->popup_menu_empty_trash_item = NULL;
 }
 
 static void
-check_visibility (GVolume *volume,
-		  GDrive  *drive,
-		  gboolean       *show_mount,
-		  gboolean       *show_unmount,
-		  gboolean       *show_eject,
-		  gboolean       *show_format)
+check_visibility (GVolume          *volume,
+		  GMountableVolume *mountable_volume,
+		  GDrive           *drive,
+		  gboolean         *show_mount,
+		  gboolean         *show_unmount,
+		  gboolean         *show_eject,
+		  gboolean         *show_rescan,
+		  gboolean         *show_format)
 {
 	*show_mount = FALSE;
 	*show_unmount = FALSE;
 	*show_eject = FALSE;
 	*show_format = FALSE;
+	*show_rescan = FALSE;
 
+	if (drive != NULL) {
+		*show_eject = g_drive_can_eject (drive);
+
+		if (g_drive_is_media_removable (drive) &&
+		    !g_drive_is_media_check_automatic (drive) && 
+		    g_drive_can_poll_for_media (drive))
+			*show_rescan = TRUE;
+	}
+
+	if (mountable_volume != NULL && volume == NULL) {
+		*show_mount = g_mountable_volume_can_mount (mountable_volume);
+	}
+
 	if (volume != NULL) {
 		*show_unmount = g_volume_can_unmount (volume);
-		*show_eject = g_volume_can_eject (volume);
-	} else if (drive != NULL) {
-		*show_eject = g_drive_can_eject (drive);
-		if (g_drive_has_volumes (drive)) {
-			*show_unmount = TRUE;
-		} else {
-			*show_mount = TRUE;
-		}
+	}
 
 #ifdef TODO_GIO
 		if (something &&
 		    g_find_program_in_path ("gfloppy")) {
 			*show_format = TRUE;
 		}
-#endif
-		
-	}
+#endif		
 }
 
 static void
@@ -1097,10 +1204,12 @@
 	GtkTreeIter iter;
 	PlaceType type; 
 	GDrive *drive = NULL;
+	GMountableVolume *mountable_volume = NULL;
 	GVolume *volume = NULL;
 	gboolean show_mount;
 	gboolean show_unmount;
 	gboolean show_eject;
+	gboolean show_rescan;
 	gboolean show_format;
 	gboolean show_empty_trash;
 	char *uri = NULL;
@@ -1115,6 +1224,7 @@
 		gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
 				    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
 				    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+				    PLACES_SIDEBAR_COLUMN_MOUNTABLE_VOLUME, &mountable_volume,
  				    PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
 				    PLACES_SIDEBAR_COLUMN_URI, &uri,
 				    -1);
@@ -1124,14 +1234,12 @@
 	gtk_widget_set_sensitive (sidebar->popup_menu_rename_item, (type == PLACES_BOOKMARK));
 	gtk_widget_set_sensitive (sidebar->popup_menu_empty_trash_item, !nautilus_trash_monitor_is_empty ());
 
- 	check_visibility (volume, drive,
- 			  &show_mount, &show_unmount, &show_eject, &show_format);	
+ 	check_visibility (volume, mountable_volume, drive,
+ 			  &show_mount, &show_unmount, &show_eject, &show_rescan, &show_format);
 
-	/* We don't want both eject and unmount, since eject
- 	   unmounts too */
- 	if (show_eject) {
- 		show_unmount = FALSE;
-  	}
+	/* We actually want both eject and unmount since eject will unmount all volumes. 
+	 * TODO: hide unmount if the drive only has a single mountable volume 
+	 */
 
 	show_empty_trash = (uri != NULL) &&
 			   (!strcmp (uri, "trash:///"));
@@ -1141,6 +1249,7 @@
 	eel_gtk_widget_set_shown (sidebar->popup_menu_mount_item, show_mount);
 	eel_gtk_widget_set_shown (sidebar->popup_menu_unmount_item, show_unmount);
 	eel_gtk_widget_set_shown (sidebar->popup_menu_eject_item, show_eject);
+	eel_gtk_widget_set_shown (sidebar->popup_menu_rescan_item, show_rescan);
 	eel_gtk_widget_set_shown (sidebar->popup_menu_format_item, show_format);
 	eel_gtk_widget_set_shown (sidebar->popup_menu_empty_trash_item, show_empty_trash);
 
@@ -1156,18 +1265,17 @@
 }
 
 static void
-drive_mount_cb (GObject *source_object,
-		GAsyncResult *res,
-		gpointer user_data)
+mountable_volume_mount_cb (GObject *source_object,
+			   GAsyncResult *res,
+			   gpointer user_data)
 {
 	GError *error;
 	char *primary;
 	char *name;
 
 	error = NULL;
-	if (!g_drive_mount_finish (G_DRIVE (source_object),
-				   res, &error)) {
-		name = g_drive_get_name (G_DRIVE (source_object));
+	if (!g_mountable_volume_mount_finish (G_MOUNTABLE_VOLUME (source_object), res, &error)) {
+		name = g_mountable_volume_get_name (G_MOUNTABLE_VOLUME (source_object));
 		primary = g_strdup_printf (_("Unable to mount %s"), name);
 		g_free (name);
 		eel_show_error_dialog (primary,
@@ -1178,8 +1286,6 @@
 	}
 }
 
-
-
 static void
 open_selected_bookmark (NautilusPlacesSidebar *sidebar,
 			GtkTreeModel	      *model,
@@ -1223,11 +1329,11 @@
 		g_free (uri);
 
 	} else {
-		GDrive *drive;
-		gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_DRIVE, &drive, -1);
-		if (drive != NULL) {
-			g_drive_mount (drive, NULL, NULL, drive_mount_cb, NULL);
-			g_object_unref (drive);
+		GMountableVolume *mountable_volume;
+		gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_MOUNTABLE_VOLUME, &mountable_volume, -1);
+		if (mountable_volume != NULL) {
+			g_mountable_volume_mount (mountable_volume, NULL, NULL, mountable_volume_mount_cb, NULL);
+			g_object_unref (mountable_volume);
 		}
 	}
 }
@@ -1330,19 +1436,23 @@
 		   NautilusPlacesSidebar *sidebar)
 {
 	GtkTreeIter iter;
-	GDrive *drive;
+	GMountableVolume *mountable_volume;
 
 	if (!get_selected_iter (sidebar, &iter)) {
 		return;
 	}
 
 	gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
-			    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+			    PLACES_SIDEBAR_COLUMN_MOUNTABLE_VOLUME, &mountable_volume,
 			    -1);
 
-	if (drive != NULL) {
-		g_drive_mount (drive, NULL, NULL, drive_mount_cb, NULL);
-		g_object_unref (drive);
+	if (mountable_volume != NULL) {
+		GMountOperation *mount_op;
+
+		/* TODO: do we leak this? */
+		mount_op = g_mount_operation_new ();
+		g_mountable_volume_mount (mountable_volume, mount_op, NULL, mountable_volume_mount_cb, NULL);
+		g_object_unref (mountable_volume);
 	}
 }
 
@@ -1352,7 +1462,7 @@
 {
 	GtkTreeIter iter;
 	GVolume *volume;
-	GDrive *drive;
+	GMountableVolume *mountable_volume;
 
 	if (!get_selected_iter (sidebar, &iter)) {
 		return;
@@ -1360,7 +1470,7 @@
 
 	gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
 			    PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
-			    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+			    PLACES_SIDEBAR_COLUMN_MOUNTABLE_VOLUME, &mountable_volume,
 			    -1);
 
 	if (volume != NULL) {
@@ -1373,8 +1483,8 @@
 	if (volume != NULL) {
 		g_object_unref (volume);
 	}
-	if (drive != NULL) {
-		g_object_unref (drive);
+	if (mountable_volume != NULL) {
+		g_object_unref (mountable_volume);
 	}
 }
 
@@ -1407,7 +1517,8 @@
 {
 	GtkTreeIter iter;
 	GVolume *volume;
-	GDrive  *drive;
+	GMountableVolume *mountable_volume;
+	GDrive *drive;
 
 	if (!get_selected_iter (sidebar, &iter)) {
 		return;
@@ -1415,6 +1526,7 @@
 
 	gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
 			    PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
+			    PLACES_SIDEBAR_COLUMN_MOUNTABLE_VOLUME, &mountable_volume,
 			    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
 			    -1);
 
@@ -1429,10 +1541,54 @@
 		g_drive_eject (drive, NULL, drive_eject_cb, NULL);
 	}
 	g_object_unref (volume);
+	g_object_unref (mountable_volume);
 	g_object_unref (drive);
 }
 
 static void
+drive_poll_for_media_cb (GObject *source_object,
+			 GAsyncResult *res,
+			 gpointer user_data)
+{
+	GError *error;
+	char *primary;
+	char *name;
+
+	error = NULL;
+	if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+		name = g_drive_get_name (G_DRIVE (source_object));
+		primary = g_strdup_printf (_("Unable to poll %s for media changes"), name);
+		g_free (name);
+		eel_show_error_dialog (primary,
+				       error->message,
+				       NULL);
+		g_free (primary);
+		g_error_free (error);
+	}
+}
+
+static void
+rescan_shortcut_cb (GtkMenuItem           *item,
+		    NautilusPlacesSidebar *sidebar)
+{
+	GtkTreeIter iter;
+	GDrive  *drive;
+
+	if (!get_selected_iter (sidebar, &iter)) {
+		return;
+	}
+
+	gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+			    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+			    -1);
+
+	if (drive != NULL) {
+		g_drive_poll_for_media (drive, NULL, drive_poll_for_media_cb, NULL);
+	}
+	g_object_unref (drive);
+}
+
+static void
 format_shortcut_cb (GtkMenuItem           *item,
 		    NautilusPlacesSidebar *sidebar)
 {
@@ -1544,6 +1700,13 @@
 	gtk_widget_show (item);
 	gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
 
+	item = gtk_menu_item_new_with_mnemonic (_("_Rescan"));
+	sidebar->popup_menu_rescan_item = item;
+	g_signal_connect (item, "activate",
+		    G_CALLBACK (rescan_shortcut_cb), sidebar);
+	gtk_widget_show (item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
 	item = gtk_menu_item_new_with_mnemonic (_("_Format"));
 	sidebar->popup_menu_format_item = item;
 	g_signal_connect (item, "activate",
@@ -1704,6 +1867,7 @@
 					     G_TYPE_INT, 
 					     G_TYPE_STRING,
 					     G_TYPE_DRIVE,
+					     G_TYPE_MOUNTABLE_VOLUME,
 					     G_TYPE_VOLUME,
 					     G_TYPE_STRING,
 					     GDK_TYPE_PIXBUF,
@@ -1866,14 +2030,24 @@
 				 G_CALLBACK (loading_uri_callback),
 				 sidebar, 0);
 			 
+	g_signal_connect_object (sidebar->volume_monitor, "mountable_volume_added",
+				 G_CALLBACK (mountable_volume_added_callback), sidebar, 0);
+	g_signal_connect_object (sidebar->volume_monitor, "mountable_volume_removed",
+				 G_CALLBACK (mountable_volume_removed_callback), sidebar, 0);
+	g_signal_connect_object (sidebar->volume_monitor, "mountable_volume_changed",
+				 G_CALLBACK (mountable_volume_changed_callback), sidebar, 0);
 	g_signal_connect_object (sidebar->volume_monitor, "volume_mounted",
 				 G_CALLBACK (volume_mounted_callback), sidebar, 0);
 	g_signal_connect_object (sidebar->volume_monitor, "volume_unmounted",
 				 G_CALLBACK (volume_unmounted_callback), sidebar, 0);
+	g_signal_connect_object (sidebar->volume_monitor, "volume_changed",
+				 G_CALLBACK (volume_changed_callback), sidebar, 0);
 	g_signal_connect_object (sidebar->volume_monitor, "drive_disconnected",
 				 G_CALLBACK (drive_disconnected_callback), sidebar, 0);
 	g_signal_connect_object (sidebar->volume_monitor, "drive_connected",
 				 G_CALLBACK (drive_connected_callback), sidebar, 0);
+	g_signal_connect_object (sidebar->volume_monitor, "drive_changed",
+				 G_CALLBACK (drive_changed_callback), sidebar, 0);
 
 	update_places (sidebar);
 }
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 13516)
+++ ChangeLog	(working copy)
@@ -1,3 +1,31 @@
+2007-12-11  David Zeuthen  <davidz redhat com>
+
+	Update for API changes in gio trunk.
+
+	* libnautilus-private/nautilus-desktop-icon-file.c:
+	(update_info_from_link):
+	* libnautilus-private/nautilus-desktop-link-monitor.c:
+	(volume_delete_dialog), (volume_changed_callback),
+	(nautilus_desktop_link_monitor_init),
+	(desktop_link_monitor_finalize):
+	* libnautilus-private/nautilus-desktop-link.c:
+	(nautilus_desktop_link_new_from_volume):
+	* libnautilus-private/nautilus-file-operations.c: (do_unmount):
+	* src/file-manager/fm-tree-view.c: (button_pressed_callback),
+	(fm_tree_view_unmount_cb):
+	* src/nautilus-places-sidebar.c: (add_place), (update_places),
+	(volume_unmounted_callback), (volume_changed_callback),
+	(mountable_volume_added_callback),
+	(mountable_volume_removed_callback),
+	(mountable_volume_changed_callback), (drive_changed_callback),
+	(bookmarks_popup_menu_detach_cb), (check_visibility),
+	(bookmarks_check_popup_sensitivity), (mountable_volume_mount_cb),
+	(open_selected_bookmark), (mount_shortcut_cb),
+	(unmount_shortcut_cb), (eject_shortcut_cb),
+	(drive_poll_for_media_cb), (rescan_shortcut_cb),
+	(bookmarks_build_popup_menu), (nautilus_places_sidebar_init),
+	(nautilus_places_sidebar_set_parent_window):
+
 2007-12-10  Alexander Larsson  <alexl redhat com>
 
         * libnautilus-private/nautilus-directory-async.c:
Index: libnautilus-private/nautilus-desktop-link.c
===================================================================
--- libnautilus-private/nautilus-desktop-link.c	(revision 13516)
+++ libnautilus-private/nautilus-desktop-link.c	(working copy)
@@ -31,7 +31,7 @@
 #include <glib/gi18n.h>
 #include <gio/gthemedicon.h>
 #include <gio/gvolume.h>
-#include <gio/gdrive.h>
+#include <gio/gmountablevolume.h>
 #include <libnautilus-private/nautilus-file-utilities.h>
 #include <libnautilus-private/nautilus-trash-monitor.h>
 #include <libnautilus-private/nautilus-global-preferences.h>
@@ -214,7 +214,7 @@
 nautilus_desktop_link_new_from_volume (GVolume *volume)
 {
 	NautilusDesktopLink *link;
-	GDrive *drive;
+	GMountableVolume *mountable_volume;
 	char *name, *filename;
 
 	link = NAUTILUS_DESKTOP_LINK (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK, NULL));
@@ -225,10 +225,10 @@
 
 	/* We try to use the drive name to get somewhat stable filenames
 	   for metadata */
-	drive = g_volume_get_drive (volume);
-	if (drive != NULL) {
-		name = g_drive_get_name (drive);
-		g_object_unref (drive);
+	mountable_volume = g_volume_get_mountable_volume (volume);
+	if (mountable_volume != NULL) {
+		name = g_mountable_volume_get_name (mountable_volume);
+		g_object_unref (mountable_volume);
 	} else {
 		name = g_volume_get_name (volume);
 	}
Index: libnautilus-private/nautilus-desktop-icon-file.c
===================================================================
--- libnautilus-private/nautilus-desktop-icon-file.c	(revision 13516)
+++ libnautilus-private/nautilus-desktop-icon-file.c	(working copy)
@@ -35,6 +35,7 @@
 #include "nautilus-desktop-directory.h"
 #include <glib/gi18n.h>
 #include <string.h>
+#include <gio/gdrive.h>
 
 struct NautilusDesktopIconFileDetails {
 	NautilusDesktopLink *link;
@@ -184,8 +185,17 @@
 	file->details->can_eject = FALSE;
 	volume = nautilus_desktop_link_get_volume (link);
 	if (volume) {
+		GDrive *drive;
+		gboolean can_eject = FALSE;
+
+		drive = g_volume_get_drive (volume);
+		if (drive != NULL) {
+			can_eject = g_drive_can_eject (drive);
+			g_object_unref (drive);
+		}
+
 		file->details->can_unmount = g_volume_can_unmount (volume);
-		file->details->can_eject = g_volume_can_eject (volume);
+		file->details->can_eject = can_eject;
 		g_object_unref (volume);
 	}
 	
Index: libnautilus-private/nautilus-desktop-link-monitor.c
===================================================================
--- libnautilus-private/nautilus-desktop-link-monitor.c	(revision 13516)
+++ libnautilus-private/nautilus-desktop-link-monitor.c	(working copy)
@@ -54,6 +54,7 @@
 
 	gulong mount_id;
 	gulong unmount_id;
+	gulong changed_id;
 	
 	GList *volume_links;
 };
@@ -98,12 +99,21 @@
 	volume = nautilus_desktop_link_get_volume (link);
 
 	if (volume != NULL) {
+		GDrive *drive;
+		gboolean can_eject = FALSE;
+
+		drive = g_volume_get_drive (volume);
+		if (drive != NULL) {
+			can_eject = g_drive_can_eject (drive);
+			g_object_unref (drive);
+		}
+
 		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_volume_can_eject (volume)) {
+		if (can_eject) {
 			eel_run_simple_dialog
 				(parent_view, 
 				 FALSE,
@@ -235,6 +245,14 @@
 }
 
 static void
+volume_changed_callback (GVolumeMonitor *volume_monitor,
+			 GVolume *volume, 
+			 NautilusDesktopLinkMonitor *monitor)
+{
+	/* TODO: update the volume */
+}
+
+static void
 update_link_visibility (NautilusDesktopLinkMonitor *monitor,
 			NautilusDesktopLink       **link_ref,
 			NautilusDesktopLinkType     link_type,
@@ -406,6 +424,9 @@
 	monitor->details->unmount_id =
 		g_signal_connect_object (monitor->details->volume_monitor, "volume_unmounted",
 					 G_CALLBACK (volume_unmounted_callback), monitor, 0);
+	monitor->details->changed_id =
+		g_signal_connect_object (monitor->details->volume_monitor, "volume_changed",
+					 G_CALLBACK (volume_changed_callback), monitor, 0);
 
 }
 
@@ -473,6 +494,9 @@
 	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);
 
Index: libnautilus-private/nautilus-file-operations.c
===================================================================
--- libnautilus-private/nautilus-file-operations.c	(revision 13516)
+++ libnautilus-private/nautilus-file-operations.c	(working copy)
@@ -1744,10 +1744,19 @@
 do_unmount (UnmountData *data)
 {
 	if (data->eject) {
-		g_volume_eject (data->volume, 
+#if 0
+/* TODO */
+		GDrive *drive;
+
+		drive = g_volume_get_drive (drive);
+		if (drive != NULL) {
+			g_drive_eject (drive, 
 				NULL,
 				unmount_volume_callback,
 				data);
+			g_object_unref (drive);
+		}
+#endif
 	} else {
 		g_volume_unmount (data->volume,
 				  NULL,


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