[Xfce4-commits] <thunar:master> Add ThunarDevice and ThunarDeviceMonitor.

Nick Schermer noreply at xfce.org
Sat Oct 13 16:12:18 CEST 2012


Updating branch refs/heads/master
         to 80b8bd1369e78797ff1b0450b0c760e8c11795c4 (commit)
       from 1995467b592f0f9c3f4ed6b960831b761ef79ae1 (commit)

commit 80b8bd1369e78797ff1b0450b0c760e8c11795c4
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Oct 7 00:10:30 2012 +0200

    Add ThunarDevice and ThunarDeviceMonitor.
    
    This is an shell around GVolumeMonitor and GVolume/GMount and
    possibly in the future GDrive. The idea is that the models
    and views don't need to know what type they handle.
    
    If a volume/drive/mount needs to be visible to the user, it is
    added with device-added, if something changed, device-removed is
    triggered and when the device need to be invisible or is removed
    device-removed is called.
    
    It also takes care of the mount/unmount/eject feature, independent of
    the type.

 thunar/Makefile.am             |    4 +
 thunar/thunar-device-monitor.c |  639 ++++++++++++++++++++++++++++++++++++
 thunar/thunar-device-monitor.h |   44 +++
 thunar/thunar-device.c         |  711 ++++++++++++++++++++++++++++++++++++++++
 thunar/thunar-device.h         |   88 +++++
 5 files changed, 1486 insertions(+), 0 deletions(-)

diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 3bafe9d..bc12573 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -71,6 +71,10 @@ thunar_SOURCES =							\
 	thunar-details-view.h						\
 	thunar-dialogs.c						\
 	thunar-dialogs.h						\
+	thunar-device.c							\
+	thunar-device.h							\
+	thunar-device-monitor.c						\
+	thunar-device-monitor.h						\
 	thunar-dnd.c							\
 	thunar-dnd.h							\
 	thunar-emblem-chooser.c						\
diff --git a/thunar/thunar-device-monitor.c b/thunar/thunar-device-monitor.c
new file mode 100644
index 0000000..c70ff7a
--- /dev/null
+++ b/thunar/thunar-device-monitor.c
@@ -0,0 +1,639 @@
+/*-
+ * Copyright (c) 2009-2010 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2012      Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+#ifdef HAVE_GIO_UNIX
+#include <gio/gunixmounts.h>
+#endif
+
+#include <thunar/thunar-device-monitor.h>
+#include <thunar/thunar-private.h>
+
+
+
+/* signal identifiers */
+enum
+{
+  DEVICE_ADDED,
+  DEVICE_REMOVED,
+  DEVICE_CHANGED,
+  LAST_SIGNAL
+};
+
+
+
+static void           thunar_device_monitor_finalize               (GObject                *object);
+static void           thunar_device_monitor_volume_added           (GVolumeMonitor         *volume_monitor,
+                                                                    GVolume                *volume,
+                                                                    ThunarDeviceMonitor    *monitor);
+static void           thunar_device_monitor_volume_removed         (GVolumeMonitor         *volume_monitor,
+                                                                    GVolume                *volume,
+                                                                    ThunarDeviceMonitor    *monitor);
+static void           thunar_device_monitor_volume_changed         (GVolumeMonitor         *volume_monitor,
+                                                                    GVolume                *volume,
+                                                                    ThunarDeviceMonitor    *monitor);
+static void           thunar_device_monitor_mount_added            (GVolumeMonitor         *volume_monitor,
+                                                                    GMount                 *mount,
+                                                                    ThunarDeviceMonitor    *monitor);
+static void           thunar_device_monitor_mount_removed          (GVolumeMonitor         *volume_monitor,
+                                                                    GMount                 *mount,
+                                                                    ThunarDeviceMonitor    *monitor);
+static void           thunar_device_monitor_mount_changed          (GVolumeMonitor         *volume_monitor,
+                                                                    GMount                 *mount,
+                                                                    ThunarDeviceMonitor    *monitor);
+
+
+
+struct _ThunarDeviceMonitorClass
+{
+  GObjectClass __parent__;
+
+  /* signals */
+  void (*device_added)   (ThunarDeviceMonitor *monitor,
+                          ThunarDevice        *device);
+  void (*device_removed) (ThunarDeviceMonitor *monitor,
+                          ThunarDevice        *device);
+  void (*device_changed) (ThunarDeviceMonitor *monitor,
+                          ThunarDevice        *device);
+};
+
+struct _ThunarDeviceMonitor
+{
+  GObject __parent__;
+
+  GVolumeMonitor *volume_monitor;
+
+  /* GVolume/GMount -> ThunarDevice */
+  GHashTable     *devices;
+
+  GList          *hidden_volumes;
+};
+
+struct _ThunarDevice
+{
+
+};
+
+
+
+static guint device_monitor_signals[LAST_SIGNAL];
+
+
+
+G_DEFINE_TYPE (ThunarDeviceMonitor, thunar_device_monitor, G_TYPE_OBJECT)
+
+
+
+static void
+thunar_device_monitor_class_init (ThunarDeviceMonitorClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = thunar_device_monitor_finalize;
+
+  device_monitor_signals[DEVICE_ADDED] =
+      g_signal_new (I_("device-added"),
+                    G_TYPE_FROM_CLASS (klass),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (ThunarDeviceMonitorClass, device_added),
+                    NULL, NULL,
+                    g_cclosure_marshal_VOID__POINTER,
+                    G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+  device_monitor_signals[DEVICE_REMOVED] =
+      g_signal_new (I_("device-removed"),
+                    G_TYPE_FROM_CLASS (klass),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (ThunarDeviceMonitorClass, device_removed),
+                    NULL, NULL,
+                    g_cclosure_marshal_VOID__POINTER,
+                    G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+  device_monitor_signals[DEVICE_CHANGED] =
+      g_signal_new (I_("device-changed"),
+                    G_TYPE_FROM_CLASS (klass),
+                    G_SIGNAL_RUN_LAST,
+                    G_STRUCT_OFFSET (ThunarDeviceMonitorClass, device_changed),
+                    NULL, NULL,
+                    g_cclosure_marshal_VOID__POINTER,
+                    G_TYPE_NONE, 1, G_TYPE_POINTER);
+}
+
+
+
+static void
+thunar_device_monitor_init (ThunarDeviceMonitor *monitor)
+{
+  GList *list;
+  GList *lp;
+
+  /* table for GVolume/GMount (key) -> ThunarDevice (value) */
+  monitor->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, g_object_unref);
+
+  /* gio volume monitor */
+  monitor->volume_monitor = g_volume_monitor_get ();
+
+  /* load all volumes */
+  list = g_volume_monitor_get_volumes (monitor->volume_monitor);
+  for (lp = list; lp != NULL; lp = lp->next)
+    {
+      thunar_device_monitor_volume_added (monitor->volume_monitor, lp->data, monitor);
+      g_object_unref (G_OBJECT (lp->data));
+    }
+  g_list_free (list);
+
+  /* load all mount */
+  list = g_volume_monitor_get_mounts (monitor->volume_monitor);
+  for (lp = list; lp != NULL; lp = lp->next)
+    {
+      thunar_device_monitor_mount_added (monitor->volume_monitor, lp->data, monitor);
+      g_object_unref (G_OBJECT (lp->data));
+    }
+  g_list_free (list);
+
+  /* watch changes */
+  g_signal_connect (monitor->volume_monitor, "volume-added", G_CALLBACK (thunar_device_monitor_volume_added), monitor);
+  g_signal_connect (monitor->volume_monitor, "volume-removed", G_CALLBACK (thunar_device_monitor_volume_removed), monitor);
+  g_signal_connect (monitor->volume_monitor, "volume-changed", G_CALLBACK (thunar_device_monitor_volume_changed), monitor);
+  g_signal_connect (monitor->volume_monitor, "mount-added", G_CALLBACK (thunar_device_monitor_mount_added), monitor);
+  g_signal_connect (monitor->volume_monitor, "mount-removed", G_CALLBACK (thunar_device_monitor_mount_removed), monitor);
+  g_signal_connect (monitor->volume_monitor, "mount-changed", G_CALLBACK (thunar_device_monitor_mount_changed), monitor);
+}
+
+
+
+static void
+thunar_device_monitor_finalize (GObject *object)
+{
+  ThunarDeviceMonitor *monitor = THUNAR_DEVICE_MONITOR (object);
+
+  /* detatch from the monitor */
+  g_signal_handlers_disconnect_matched (monitor->volume_monitor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, monitor);
+  g_object_unref (monitor->volume_monitor);
+
+  /* clear list of devices */
+  g_hash_table_destroy (monitor->devices);
+
+  /* clear list of hidden volumes */
+  g_list_free_full (monitor->hidden_volumes, g_object_unref);
+
+  (*G_OBJECT_CLASS (thunar_device_monitor_parent_class)->finalize) (object);
+}
+
+
+
+#ifdef HAVE_GIO_UNIX
+static gboolean
+thunar_device_monitor_mount_is_internal (GMount *mount)
+{
+  const gchar *point_mount_path;
+  gboolean     is_internal = FALSE;
+  GFile       *root;
+  GList       *lp;
+  GList       *mount_points;
+  gchar       *mount_path;
+
+  _thunar_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
+
+  /* determine the mount path */
+  root = g_mount_get_root (mount);
+  mount_path = g_file_get_path (root);
+  g_object_unref (root);
+
+  /* assume non-internal if we cannot determine the path */
+  if (mount_path == NULL)
+    return FALSE;
+
+  if (g_unix_is_mount_path_system_internal (mount_path))
+    {
+      /* mark as internal */
+      is_internal = TRUE;
+    }
+  else
+    {
+      /* get a list of all mount points */
+      mount_points = g_unix_mount_points_get (NULL);
+
+      /* search for the mount point associated with the mount entry */
+      for (lp = mount_points; !is_internal && lp != NULL; lp = lp->next)
+        {
+          point_mount_path = g_unix_mount_point_get_mount_path (lp->data);
+
+          /* check if this is the mount point we are looking for */
+          if (g_strcmp0 (mount_path, point_mount_path) == 0)
+            {
+              /* mark as internal if the user cannot mount this device */
+              if (!g_unix_mount_point_is_user_mountable (lp->data))
+                is_internal = TRUE;
+            }
+
+          /* free the mount point, we no longer need it */
+          g_unix_mount_point_free (lp->data);
+        }
+
+      /* free the mount point list */
+      g_list_free (mount_points);
+    }
+
+  g_free (mount_path);
+
+  return is_internal;
+}
+#endif
+
+
+
+static gboolean
+thunar_device_monitor_has_location (ThunarDeviceMonitor *monitor,
+                                    GFile               *location)
+{
+
+  _thunar_return_val_if_fail (G_IS_FILE (location), FALSE);
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor), FALSE);
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_device_monitor_mount_is_hidden (GMount              *mount,
+                                       ThunarDeviceMonitor *monitor)
+{
+  GVolume *volume;
+  GFile   *location;
+
+  _thunar_return_val_if_fail (G_IS_MOUNT (mount), TRUE);
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor), TRUE);
+
+  /* never show shadowed mounts */
+  if (g_mount_is_shadowed (mount))
+    return TRUE;
+
+  /* skip mounts with a volume, we prefer a volume as device */
+  volume = g_mount_get_volume (mount);
+  if (volume != NULL)
+    {
+      g_object_unref (volume);
+      return TRUE;
+    }
+
+  location = g_mount_get_root (mount);
+
+  /* skip ghoto locations, since those also have a volume
+   * and igore locations already in the device list */
+  if (g_file_has_uri_scheme (location, "gphoto2")
+      || thunar_device_monitor_has_location (monitor, location))
+    {
+      g_object_unref (location);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_device_monitor_volume_is_visible (GVolume *volume)
+{
+  gboolean         can_eject = FALSE;
+  gboolean         can_mount = FALSE;
+  gboolean         can_unmount = FALSE;
+  gboolean         is_removable = FALSE;
+  gboolean         is_internal = FALSE;
+  GDrive          *drive;
+  GMount          *mount;
+
+  _thunar_return_val_if_fail (G_IS_VOLUME (volume), TRUE);
+
+  /* determine the mount for the volume (if it is mounted at all) */
+  mount = g_volume_get_mount (volume);
+  if (mount != NULL)
+    {
+#ifdef HAVE_GIO_UNIX
+      is_internal = thunar_device_monitor_mount_is_internal (mount);
+#endif
+
+      /* check if the volume can be unmounted */
+      can_unmount = g_mount_can_unmount (mount);
+
+      /* release the mount */
+      g_object_unref (mount);
+    }
+
+  /* don't show internal volumes */
+  if (is_internal)
+    return FALSE;
+
+  /* check if the volume can be ejected */
+  can_eject = g_volume_can_eject (volume);
+
+  /* determine the drive for the volume */
+  drive = g_volume_get_drive (volume);
+  if (drive != NULL)
+    {
+      /* check if the drive media can be removed */
+      is_removable = g_drive_is_media_removable (drive);
+
+      /* release the drive */
+      g_object_unref (drive);
+    }
+
+  /* determine whether the device can be mounted */
+  can_mount = g_volume_can_mount (volume);
+
+  return (can_eject || can_unmount || is_removable || can_mount);
+}
+
+
+
+static void
+thunar_device_monitor_volume_added (GVolumeMonitor      *volume_monitor,
+                                    GVolume             *volume,
+                                    ThunarDeviceMonitor *monitor)
+{
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor));
+  _thunar_return_if_fail (monitor->volume_monitor == volume_monitor);
+  _thunar_return_if_fail (G_IS_VOLUME (volume));
+
+  /* add to internal list */
+  monitor->hidden_volumes = g_list_prepend (monitor->hidden_volumes, g_object_ref (volume));
+
+  /* change visibility in changed */
+  thunar_device_monitor_volume_changed (volume_monitor, volume, monitor);
+}
+
+
+
+static void
+thunar_device_monitor_volume_removed (GVolumeMonitor      *volume_monitor,
+                                      GVolume             *volume,
+                                      ThunarDeviceMonitor *monitor)
+{
+  ThunarDevice *device;
+  GList        *lp;
+
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor));
+  _thunar_return_if_fail (monitor->volume_monitor == volume_monitor);
+  _thunar_return_if_fail (G_IS_VOLUME (volume));
+
+  /* remove the volume */
+  lp = g_list_find (monitor->hidden_volumes, volume);
+  if (lp != NULL)
+    {
+      /* silently drop it */
+      monitor->hidden_volumes = g_list_delete_link (monitor->hidden_volumes, lp);
+
+      /* release ref from hidden list */
+      g_object_unref (G_OBJECT (volume));
+    }
+  else
+    {
+      /* find device */
+      device = g_hash_table_lookup (monitor->devices, volume);
+
+      /* meh */
+      _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
+      if (G_UNLIKELY (device == NULL))
+        return;
+
+      /* the device is not visble for the user */
+      g_signal_emit (G_OBJECT (monitor), device_monitor_signals[DEVICE_REMOVED], 0, device);
+
+      /* drop it */
+      g_hash_table_remove (monitor->devices, volume);
+    }
+}
+
+
+
+static void
+thunar_device_monitor_volume_changed (GVolumeMonitor      *volume_monitor,
+                                      GVolume             *volume,
+                                      ThunarDeviceMonitor *monitor)
+{
+  GList        *lp;
+  ThunarDevice *device;
+
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor));
+  _thunar_return_if_fail (monitor->volume_monitor == volume_monitor);
+  _thunar_return_if_fail (G_IS_VOLUME (volume));
+
+  lp = g_list_find (monitor->hidden_volumes, volume);
+  if (lp != NULL)
+    {
+      /* check if the volume should be visible again */
+      if (thunar_device_monitor_volume_is_visible (volume))
+        {
+          /* remove from the hidden list */
+          monitor->hidden_volumes = g_list_delete_link (monitor->hidden_volumes, lp);
+
+          /* create a new device for this volume */
+          device = g_object_new (THUNAR_TYPE_DEVICE,
+                                 "device", volume,
+                                 "kind", THUNAR_DEVICE_KIND_VOLUME,
+                                 NULL);
+
+          /* insert to list (takes ref from hidden list) */
+          g_hash_table_insert (monitor->devices, volume, device);
+
+          /* notify */
+          g_signal_emit (G_OBJECT (monitor), device_monitor_signals[DEVICE_ADDED], 0, device);
+        }
+    }
+  else
+    {
+      /* find device */
+      device = g_hash_table_lookup (monitor->devices, volume);
+
+      /* meh */
+      _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
+      if (G_UNLIKELY (device == NULL))
+        return;
+
+      if (!thunar_device_monitor_volume_is_visible (volume))
+        {
+          /* remove from table */
+          g_hash_table_steal (monitor->devices, volume);
+
+          /* insert volume in hidden table, take ref from table */
+          monitor->hidden_volumes = g_list_prepend (monitor->hidden_volumes, volume);
+
+          /* the device is not visble for the user */
+          g_signal_emit (G_OBJECT (monitor), device_monitor_signals[DEVICE_REMOVED], 0, device);
+
+          /* destroy device */
+          g_object_unref (G_OBJECT (device));
+        }
+      else
+        {
+          /* the device changed */
+          g_signal_emit (G_OBJECT (monitor), device_monitor_signals[DEVICE_CHANGED], 0, device);
+        }
+    }
+}
+
+
+
+static void
+thunar_device_monitor_mount_added (GVolumeMonitor      *volume_monitor,
+                                   GMount              *mount,
+                                   ThunarDeviceMonitor *monitor)
+{
+  ThunarDevice     *device;
+  GFile            *location;
+  ThunarDeviceKind  kind = THUNAR_DEVICE_KIND_MOUNT_LOCAL;
+
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor));
+  _thunar_return_if_fail (monitor->volume_monitor == volume_monitor);
+  _thunar_return_if_fail (G_IS_MOUNT (mount));
+
+  if (!thunar_device_monitor_mount_is_hidden (mount, monitor))
+    {
+      location = g_mount_get_root (mount);
+      if (G_LIKELY (location != NULL))
+        {
+          if (g_file_has_uri_scheme (location, "file")
+              || g_file_has_uri_scheme (location, "archive"))
+            kind = THUNAR_DEVICE_KIND_MOUNT_LOCAL;
+          else
+            kind = THUNAR_DEVICE_KIND_MOUNT_REMOTE;
+
+          g_object_unref (location);
+        }
+
+      /* create a new device for this mount */
+      device = g_object_new (THUNAR_TYPE_DEVICE,
+                             "device", mount,
+                             "kind", kind,
+                             NULL);
+
+      /* insert to list */
+      g_hash_table_insert (monitor->devices, g_object_ref (mount), device);
+
+      /* notify */
+      g_signal_emit (G_OBJECT (monitor), device_monitor_signals[DEVICE_ADDED], 0, device);
+    }
+}
+
+
+
+static void
+thunar_device_monitor_mount_removed (GVolumeMonitor      *volume_monitor,
+                                     GMount              *mount,
+                                     ThunarDeviceMonitor *monitor)
+{
+  ThunarDevice *device;
+
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor));
+  _thunar_return_if_fail (monitor->volume_monitor == volume_monitor);
+  _thunar_return_if_fail (G_IS_MOUNT (mount));
+
+  /* check if we have a device for this mount */
+  device = g_hash_table_lookup (monitor->devices, mount);
+  if (device != NULL)
+    {
+      /* notify */
+      g_signal_emit (G_OBJECT (monitor), device_monitor_signals[DEVICE_REMOVED], 0, device);
+
+      /* drop it */
+      g_hash_table_remove (monitor->devices, mount);
+    }
+}
+
+
+
+static void
+thunar_device_monitor_mount_changed (GVolumeMonitor      *volume_monitor,
+                                     GMount              *mount,
+                                     ThunarDeviceMonitor *monitor)
+{
+  ThunarDevice *device;
+
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (volume_monitor));
+  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor));
+  _thunar_return_if_fail (monitor->volume_monitor == volume_monitor);
+  _thunar_return_if_fail (G_IS_MOUNT (mount));
+
+  /* check if we have a device for this mount */
+  device = g_hash_table_lookup (monitor->devices, mount);
+  if (device != NULL)
+    {
+      /* notify */
+      g_signal_emit (G_OBJECT (monitor), device_monitor_signals[DEVICE_CHANGED], 0, device);
+    }
+}
+
+
+
+static void
+thunar_device_monitor_list_prepend (gpointer key,
+                                    gpointer value,
+                                    gpointer user_data)
+{
+  GList **list = user_data;
+
+  _thunar_return_if_fail (THUNAR_IS_DEVICE (value));
+  *list = g_list_prepend (*list, g_object_ref (value));
+}
+
+
+
+ThunarDeviceMonitor *
+thunar_device_monitor_get (void)
+{
+static ThunarDeviceMonitor *monitor = NULL;
+
+  if (G_UNLIKELY (monitor == NULL))
+    {
+      monitor = g_object_new (THUNAR_TYPE_DEVICE_MONITOR, NULL);
+      g_object_add_weak_pointer (G_OBJECT (monitor), (gpointer) &monitor);
+    }
+  else
+    {
+      g_object_ref (G_OBJECT (monitor));
+    }
+
+  return monitor;
+}
+
+
+
+GList *
+thunar_device_monitor_get_devices (ThunarDeviceMonitor *monitor)
+{
+  GList *list = NULL;
+
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE_MONITOR (monitor), NULL);
+
+  g_hash_table_foreach (monitor->devices, thunar_device_monitor_list_prepend, &list);
+
+  return list;
+}
diff --git a/thunar/thunar-device-monitor.h b/thunar/thunar-device-monitor.h
new file mode 100644
index 0000000..4932c41
--- /dev/null
+++ b/thunar/thunar-device-monitor.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2012 Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __THUNAR_DEVICE_MONITOR_H__
+#define __THUNAR_DEVICE_MONITOR_H__
+
+#include <thunar/thunar-device.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ThunarDeviceMonitorClass ThunarDeviceMonitorClass;
+typedef struct _ThunarDeviceMonitor      ThunarDeviceMonitor;
+
+#define THUNAR_TYPE_DEVICE_MONITOR             (thunar_device_monitor_get_type ())
+#define THUNAR_DEVICE_MONITOR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DEVICE_MONITOR, ThunarDeviceMonitor))
+#define THUNAR_DEVICE_MONITOR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DEVICE_MONITOR, ThunarDeviceMonitorClass))
+#define THUNAR_IS_DEVICE_MONITOR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DEVICE_MONITOR))
+#define THUNAR_IS_DEVICE_MONITOR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((obj), THUNAR_TYPE_DEVICE_MONITOR))
+#define THUNAR_DEVICE_MONITOR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DEVICE_MONITOR, ThunarDeviceMonitorClass))
+
+GType                thunar_device_monitor_get_type    (void) G_GNUC_CONST;
+
+ThunarDeviceMonitor *thunar_device_monitor_get         (void);
+
+GList               *thunar_device_monitor_get_devices (ThunarDeviceMonitor *monitor);
+
+G_END_DECLS
+
+#endif /* !__THUNAR_DEVICE_MONITOR_H__ */
diff --git a/thunar/thunar-device.c b/thunar/thunar-device.c
new file mode 100644
index 0000000..0178014
--- /dev/null
+++ b/thunar/thunar-device.c
@@ -0,0 +1,711 @@
+/*-
+ * Copyright (c) 2012 Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_LIBNOTIFY
+#include <thunar/thunar-notify.h>
+#endif
+#include <thunar/thunar-device.h>
+#include <thunar/thunar-private.h>
+
+
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE,
+  PROP_KIND
+};
+
+
+
+static void           thunar_device_finalize               (GObject                *object);
+static void           thunar_device_get_property           (GObject                 *object,
+                                                            guint                    prop_id,
+                                                            GValue                  *value,
+                                                            GParamSpec              *pspec);
+static void           thunar_device_set_property           (GObject                 *object,
+                                                            guint                    prop_id,
+                                                            const GValue            *value,
+                                                            GParamSpec              *pspec);
+
+
+
+struct _ThunarDeviceClass
+{
+  GObjectClass __parent__;
+};
+
+struct _ThunarDevice
+{
+  GObject __parent__;
+
+  /* a GVolume/GMount/GDrive */
+  gpointer          device;
+
+  ThunarDeviceKind  kind;
+};
+
+typedef struct
+{
+  ThunarDevice         *device;
+  ThunarDeviceCallback  callback;
+  gpointer              user_data;
+}
+ThunarDeviceOperation;
+
+
+
+G_DEFINE_TYPE (ThunarDevice, thunar_device, G_TYPE_OBJECT)
+
+
+
+static void
+thunar_device_class_init (ThunarDeviceClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = thunar_device_finalize;
+  gobject_class->get_property = thunar_device_get_property;
+  gobject_class->set_property = thunar_device_set_property;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_DEVICE,
+                                   g_param_spec_object ("device",
+                                                        "device",
+                                                        "device",
+                                                        G_TYPE_OBJECT,
+                                                        EXO_PARAM_READWRITE
+                                                        | G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_KIND,
+                                   g_param_spec_uint ("kind",
+                                                      "kind",
+                                                      "kind",
+                                                      THUNAR_DEVICE_KIND_VOLUME,
+                                                      THUNAR_DEVICE_KIND_MOUNT_REMOTE,
+                                                      THUNAR_DEVICE_KIND_VOLUME,
+                                                      EXO_PARAM_READWRITE
+                                                      | G_PARAM_CONSTRUCT_ONLY));
+}
+
+
+
+static void
+thunar_device_init (ThunarDevice *device)
+{
+  device->kind = THUNAR_DEVICE_KIND_VOLUME;
+}
+
+
+
+static void
+thunar_device_finalize (GObject *object)
+{
+  ThunarDevice *device = THUNAR_DEVICE (object);
+
+  if (device->device != NULL)
+    g_object_unref (G_OBJECT (device->device));
+
+  (*G_OBJECT_CLASS (thunar_device_parent_class)->finalize) (object);
+}
+
+
+
+static void
+thunar_device_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  ThunarDevice *device = THUNAR_DEVICE (object);
+
+  switch (prop_id)
+    {
+    case PROP_DEVICE:
+      g_value_set_object (value, device->device);
+      break;
+
+    case PROP_KIND:
+      g_value_set_uint (value, device->kind);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+static void
+thunar_device_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  ThunarDevice *device = THUNAR_DEVICE (object);
+
+  switch (prop_id)
+    {
+    case PROP_DEVICE:
+      device->device = g_value_dup_object (value);
+      _thunar_assert (G_IS_VOLUME (device->device) || G_IS_MOUNT (device->device));
+      break;
+
+    case PROP_KIND:
+      device->kind = g_value_get_uint (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+
+static ThunarDeviceOperation *
+thunar_device_operation_new (ThunarDevice         *device,
+                             ThunarDeviceCallback  callback,
+                             gpointer              user_data)
+{
+  ThunarDeviceOperation *operation;
+
+  operation = g_slice_new0 (ThunarDeviceOperation);
+  operation->device = g_object_ref (device);
+  operation->callback = callback;
+  operation->user_data = user_data;
+
+  return operation;
+}
+
+
+
+static void
+thunar_device_operation_free (ThunarDeviceOperation *operation)
+{
+  g_object_unref (operation->device);
+  g_slice_free (ThunarDeviceOperation, operation);
+}
+
+
+
+static void
+thunar_device_mount_unmount_finish (GObject      *object,
+                                    GAsyncResult *result,
+                                    gpointer      user_data)
+{
+  ThunarDeviceOperation *operation = user_data;
+  GError                *error = NULL;
+
+  _thunar_return_if_fail (G_IS_MOUNT (object));
+  _thunar_return_if_fail (G_IS_ASYNC_RESULT (result));
+
+#ifdef HAVE_LIBNOTIFY
+  thunar_notify_unmount_finish (G_MOUNT (object));
+#endif
+
+  /* finish the unmount */
+  if (!g_mount_unmount_with_operation_finish (G_MOUNT (object), result, &error))
+    {
+      /* unset the error if a helper program has already interacted with the user */
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED))
+        g_clear_error (&error);
+    }
+
+  /* callback */
+  (operation->callback) (operation->device, error, operation->user_data);
+
+  /* cleanup */
+  if (error != NULL)
+    g_error_free (error);
+  thunar_device_operation_free (operation);
+}
+
+
+
+static void
+thunar_device_mount_eject_finish (GObject      *object,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  ThunarDeviceOperation *operation = user_data;
+  GError                *error = NULL;
+
+  _thunar_return_if_fail (G_IS_MOUNT (object));
+  _thunar_return_if_fail (G_IS_ASYNC_RESULT (result));
+
+#ifdef HAVE_LIBNOTIFY
+  thunar_notify_unmount_finish (G_MOUNT (object));
+#endif
+
+  /* finish the eject */
+  if (!g_mount_eject_with_operation_finish (G_MOUNT (object), result, &error))
+    {
+      /* unset the error if a helper program has already interacted with the user */
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED))
+        g_clear_error (&error);
+    }
+
+  /* callback */
+  (operation->callback) (operation->device, error, operation->user_data);
+
+  /* cleanup */
+  if (error != NULL)
+    g_error_free (error);
+  thunar_device_operation_free (operation);
+}
+
+
+
+static void
+thunar_device_volume_eject_finish (GObject      *object,
+                                   GAsyncResult *result,
+                                   gpointer      user_data)
+{
+  ThunarDeviceOperation *operation = user_data;
+  GError                *error = NULL;
+
+  _thunar_return_if_fail (G_IS_VOLUME (object));
+  _thunar_return_if_fail (G_IS_ASYNC_RESULT (result));
+
+#ifdef HAVE_LIBNOTIFY
+  thunar_notify_eject_finish (G_VOLUME (object));
+#endif
+
+  /* finish the eject */
+  if (!g_volume_eject_with_operation_finish (G_VOLUME (object), result, &error))
+    {
+      /* unset the error if a helper program has already interacted with the user */
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED))
+        g_clear_error (&error);
+    }
+
+  /* callback */
+  (operation->callback) (operation->device, error, operation->user_data);
+
+  /* cleanup */
+  if (error != NULL)
+    g_error_free (error);
+  thunar_device_operation_free (operation);
+}
+
+
+
+gchar *
+thunar_device_get_name (const ThunarDevice *device)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
+
+  if (G_IS_VOLUME (device->device))
+    return g_volume_get_name (device->device);
+  else if (G_IS_MOUNT (device->device))
+   return g_mount_get_name (device->device);
+  else
+    _thunar_assert_not_reached ();
+
+  return NULL;
+}
+
+
+
+GIcon *
+thunar_device_get_icon (const ThunarDevice *device)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
+
+  if (G_IS_VOLUME (device->device))
+    return g_volume_get_icon (device->device);
+  else if (G_IS_MOUNT (device->device))
+   return g_mount_get_icon (device->device);
+  else
+    _thunar_assert_not_reached ();
+
+  return NULL;
+}
+
+
+
+ThunarDeviceKind
+thunar_device_get_kind (const ThunarDevice *device)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), THUNAR_DEVICE_KIND_VOLUME);
+  return device->kind;
+}
+
+
+
+/**
+ * thunar_device_can_eject:
+ *
+ * If the user should see the option to eject this device.
+ **/
+gboolean
+thunar_device_can_eject (const ThunarDevice *device)
+{
+  gboolean  can_eject = FALSE;
+  GMount   *volume_mount;
+
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
+
+  if (G_IS_VOLUME (device->device))
+    {
+      can_eject = g_volume_can_eject (device->device);
+
+      if (!can_eject)
+        {
+          /* check if the mount can eject/unmount */
+          volume_mount = g_volume_get_mount (device->device);
+          if (volume_mount != NULL)
+            {
+              can_eject = g_mount_can_eject (volume_mount) || g_mount_can_unmount (volume_mount);
+              g_object_unref (volume_mount);
+            }
+        }
+    }
+  else if (G_IS_MOUNT (device->device))
+    {
+      /* eject or unmount because thats for the user the same
+       * because we prefer volumes over mounts as devices */
+      can_eject = g_mount_can_eject (device->device) || g_mount_can_unmount (device->device);
+    }
+  else
+    _thunar_assert_not_reached ();
+
+  return can_eject;
+}
+
+
+
+/**
+ * thunar_device_can_mount:
+ *
+ * If the user should see the option to mount this device.
+ **/
+gboolean
+thunar_device_can_mount (const ThunarDevice *device)
+{
+  gboolean  can_mount = FALSE;
+  GMount   *volume_mount;
+
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
+
+  if (G_IS_VOLUME (device->device))
+    {
+      /* only volumes without a mountpoint and mount capability */
+      volume_mount = g_volume_get_mount (device->device);
+      if (volume_mount == NULL)
+        can_mount = g_volume_can_mount (device->device);
+      else
+        g_object_unref (volume_mount);
+    }
+  else if (G_IS_MOUNT (device->device))
+    {
+      /* a mount is already mounted... */
+      can_mount = FALSE;
+    }
+  else
+    _thunar_assert_not_reached ();
+
+  return can_mount;
+}
+
+
+
+/**
+ * thunar_device_can_unmount:
+ *
+ * If the user should see the option to unmount this device.
+ **/
+gboolean
+thunar_device_can_unmount (const ThunarDevice *device)
+{
+  gboolean  can_unmount = FALSE;
+  GMount   *volume_mount;
+
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
+
+  if (G_IS_VOLUME (device->device))
+    {
+      /* only volumes with a mountpoint and unmount capability */
+      volume_mount = g_volume_get_mount (device->device);
+      if (volume_mount != NULL)
+        {
+          can_unmount = g_mount_can_unmount (volume_mount);
+          g_object_unref (volume_mount);
+        }
+    }
+  else if (G_IS_MOUNT (device->device))
+    {
+      /* check if the mount can unmount */
+      can_unmount = g_mount_can_unmount (device->device);
+    }
+  else
+    _thunar_assert_not_reached ();
+
+  return can_unmount;
+}
+
+
+
+gboolean
+thunar_device_is_mounted (const ThunarDevice *device)
+{
+  gboolean  is_mounted = FALSE;
+  GMount   *volume_mount;
+
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
+  
+  if (G_IS_VOLUME (device->device))
+    {
+      /* a volume with a mount point is mounted */
+      volume_mount = g_volume_get_mount (device->device);
+      if (volume_mount != NULL)
+        {
+          is_mounted = TRUE;
+          g_object_unref (volume_mount);
+        }
+    }
+  else if (G_IS_MOUNT (device->device))
+    {
+      /* mounter are always mounted... */
+      is_mounted = TRUE;
+    }
+  else
+    _thunar_assert_not_reached ();
+
+  return is_mounted;
+}
+
+
+
+GFile *
+thunar_device_get_root (const ThunarDevice *device)
+{
+  GFile  *root = NULL;
+  GMount *volume_mount;
+
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
+
+  if (G_IS_VOLUME (device->device))
+    {
+      volume_mount = g_volume_get_mount (device->device);
+      if (volume_mount != NULL)
+        {
+          root = g_mount_get_root (volume_mount);
+          g_object_unref (volume_mount);
+        }
+    }
+  else if (G_IS_MOUNT (device->device))
+    {
+      root = g_mount_get_root (device->device);
+    }
+  else
+    _thunar_assert_not_reached ();
+
+  return root;
+}
+
+
+
+const gchar *
+thunar_device_get_sort_key (const ThunarDevice *device)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
+
+  if (G_IS_VOLUME (device->device))
+    return g_volume_get_sort_key (device->device);
+  else if (G_IS_MOUNT (device->device))
+    return g_mount_get_sort_key (device->device);
+  else
+    _thunar_assert_not_reached ();
+
+  return NULL;
+}
+
+
+
+void
+thunar_device_mount (ThunarDevice         *device,
+                     GMountOperation      *mount_operation,
+                     GCancellable         *cancellable,
+                     ThunarDeviceCallback  callback,
+                     gpointer              user_data)
+{
+  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
+  _thunar_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
+  _thunar_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+  _thunar_return_if_fail (callback != NULL);
+}
+
+
+
+/**
+ * thunar_device_unmount:
+ *
+ * Unmount a #ThunarDevice. Don't try to eject.
+ **/
+void
+thunar_device_unmount (ThunarDevice         *device,
+                       GMountOperation      *mount_operation,
+                       GCancellable         *cancellable,
+                       ThunarDeviceCallback  callback,
+                       gpointer              user_data)
+{
+  ThunarDeviceOperation *operation;
+  GMount                *mount;
+
+  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
+  _thunar_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
+  _thunar_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+  _thunar_return_if_fail (callback != NULL);
+
+  /* get the mount from the volume or use existing mount */
+  if (G_IS_VOLUME (device->device))
+    mount = g_volume_get_mount (device->device);
+  else if (G_IS_MOUNT (device->device))
+    mount = g_object_ref (device->device);
+  else
+    mount = NULL;
+
+  if (G_LIKELY (mount != NULL))
+    {
+      /* only handle mounts that can be unmounted here */
+      if (g_mount_can_unmount (mount))
+        {
+#ifdef HAVE_LIBNOTIFY
+          thunar_notify_unmount (mount);
+#endif
+
+          /* try unmounting the mount */
+          operation = thunar_device_operation_new (device, callback, user_data);
+          g_mount_unmount_with_operation (mount,
+                                          G_MOUNT_UNMOUNT_NONE,
+                                          mount_operation,
+                                          cancellable,
+                                          thunar_device_mount_unmount_finish,
+                                          operation);
+        }
+
+      g_object_unref (G_OBJECT (mount));
+    }
+}
+
+
+
+/**
+ * thunar_device_unmount:
+ *
+ * Try to eject a #ThunarDevice, fall-back to unmounting
+ **/
+void
+thunar_device_eject (ThunarDevice         *device,
+                     GMountOperation      *mount_operation,
+                     GCancellable         *cancellable,
+                     ThunarDeviceCallback  callback,
+                     gpointer              user_data)
+{
+  ThunarDeviceOperation *operation;
+  GMount                *mount = NULL;
+  GVolume               *volume;
+
+  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
+  _thunar_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
+  _thunar_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+  _thunar_return_if_fail (callback != NULL);
+
+
+  if (G_IS_VOLUME (device->device))
+    {
+      volume = device->device;
+
+      if (g_volume_can_eject (volume))
+        {
+#ifdef HAVE_LIBNOTIFY
+          thunar_notify_eject (volume);
+#endif
+
+          /* try ejecting the volume */
+          operation = thunar_device_operation_new (device, callback, user_data);
+          g_volume_eject_with_operation (volume,
+                                         G_MOUNT_UNMOUNT_NONE,
+                                         mount_operation,
+                                         cancellable,
+                                         thunar_device_volume_eject_finish,
+                                         operation);
+
+          /* done */
+          return;
+        }
+      else
+        {
+          /* get the mount and fall-through */
+          mount = g_volume_get_mount (volume);
+        }
+    }
+  else if (G_IS_MOUNT (device->device))
+    {
+      /* set the mount and fall-through */
+      mount = g_object_ref (device->device);
+    }
+
+  /* handle mounts */
+  if (mount != NULL)
+    {
+      /* distinguish between ejectable and unmountable mounts */
+      if (g_mount_can_eject (mount))
+        {
+#ifdef HAVE_LIBNOTIFY
+          thunar_notify_unmount (mount);
+#endif
+
+          /* try ejecting the mount */
+          operation = thunar_device_operation_new (device, callback, user_data);
+          g_mount_eject_with_operation (mount,
+                                        G_MOUNT_UNMOUNT_NONE,
+                                        mount_operation,
+                                        cancellable,
+                                        thunar_device_mount_eject_finish,
+                                        operation);
+        }
+      else if (g_mount_can_unmount (mount))
+        {
+#ifdef HAVE_LIBNOTIFY
+          thunar_notify_unmount (mount);
+#endif
+
+          /* try unmounting the mount */
+          operation = thunar_device_operation_new (device, callback, user_data);
+          g_mount_unmount_with_operation (mount,
+                                          G_MOUNT_UNMOUNT_NONE,
+                                          mount_operation,
+                                          cancellable,
+                                          thunar_device_mount_unmount_finish,
+                                          operation);
+        }
+
+      g_object_unref (G_OBJECT (mount));
+    }
+}
diff --git a/thunar/thunar-device.h b/thunar/thunar-device.h
new file mode 100644
index 0000000..f4de610
--- /dev/null
+++ b/thunar/thunar-device.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2012 Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __THUNAR_DEVICE_H__
+#define __THUNAR_DEVICE_H__
+
+#include <thunar/thunar-file.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ThunarDeviceClass ThunarDeviceClass;
+typedef struct _ThunarDevice      ThunarDevice;
+typedef enum   _ThunarDeviceKind  ThunarDeviceKind;
+
+typedef void   (*ThunarDeviceCallback) (ThunarDevice *device,
+                                        const GError *error,
+                                        gpointer      user_data);
+
+enum _ThunarDeviceKind
+{
+  THUNAR_DEVICE_KIND_VOLUME,
+  THUNAR_DEVICE_KIND_MOUNT_LOCAL,
+  THUNAR_DEVICE_KIND_MOUNT_REMOTE
+};
+
+#define THUNAR_TYPE_DEVICE             (thunar_device_get_type ())
+#define THUNAR_DEVICE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DEVICE, ThunarDevice))
+#define THUNAR_DEVICE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DEVICE, ThunarDeviceClass))
+#define THUNAR_IS_DEVICE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DEVICE))
+#define THUNAR_IS_DEVICE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((obj), THUNAR_TYPE_DEVICE))
+#define THUNAR_DEVICE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DEVICE, ThunarDeviceClass))
+
+GType                thunar_device_get_type         (void) G_GNUC_CONST;
+
+gchar               *thunar_device_get_name         (const ThunarDevice   *device) G_GNUC_MALLOC;
+
+GIcon               *thunar_device_get_icon         (const ThunarDevice   *device);
+
+ThunarDeviceKind     thunar_device_get_kind         (const ThunarDevice   *device) G_GNUC_PURE;
+
+gboolean             thunar_device_can_eject        (const ThunarDevice   *device);
+
+gboolean             thunar_device_can_mount        (const ThunarDevice   *device);
+
+gboolean             thunar_device_can_unmount      (const ThunarDevice   *device);
+
+gboolean             thunar_device_is_mounted       (const ThunarDevice   *device);
+
+GFile               *thunar_device_get_root         (const ThunarDevice   *device);
+
+const gchar         *thunar_device_get_sort_key     (const ThunarDevice   *device);
+
+void                 thunar_device_mount            (ThunarDevice         *device,
+                                                     GMountOperation      *mount_operation,
+                                                     GCancellable         *cancellable,
+                                                     ThunarDeviceCallback  callback,
+                                                     gpointer              user_data);
+
+void                 thunar_device_unmount          (ThunarDevice         *device,
+                                                     GMountOperation      *mount_operation,
+                                                     GCancellable         *cancellable,
+                                                     ThunarDeviceCallback  callback,
+                                                     gpointer              user_data);
+
+void                 thunar_device_eject            (ThunarDevice         *device,
+                                                     GMountOperation      *mount_operation,
+                                                     GCancellable         *cancellable,
+                                                     ThunarDeviceCallback  callback,
+                                                     gpointer              user_data);
+
+G_END_DECLS
+
+#endif /* !__THUNAR_DEVICE_H__ */


More information about the Xfce4-commits mailing list