summaryrefslogtreecommitdiff
path: root/gnome-2-24/monitor/hal
diff options
context:
space:
mode:
authorChristian Kellner <gicmo@src.gnome.org>2008-09-24 12:40:53 +0000
committerChristian Kellner <gicmo@src.gnome.org>2008-09-24 12:40:53 +0000
commit953132a87aed73507042a6279b343523741a1800 (patch)
tree1dd2709300f9a91685f2724ec2f649abae88b84b /gnome-2-24/monitor/hal
parent923b6f2d78e357029acef582b308c6ca406f2b66 (diff)
downloadgvfs-953132a87aed73507042a6279b343523741a1800.tar.gz
Tagged for release 1.0.1
svn path=/tags/GVFS_1_0_1/; revision=2025
Diffstat (limited to 'gnome-2-24/monitor/hal')
-rw-r--r--gnome-2-24/monitor/hal/Makefile.am62
-rw-r--r--gnome-2-24/monitor/hal/ghaldrive.c1009
-rw-r--r--gnome-2-24/monitor/hal/ghaldrive.h62
-rw-r--r--gnome-2-24/monitor/hal/ghalmount.c1592
-rw-r--r--gnome-2-24/monitor/hal/ghalmount.h76
-rw-r--r--gnome-2-24/monitor/hal/ghalvolume.c1068
-rw-r--r--gnome-2-24/monitor/hal/ghalvolume.h84
-rw-r--r--gnome-2-24/monitor/hal/ghalvolumemonitor.c1399
-rw-r--r--gnome-2-24/monitor/hal/ghalvolumemonitor.h58
-rw-r--r--gnome-2-24/monitor/hal/hal-device.c297
-rw-r--r--gnome-2-24/monitor/hal/hal-device.h93
-rw-r--r--gnome-2-24/monitor/hal/hal-marshal.list3
-rw-r--r--gnome-2-24/monitor/hal/hal-pool.c458
-rw-r--r--gnome-2-24/monitor/hal/hal-pool.h74
-rw-r--r--gnome-2-24/monitor/hal/hal-utils.c171
-rw-r--r--gnome-2-24/monitor/hal/hal-utils.h42
-rw-r--r--gnome-2-24/monitor/hal/hal-volume-monitor-daemon.c43
-rw-r--r--gnome-2-24/monitor/hal/hal.monitor5
-rw-r--r--gnome-2-24/monitor/hal/org.gtk.Private.HalVolumeMonitor.service.in3
19 files changed, 6599 insertions, 0 deletions
diff --git a/gnome-2-24/monitor/hal/Makefile.am b/gnome-2-24/monitor/hal/Makefile.am
new file mode 100644
index 00000000..9c3d1777
--- /dev/null
+++ b/gnome-2-24/monitor/hal/Makefile.am
@@ -0,0 +1,62 @@
+
+NULL =
+
+libexec_PROGRAMS = gvfs-hal-volume-monitor
+
+BUILT_SOURCES = \
+ hal-marshal.h hal-marshal.c
+
+hal-marshal.h: hal-marshal.list
+ glib-genmarshal $< --prefix=hal_marshal --header > $@
+
+hal-marshal.c: hal-marshal.list
+ echo "#include \"hal-marshal.h\"" > $@ && glib-genmarshal $< --prefix=hal_marshal --body >> $@
+
+
+gvfs_hal_volume_monitor_SOURCES = \
+ hal-utils.c hal-utils.h \
+ hal-volume-monitor-daemon.c \
+ hal-marshal.c hal-marshal.h \
+ hal-device.c hal-device.h \
+ hal-pool.c hal-pool.h \
+ ghaldrive.c ghaldrive.h \
+ ghalvolume.c ghalvolume.h \
+ ghalmount.c ghalmount.h \
+ ghalvolumemonitor.c ghalvolumemonitor.h \
+ $(NULL)
+
+gvfs_hal_volume_monitor_CFLAGS = \
+ -DG_LOG_DOMAIN=\"GVFS-Hal\" \
+ -I$(top_srcdir)/common \
+ -I$(top_srcdir)/monitor/proxy \
+ $(GLIB_CFLAGS) \
+ $(HAL_CFLAGS) \
+ -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\" \
+ -DGVFS_LOCALEDIR=\""$(localedir)"\" \
+ -DG_DISABLE_DEPRECATED \
+ $(NULL)
+
+gvfs_hal_volume_monitor_LDFLAGS = \
+ $(NULL)
+
+gvfs_hal_volume_monitor_LDADD = \
+ $(GLIB_LIBS) \
+ $(HAL_LIBS) \
+ $(top_builddir)/common/libgvfscommon.la \
+ $(top_builddir)/monitor/proxy/libgvfsproxyvolumemonitordaemon-noin.la \
+ $(NULL)
+
+remote_volume_monitorsdir = $(datadir)/gvfs/remote-volume-monitors
+remote_volume_monitors_DATA = hal.monitor
+
+servicedir = $(datadir)/dbus-1/services
+service_in_files = org.gtk.Private.HalVolumeMonitor.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
+
+clean-local:
+ rm -f *~ *.loT $(BUILT_SOURCES) $(service_DATA)
+
+EXTRA_DIST = hal-marshal.list $(service_in_files) hal.monitor
diff --git a/gnome-2-24/monitor/hal/ghaldrive.c b/gnome-2-24/monitor/hal/ghaldrive.c
new file mode 100644
index 00000000..c7aea30b
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghaldrive.c
@@ -0,0 +1,1009 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include "ghalvolumemonitor.h"
+#include "ghaldrive.h"
+#include "ghalvolume.h"
+
+/* Protects all fields of GHalDrive that can change */
+G_LOCK_DEFINE_STATIC(hal_drive);
+
+struct _GHalDrive {
+ GObject parent;
+
+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */
+ GList *volumes; /* entries in list are owned by volume_monitor */
+
+ char *name;
+ char *icon;
+ char *device_path;
+
+ gboolean can_eject;
+ gboolean can_poll_for_media;
+ gboolean is_media_check_automatic;
+ gboolean has_media;
+ gboolean uses_removable_media;
+
+ HalDevice *device;
+ HalPool *pool;
+};
+
+static void g_hal_drive_drive_iface_init (GDriveIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GHalDrive, g_hal_drive, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DRIVE,
+ g_hal_drive_drive_iface_init))
+
+static void
+g_hal_drive_finalize (GObject *object)
+{
+ GList *l;
+ GHalDrive *drive;
+
+ drive = G_HAL_DRIVE (object);
+
+ for (l = drive->volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+ g_hal_volume_unset_drive (volume, drive);
+ }
+
+ g_free (drive->device_path);
+ if (drive->device != NULL)
+ g_object_unref (drive->device);
+ if (drive->pool != NULL)
+ g_object_unref (drive->pool);
+
+ g_free (drive->name);
+ g_free (drive->icon);
+
+ if (drive->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (drive->volume_monitor), (gpointer) &(drive->volume_monitor));
+
+ if (G_OBJECT_CLASS (g_hal_drive_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_hal_drive_parent_class)->finalize) (object);
+}
+
+static void
+g_hal_drive_class_init (GHalDriveClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_hal_drive_finalize;
+}
+
+static void
+g_hal_drive_init (GHalDrive *hal_drive)
+{
+}
+
+static char *
+_drive_get_description (HalDevice *d)
+{
+ char *s = NULL;
+ const char *drive_type;
+ const char *drive_bus;
+ const char *name_from_hal;
+
+ drive_type = hal_device_get_property_string (d, "storage.drive_type");
+ drive_bus = hal_device_get_property_string (d, "storage.bus");
+ name_from_hal = hal_device_get_property_string (d, "info.desktop.name");
+
+
+ if (strlen (name_from_hal) > 0)
+ {
+ s = g_strdup (name_from_hal);
+ }
+ else if (strcmp (drive_type, "cdrom") == 0)
+ {
+ const char *first;
+ const char *second;
+
+ first = _("CD-ROM");
+ if (hal_device_get_property_bool (d, "storage.cdrom.cdr"))
+ first = _("CD-R");
+ if (hal_device_get_property_bool (d, "storage.cdrom.cdrw"))
+ first = _("CD-RW");
+
+ second = NULL;
+ if (hal_device_get_property_bool (d, "storage.cdrom.dvd"))
+ second = _("DVD-ROM");
+ if (hal_device_get_property_bool (d, "storage.cdrom.dvdplusr"))
+ second = _("DVD+R");
+ if (hal_device_get_property_bool (d, "storage.cdrom.dvdplusrw"))
+ second = _("DVD+RW");
+ if (hal_device_get_property_bool (d, "storage.cdrom.dvdr"))
+ second = _("DVD-R");
+ if (hal_device_get_property_bool (d, "storage.cdrom.dvdrw"))
+ second = _("DVD-RW");
+ if (hal_device_get_property_bool (d, "storage.cdrom.dvdram"))
+ second = _("DVD-RAM");
+ if ((hal_device_get_property_bool (d, "storage.cdrom.dvdr")) &&
+ (hal_device_get_property_bool (d, "storage.cdrom.dvdplusr")))
+ second = _("DVD\xc2\xb1R");
+ if (hal_device_get_property_bool (d, "storage.cdrom.dvdrw") &&
+ hal_device_get_property_bool (d, "storage.cdrom.dvdplusrw"))
+ second = _("DVD\xc2\xb1RW");
+ if (hal_device_get_property_bool (d, "storage.cdrom.hddvd"))
+ second = _("HDDVD");
+ if (hal_device_get_property_bool (d, "storage.cdrom.hddvdr"))
+ second = _("HDDVD-r");
+ if (hal_device_get_property_bool (d, "storage.cdrom.hddvdrw"))
+ second = _("HDDVD-RW");
+ if (hal_device_get_property_bool (d, "storage.cdrom.bd"))
+ second = _("Blu-ray");
+ if (hal_device_get_property_bool (d, "storage.cdrom.bdr"))
+ second = _("Blu-ray-R");
+ if (hal_device_get_property_bool (d, "storage.cdrom.bdre"))
+ second = _("Blu-ray-RE");
+
+ if (second != NULL)
+ {
+ /* translators: This wis something like "CD-ROM/DVD Drive" or
+ "CD-RW/Blue-ray Drive" depending on the properties of the drive */
+ s = g_strdup_printf (_("%s/%s Drive"), first, second);
+ }
+ else
+ {
+ /* translators: This wis something like "CD-ROM Drive" or "CD-RW Drive
+ depending on the properties of the drive */
+ s = g_strdup_printf (_("%s Drive"), first);
+ }
+ }
+ else if (strcmp (drive_type, "floppy") == 0)
+ s = g_strdup (_("Floppy Drive"));
+ else if (strcmp (drive_type, "disk") == 0)
+ {
+ if (drive_bus != NULL)
+ {
+ if (strcmp (drive_bus, "linux_raid") == 0)
+ s = g_strdup (_("Software RAID Drive"));
+ if (strcmp (drive_bus, "usb") == 0)
+ s = g_strdup (_("USB Drive"));
+ if (strcmp (drive_bus, "ide") == 0)
+ s = g_strdup (_("ATA Drive"));
+ if (strcmp (drive_bus, "scsi") == 0)
+ s = g_strdup (_("SCSI Drive"));
+ if (strcmp (drive_bus, "ieee1394") == 0)
+ s = g_strdup (_("FireWire Drive"));
+ }
+ }
+ else if (strcmp (drive_type, "tape") == 0)
+ s = g_strdup (_("Tape Drive"));
+ else if (strcmp (drive_type, "compact_flash") == 0)
+ s = g_strdup (_("CompactFlash Drive"));
+ else if (strcmp (drive_type, "memory_stick") == 0)
+ s = g_strdup (_("MemoryStick Drive"));
+ else if (strcmp (drive_type, "smart_media") == 0)
+ s = g_strdup (_("SmartMedia Drive"));
+ else if (strcmp (drive_type, "sd_mmc") == 0)
+ s = g_strdup (_("SD/MMC Drive"));
+ else if (strcmp (drive_type, "zip") == 0)
+ s = g_strdup (_("Zip Drive"));
+ else if (strcmp (drive_type, "jaz") == 0)
+ s = g_strdup (_("Jaz Drive"));
+ else if (strcmp (drive_type, "flashkey") == 0)
+ s = g_strdup (_("Thumb Drive"));
+
+ if (s == NULL)
+ s = g_strdup (_("Mass Storage Drive"));
+
+ return s;
+}
+
+char *
+_drive_get_icon (HalDevice *d)
+{
+ char *s = NULL;
+ const char *drive_type;
+ const char *drive_bus;
+ const char *icon_from_hal;
+ gboolean is_audio_player;
+
+ drive_type = hal_device_get_property_string (d, "storage.drive_type");
+ drive_bus = hal_device_get_property_string (d, "storage.bus");
+ is_audio_player = hal_device_has_capability (d, "portable_audio_player");
+ icon_from_hal = hal_device_get_property_string (d, "info.desktop.icon");
+
+ if (strlen (icon_from_hal) > 0)
+ s = g_strdup (icon_from_hal);
+ else if (is_audio_player)
+ s = g_strdup ("multimedia-player");
+ else if (strcmp (drive_type, "disk") == 0)
+ {
+ if (strcmp (drive_bus, "ide") == 0)
+ s = g_strdup ("drive-removable-media-ata");
+ else if (strcmp (drive_bus, "scsi") == 0)
+ s = g_strdup ("drive-removable-media-scsi");
+ else if (strcmp (drive_bus, "ieee1394") == 0)
+ s = g_strdup ("drive-removable-media-ieee1394");
+ else if (strcmp (drive_bus, "usb") == 0)
+ s = g_strdup ("drive-removable-media-usb");
+ else
+ s = g_strdup ("drive-removable-media");
+ }
+ else if (strcmp (drive_type, "cdrom") == 0)
+ {
+ /* TODO: maybe there's a better heuristic than this */
+ if (hal_device_get_property_int (d, "storage.cdrom.write_speed") > 0)
+ s = g_strdup ("drive-optical-recorder");
+ else
+ s = g_strdup ("drive-optical");
+ }
+ else if (strcmp (drive_type, "floppy") == 0)
+ s = g_strdup ("drive-removable-media-floppy");
+ else if (strcmp (drive_type, "tape") == 0)
+ s = g_strdup ("drive-removable-media-tape");
+ else if (strcmp (drive_type, "compact_flash") == 0)
+ s = g_strdup ("drive-removable-media-flash-cf");
+ else if (strcmp (drive_type, "memory_stick") == 0)
+ s = g_strdup ("drive-removable-media-flash-ms");
+ else if (strcmp (drive_type, "smart_media") == 0)
+ s = g_strdup ("drive-removable-media-flash-sm");
+ else if (strcmp (drive_type, "sd_mmc") == 0)
+ s = g_strdup ("drive-removable-media-flash-sd");
+
+ if (s == NULL)
+ s = g_strdup ("drive-removable-media");
+
+ return s;
+}
+
+static void
+_do_update_from_hal (GHalDrive *d)
+{
+ d->name = _drive_get_description (d->device);
+ d->icon = _drive_get_icon (d->device);
+
+ d->uses_removable_media = hal_device_get_property_bool (d->device, "storage.removable");
+ if (d->uses_removable_media)
+ {
+ d->has_media = hal_device_get_property_bool (d->device, "storage.removable.media_available");
+ d->is_media_check_automatic = hal_device_get_property_bool (d->device, "storage.media_check_enabled");
+ d->can_poll_for_media = hal_device_has_interface (d->device, "org.freedesktop.Hal.Device.Storage.Removable");
+ d->can_eject = hal_device_get_property_bool (d->device, "storage.requires_eject");
+ }
+ else
+ {
+ d->has_media = TRUE;
+ d->is_media_check_automatic = FALSE;
+ d->can_poll_for_media = FALSE;
+ d->can_eject = FALSE;
+ }
+}
+
+static gboolean
+changed_in_idle (gpointer data)
+{
+ GHalDrive *drive = data;
+
+ g_signal_emit_by_name (drive, "changed");
+ if (drive->volume_monitor != NULL)
+ g_signal_emit_by_name (drive->volume_monitor, "drive_changed", drive);
+ g_object_unref (drive);
+
+ return FALSE;
+}
+
+static void
+_update_from_hal (GHalDrive *d, gboolean emit_changed)
+{
+ char *old_name;
+ char *old_icon;
+ gboolean old_uses_removable_media;
+ gboolean old_has_media;
+ gboolean old_is_media_check_automatic;
+ gboolean old_can_poll_for_media;
+ gboolean old_can_eject;
+
+ G_LOCK (hal_drive);
+
+ old_name = g_strdup (d->name);
+ old_icon = g_strdup (d->icon);
+ old_uses_removable_media = d->uses_removable_media;
+ old_has_media = d->has_media;
+ old_is_media_check_automatic = d->is_media_check_automatic;
+ old_can_poll_for_media = d->can_poll_for_media;
+ old_can_eject = d->can_eject;
+
+ g_free (d->name);
+ g_free (d->icon);
+ _do_update_from_hal (d);
+
+ if (emit_changed &&
+ (old_uses_removable_media != d->uses_removable_media ||
+ old_has_media != d->has_media ||
+ old_is_media_check_automatic != d->is_media_check_automatic ||
+ old_can_poll_for_media != d->can_poll_for_media ||
+ old_can_eject != d->can_eject ||
+ old_name == NULL ||
+ old_icon == NULL ||
+ strcmp (old_name, d->name) != 0 ||
+ strcmp (old_icon, d->icon) != 0))
+ g_idle_add (changed_in_idle, g_object_ref (d));
+
+ g_free (old_name);
+ g_free (old_icon);
+
+ G_UNLOCK (hal_drive);
+}
+
+static void
+hal_condition (HalDevice *device, const char *name, const char *detail, gpointer user_data)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (user_data);
+
+ if (strcmp (name, "EjectPressed") == 0)
+ {
+ g_signal_emit_by_name (hal_drive, "eject-button");
+ if (hal_drive->volume_monitor != NULL)
+ g_signal_emit_by_name (hal_drive->volume_monitor, "drive-eject-button", hal_drive);
+ }
+
+}
+
+static void
+hal_changed (HalDevice *device, const char *key, gpointer user_data)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (user_data);
+
+ /*g_warning ("volhal modifying %s (property %s changed)", hal_drive->device_path, key);*/
+ _update_from_hal (hal_drive, TRUE);
+}
+
+GHalDrive *
+g_hal_drive_new (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ HalPool *pool)
+{
+ GHalDrive *drive;
+
+ drive = g_object_new (G_TYPE_HAL_DRIVE, NULL);
+ drive->volume_monitor = volume_monitor;
+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(drive->volume_monitor));
+ drive->device_path = g_strdup (hal_device_get_property_string (device, "block.device"));
+ drive->device = g_object_ref (device);
+ drive->pool = g_object_ref (pool);
+
+ drive->name = g_strdup_printf ("Drive for %s", drive->device_path);
+ drive->icon = g_strdup_printf ("drive-removable-media");
+
+ g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, drive, 0);
+ g_signal_connect_object (device, "hal_condition", (GCallback) hal_condition, drive, 0);
+
+ _update_from_hal (drive, FALSE);
+
+ return drive;
+}
+
+void
+g_hal_drive_disconnected (GHalDrive *drive)
+{
+ GList *l, *volumes;
+
+ G_LOCK (hal_drive);
+ volumes = drive->volumes;
+ drive->volumes = NULL;
+ G_UNLOCK (hal_drive);
+
+ for (l = volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+ g_hal_volume_unset_drive (volume, drive);
+ }
+
+ g_list_free (volumes);
+}
+
+void
+g_hal_drive_set_volume (GHalDrive *drive,
+ GHalVolume *volume)
+{
+
+ G_LOCK (hal_drive);
+
+ if (g_list_find (drive->volumes, volume) == NULL)
+ {
+ drive->volumes = g_list_prepend (drive->volumes, volume);
+ g_idle_add (changed_in_idle, g_object_ref (drive));
+ }
+
+ G_UNLOCK (hal_drive);
+}
+
+void
+g_hal_drive_unset_volume (GHalDrive *drive,
+ GHalVolume *volume)
+{
+ GList *l;
+
+ G_LOCK (hal_drive);
+
+ l = g_list_find (drive->volumes, volume);
+ if (l != NULL)
+ {
+ drive->volumes = g_list_delete_link (drive->volumes, l);
+
+ g_idle_add (changed_in_idle, g_object_ref (drive));
+ }
+
+ G_UNLOCK (hal_drive);
+}
+
+gboolean
+g_hal_drive_has_udi (GHalDrive *drive, const char *udi)
+{
+ gboolean res;
+
+ G_LOCK (hal_drive);
+ res = strcmp (udi, hal_device_get_udi (drive->device)) == 0;
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+static GIcon *
+g_hal_drive_get_icon (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ GIcon *icon;
+
+ G_LOCK (hal_drive);
+ icon = g_themed_icon_new_with_default_fallbacks (hal_drive->icon);
+ G_UNLOCK (hal_drive);
+
+ return icon;
+}
+
+static char *
+g_hal_drive_get_name (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ char *name;
+
+ G_LOCK (hal_drive);
+ name = g_strdup (hal_drive->name);
+ G_UNLOCK (hal_drive);
+
+ return name;
+}
+
+static GList *
+g_hal_drive_get_volumes (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ GList *l;
+
+ G_LOCK (hal_drive);
+ l = g_list_copy (hal_drive->volumes);
+ g_list_foreach (l, (GFunc) g_object_ref, NULL);
+ G_UNLOCK (hal_drive);
+
+ return l;
+}
+
+static gboolean
+g_hal_drive_has_volumes (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ gboolean res;
+
+ G_LOCK (hal_drive);
+ res = hal_drive->volumes != NULL;
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+static gboolean
+g_hal_drive_is_media_removable (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ gboolean res;
+
+ G_LOCK (hal_drive);
+ res = hal_drive->uses_removable_media;
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+static gboolean
+g_hal_drive_has_media (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ gboolean res;
+
+ G_LOCK (hal_drive);
+ res = hal_drive->has_media;
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+static gboolean
+g_hal_drive_is_media_check_automatic (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ gboolean res;
+
+ G_LOCK (hal_drive);
+ res = hal_drive->is_media_check_automatic;
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+static gboolean
+g_hal_drive_can_eject (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ gboolean res;
+
+ G_LOCK (hal_drive);
+ res = hal_drive->can_eject;
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+static gboolean
+g_hal_drive_can_poll_for_media (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ gboolean res;
+
+ G_LOCK (hal_drive);
+ res = hal_drive->can_poll_for_media;
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
+} SpawnOp;
+
+static void
+spawn_cb (GPid pid, gint status, gpointer user_data)
+{
+ SpawnOp *data = user_data;
+ GSimpleAsyncResult *simple;
+
+
+ if (WEXITSTATUS (status) != 0)
+ {
+ GError *error;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "You are not supposed to show G_IO_ERROR_FAILED_HANDLED in the UI");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ }
+ else
+ {
+ simple = g_simple_async_result_new (data->object,
+ data->callback,
+ data->user_data,
+ NULL);
+ }
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_object_unref (data->object);
+ g_free (data);
+}
+
+static void
+g_hal_drive_eject_do (GDrive *drive,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ SpawnOp *data;
+ GPid child_pid;
+ GError *error;
+ char *argv[] = {"gnome-mount", "-e", "-b", "-d", NULL, NULL};
+
+ G_LOCK (hal_drive);
+ argv[4] = g_strdup (hal_drive->device_path);
+ G_UNLOCK (hal_drive);
+
+ data = g_new0 (SpawnOp, 1);
+ data->object = g_object_ref (drive);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->cancellable = cancellable;
+
+ error = NULL;
+ if (!g_spawn_async (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,
+ &error))
+ {
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_object_unref (drive);
+ g_error_free (error);
+ g_free (data);
+ }
+ else
+ g_child_watch_add (child_pid, spawn_cb, data);
+
+ g_free (argv[4]);
+}
+
+
+typedef struct {
+ GDrive *drive;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
+ GMountUnmountFlags flags;
+
+ GList *pending_mounts;
+} UnmountMountsOp;
+
+static void
+free_unmount_mounts_op (UnmountMountsOp *data)
+{
+ GList *l;
+
+ for (l = data->pending_mounts; l != NULL; l = l->next)
+ {
+ GMount *mount = l->data;
+ g_object_unref (mount);
+ }
+ g_list_free (data->pending_mounts);
+}
+
+static void _eject_unmount_mounts (UnmountMountsOp *data);
+
+static void
+_eject_unmount_mounts_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ UnmountMountsOp *data = user_data;
+ GMount *mount = G_MOUNT (source_object);
+ GSimpleAsyncResult *simple;
+ GError *error = NULL;
+
+ if (!g_mount_unmount_finish (mount, res, &error))
+ {
+ /* make the error dialog more targeted to the drive.. unless the user has already seen a dialog */
+ if (error->code != G_IO_ERROR_FAILED_HANDLED)
+ {
+ g_error_free (error);
+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_BUSY,
+ _("Failed to eject media; one or more volumes on the media are busy."));
+ }
+
+ /* unmount failed; need to fail the whole eject operation */
+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->drive),
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+
+ free_unmount_mounts_op (data);
+ }
+ else
+ {
+
+ /*g_warning ("successfully unmounted %p", mount);*/
+
+ /* move on to the next mount.. */
+ _eject_unmount_mounts (data);
+ }
+
+ g_object_unref (mount);
+}
+
+static void
+_eject_unmount_mounts (UnmountMountsOp *data)
+{
+ GMount *mount;
+
+ if (data->pending_mounts == NULL)
+ {
+
+ /*g_warning ("all pending mounts done; ejecting drive");*/
+
+ g_hal_drive_eject_do (data->drive,
+ data->cancellable,
+ data->callback,
+ data->user_data);
+
+ g_object_unref (data->drive);
+ g_free (data);
+ }
+ else
+ {
+ mount = data->pending_mounts->data;
+ data->pending_mounts = g_list_remove (data->pending_mounts, mount);
+
+ /*g_warning ("unmounting %p", mount);*/
+
+ g_mount_unmount (mount,
+ data->flags,
+ data->cancellable,
+ _eject_unmount_mounts_cb,
+ data);
+ }
+}
+
+static void
+g_hal_drive_eject (GDrive *drive,
+ GMountUnmountFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ UnmountMountsOp *data;
+ GList *l;
+
+ /* first we need to go through all the volumes and unmount their assoicated mounts (if any) */
+
+ data = g_new0 (UnmountMountsOp, 1);
+ data->drive = g_object_ref (drive);
+ data->cancellable = cancellable;
+ data->callback = callback;
+ data->user_data = user_data;
+ data->flags = flags;
+
+ G_LOCK (hal_drive);
+ for (l = hal_drive->volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+ GMount *mount; /* the mount may be foreign; cannot assume GHalMount */
+
+ mount = g_volume_get_mount (G_VOLUME (volume));
+ if (mount != NULL && g_mount_can_unmount (mount))
+ data->pending_mounts = g_list_prepend (data->pending_mounts, g_object_ref (mount));
+ }
+ G_UNLOCK (hal_drive);
+
+ _eject_unmount_mounts (data);
+}
+
+static gboolean
+g_hal_drive_eject_finish (GDrive *drive,
+ GAsyncResult *result,
+ GError **error)
+{
+ return TRUE;
+}
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
+} PollOp;
+
+static void
+poll_for_media_cb (DBusPendingCall *pending_call, void *user_data)
+{
+ PollOp *data = (PollOp *) user_data;
+ GSimpleAsyncResult *simple;
+ DBusMessage *reply;
+
+ reply = dbus_pending_call_steal_reply (pending_call);
+
+ if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ GError *error;
+ DBusError dbus_error;
+
+ dbus_error_init (&dbus_error);
+ dbus_set_error_from_message (&dbus_error, reply);
+ error = g_error_new (G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Cannot invoke CheckForMedia on HAL: %s: %s", dbus_error.name, dbus_error.message);
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_error_free (error);
+ dbus_error_free (&dbus_error);
+ goto out;
+ }
+
+ /* TODO: parse reply and extract result?
+ * (the result is whether the media availability state changed)
+ */
+
+ simple = g_simple_async_result_new (data->object,
+ data->callback,
+ data->user_data,
+ NULL);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+
+ out:
+ g_object_unref (data->object);
+ dbus_message_unref (reply);
+ dbus_pending_call_unref (pending_call);
+}
+
+
+static void
+g_hal_drive_poll_for_media (GDrive *drive,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ DBusConnection *con;
+ DBusMessage *msg;
+ DBusPendingCall *pending_call;
+ PollOp *data;
+
+ data = g_new0 (PollOp, 1);
+ data->object = g_object_ref (drive);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->cancellable = cancellable;
+
+ /*g_warning ("Rescanning udi %s", hal_device_get_udi (hal_drive->device));*/
+
+ G_LOCK (hal_drive);
+ con = hal_pool_get_dbus_connection (hal_drive->pool);
+ msg = dbus_message_new_method_call ("org.freedesktop.Hal",
+ hal_device_get_udi (hal_drive->device),
+ "org.freedesktop.Hal.Device.Storage.Removable",
+ "CheckForMedia");
+ G_UNLOCK (hal_drive);
+
+ if (!dbus_connection_send_with_reply (con, msg, &pending_call, -1))
+ {
+ GError *error;
+ GSimpleAsyncResult *simple;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Cannot invoke CheckForMedia on HAL");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_error_free (error);
+ g_object_unref (data->object);
+ g_free (data);
+ }
+ else
+ dbus_pending_call_set_notify (pending_call,
+ poll_for_media_cb,
+ data,
+ (DBusFreeFunction) g_free);
+
+ dbus_message_unref (msg);
+}
+
+static gboolean
+g_hal_drive_poll_for_media_finish (GDrive *drive,
+ GAsyncResult *result,
+ GError **error)
+{
+ /*g_warning ("poll finish");*/
+ return TRUE;
+}
+
+static char *
+g_hal_drive_get_identifier (GDrive *drive,
+ const char *kind)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ char *res;
+
+ res = NULL;
+
+ G_LOCK (hal_drive);
+
+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_HAL_UDI) == 0)
+ res = g_strdup (hal_device_get_udi (hal_drive->device));
+
+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
+ res = g_strdup (hal_drive->device_path);
+
+ G_UNLOCK (hal_drive);
+
+ return res;
+}
+
+static char **
+g_hal_drive_enumerate_identifiers (GDrive *drive)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (drive);
+ GPtrArray *res;
+
+ res = g_ptr_array_new ();
+
+ G_LOCK (hal_drive);
+
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_HAL_UDI));
+
+ if (hal_drive->device_path && *hal_drive->device_path != 0)
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
+
+
+ G_UNLOCK (hal_drive);
+
+ /* Null-terminate */
+ g_ptr_array_add (res, NULL);
+
+ return (char **)g_ptr_array_free (res, FALSE);
+}
+
+static void
+g_hal_drive_drive_iface_init (GDriveIface *iface)
+{
+ iface->get_name = g_hal_drive_get_name;
+ iface->get_icon = g_hal_drive_get_icon;
+ iface->has_volumes = g_hal_drive_has_volumes;
+ iface->get_volumes = g_hal_drive_get_volumes;
+ iface->is_media_removable = g_hal_drive_is_media_removable;
+ iface->has_media = g_hal_drive_has_media;
+ iface->is_media_check_automatic = g_hal_drive_is_media_check_automatic;
+ iface->can_eject = g_hal_drive_can_eject;
+ iface->can_poll_for_media = g_hal_drive_can_poll_for_media;
+ iface->eject = g_hal_drive_eject;
+ iface->eject_finish = g_hal_drive_eject_finish;
+ iface->poll_for_media = g_hal_drive_poll_for_media;
+ iface->poll_for_media_finish = g_hal_drive_poll_for_media_finish;
+ iface->get_identifier = g_hal_drive_get_identifier;
+ iface->enumerate_identifiers = g_hal_drive_enumerate_identifiers;
+}
diff --git a/gnome-2-24/monitor/hal/ghaldrive.h b/gnome-2-24/monitor/hal/ghaldrive.h
new file mode 100644
index 00000000..7832db59
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghaldrive.h
@@ -0,0 +1,62 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#ifndef __G_HAL_DRIVE_H__
+#define __G_HAL_DRIVE_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "hal-pool.h"
+#include "ghalvolumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_HAL_DRIVE (g_hal_drive_get_type ())
+#define G_HAL_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_HAL_DRIVE, GHalDrive))
+#define G_HAL_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_HAL_DRIVE, GHalDriveClass))
+#define G_IS_HAL_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_HAL_DRIVE))
+#define G_IS_HAL_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_HAL_DRIVE))
+
+typedef struct _GHalDriveClass GHalDriveClass;
+
+struct _GHalDriveClass {
+ GObjectClass parent_class;
+};
+
+GType g_hal_drive_get_type (void) G_GNUC_CONST;
+
+GHalDrive *g_hal_drive_new (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ HalPool *pool);
+gboolean g_hal_drive_has_udi (GHalDrive *drive,
+ const char *udi);
+void g_hal_drive_set_volume (GHalDrive *drive,
+ GHalVolume *volume);
+void g_hal_drive_unset_volume (GHalDrive *drive,
+ GHalVolume *volume);
+void g_hal_drive_disconnected (GHalDrive *drive);
+char * _drive_get_icon (HalDevice *d);
+
+G_END_DECLS
+
+#endif /* __G_HAL_DRIVE_H__ */
diff --git a/gnome-2-24/monitor/hal/ghalmount.c b/gnome-2-24/monitor/hal/ghalmount.c
new file mode 100644
index 00000000..138c9a10
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghalmount.c
@@ -0,0 +1,1592 @@
+/* -*- 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "ghalvolumemonitor.h"
+#include "ghalmount.h"
+#include "ghalvolume.h"
+
+#include "hal-utils.h"
+
+/* Protects all fields of GHalDrive that can change */
+G_LOCK_DEFINE_STATIC(hal_mount);
+
+struct _GHalMount {
+ GObject parent;
+
+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */
+ GHalVolume *volume; /* owned by volume monitor */
+
+ char *name;
+ GIcon *icon;
+ char *device_path;
+ char *mount_path;
+
+ char *uuid;
+
+ char *override_name;
+ GIcon *override_icon;
+ GFile *override_root;
+ gboolean cannot_unmount;
+ gboolean searched_for_icon;
+
+ HalDevice *device;
+ HalDevice *drive_device;
+};
+
+static GFile *
+_g_find_file_insensitive_finish (GFile *parent,
+ GAsyncResult *result,
+ GError **error);
+
+static void
+_g_find_file_insensitive_async (GFile *parent,
+ const gchar *name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+
+static GFile *get_root (GHalMount *hal_mount);
+
+static void g_hal_mount_mount_iface_init (GMountIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GHalMount, g_hal_mount, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,
+ g_hal_mount_mount_iface_init))
+
+static void
+g_hal_mount_finalize (GObject *object)
+{
+ GHalMount *mount;
+
+ mount = G_HAL_MOUNT (object);
+
+ if (mount->volume != NULL)
+ g_hal_volume_unset_mount (mount->volume, mount);
+
+ g_free (mount->device_path);
+ g_free (mount->mount_path);
+ g_free (mount->uuid);
+
+ if (mount->device != NULL)
+ g_object_unref (mount->device);
+ if (mount->drive_device != NULL)
+ g_object_unref (mount->drive_device);
+
+ g_free (mount->name);
+ if (mount->icon != NULL)
+ g_object_unref (mount->icon);
+
+ g_free (mount->override_name);
+ if (mount->override_icon != NULL)
+ g_object_unref (mount->override_icon);
+
+ if (mount->override_root != NULL)
+ g_object_unref (mount->override_root);
+
+ if (mount->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (mount->volume_monitor), (gpointer) &(mount->volume_monitor));
+
+ if (G_OBJECT_CLASS (g_hal_mount_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_hal_mount_parent_class)->finalize) (object);
+}
+
+static void
+g_hal_mount_class_init (GHalMountClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_hal_mount_finalize;
+}
+
+static void
+g_hal_mount_init (GHalMount *hal_mount)
+{
+}
+
+static gboolean
+changed_in_idle (gpointer data)
+{
+ GHalMount *mount = data;
+
+ g_signal_emit_by_name (mount, "changed");
+ if (mount->volume_monitor != NULL)
+ g_signal_emit_by_name (mount->volume_monitor, "mount_changed", mount);
+ g_object_unref (mount);
+
+ return FALSE;
+}
+
+typedef struct _MountIconSearchData
+{
+ GHalMount *mount;
+ GFile *root;
+} MountIconSearchData;
+
+static void
+clear_icon_search_data (MountIconSearchData *data)
+{
+ if (data->mount)
+ g_object_unref (data->mount);
+ if (data->root)
+ g_object_unref (data->root);
+ g_free (data);
+}
+
+static void
+on_icon_file_located (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ GFile *icon_file;
+ GIcon *icon;
+ MountIconSearchData *data = (MountIconSearchData *) (user_data);
+
+ icon_file = _g_find_file_insensitive_finish (G_FILE (source_object),
+ res, NULL);
+
+ /* TODO: check if the file actually exists? */
+
+ icon = g_file_icon_new (icon_file);
+ g_object_unref (icon_file);
+
+ g_hal_mount_override_icon (data->mount, icon);
+ g_object_unref (icon);
+
+ clear_icon_search_data (data);
+}
+
+static void
+on_autorun_loaded (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ gchar *content, *relative_icon_path = NULL;
+ gsize content_length;
+ MountIconSearchData *data = (MountIconSearchData *) (user_data);
+
+ if (g_file_load_contents_finish (G_FILE (source_object), res, &content,
+ &content_length, NULL, NULL))
+ {
+ /* Scan through for an "icon=" line. Can't use GKeyFile,
+ * because .inf files aren't always valid key files
+ **/
+ GRegex *icon_regex;
+ GMatchInfo *match_info;
+
+ /* [^,] is because sometimes the icon= line
+ * has a comma at the end
+ **/
+ icon_regex = g_regex_new ("icon=([^,\\r\\n]+)",
+ G_REGEX_CASELESS, 0, NULL);
+ g_regex_match (icon_regex, content, 0,
+ &match_info);
+
+ /* Even if there are multiple matches, pick only the
+ * first.
+ **/
+ if (g_match_info_matches (match_info))
+ {
+ gchar *chr;
+ gchar *word = g_match_info_fetch (match_info, 1);
+
+ /* Replace '\' with '/' */
+ while ((chr = strchr (word, '\\')) != NULL)
+ *chr = '/';
+
+ /* If the file name's not valid UTF-8,
+ * don't even try to load it
+ **/
+ if (g_utf8_validate (word, -1, NULL))
+ relative_icon_path = word;
+ else
+ g_free (word);
+ }
+
+ g_match_info_free (match_info);
+
+ g_regex_unref (icon_regex);
+ g_free (content);
+ }
+
+ /* some autorun.in points to the .exe file for the icon; make sure we avoid using that */
+ if (relative_icon_path && !g_str_has_suffix (relative_icon_path, ".exe"))
+ {
+ _g_find_file_insensitive_async (data->root,
+ relative_icon_path,
+ NULL, on_icon_file_located,
+ data);
+
+ g_free (relative_icon_path);
+ }
+ else
+ clear_icon_search_data (data);
+}
+
+static void
+on_autorun_located (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ GFile *autorun_path;
+ MountIconSearchData *data = (MountIconSearchData *) (user_data);
+
+ autorun_path = _g_find_file_insensitive_finish (G_FILE (source_object),
+ res, NULL);
+ if (autorun_path)
+ g_file_load_contents_async (autorun_path, NULL, on_autorun_loaded, data);
+ else
+ clear_icon_search_data (data);
+
+ g_object_unref (autorun_path);
+}
+
+static void
+_g_find_mount_icon (GHalMount *m)
+{
+ MountIconSearchData *search_data;
+
+ m->searched_for_icon = TRUE;
+
+ search_data = g_new0 (MountIconSearchData, 1);
+ search_data->mount = g_object_ref (m);
+ search_data->root = get_root (m);
+
+ _g_find_file_insensitive_async (search_data->root,
+ "autorun.inf",
+ NULL, on_autorun_located,
+ search_data);
+}
+
+#define KILOBYTE_FACTOR 1000.0
+#define MEGABYTE_FACTOR (1000.0 * 1000.0)
+#define GIGABYTE_FACTOR (1000.0 * 1000.0 * 1000.0)
+
+static char *
+format_size_for_display (guint64 size)
+{
+ char *str;
+ gdouble displayed_size;
+
+ if (size < MEGABYTE_FACTOR)
+ {
+ displayed_size = (double) size / KILOBYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f kB"), displayed_size);
+ }
+ else if (size < GIGABYTE_FACTOR)
+ {
+ displayed_size = (double) size / MEGABYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f MB"), displayed_size);
+ }
+ else
+ {
+ displayed_size = (double) size / GIGABYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f GB"), displayed_size);
+ }
+
+ return str;
+}
+
+static void
+do_update_from_hal (GHalMount *m)
+{
+ HalDevice *volume;
+ HalDevice *drive;
+ char *name;
+ const char *icon_name;
+ const char *icon_name_fallback;
+ const char *drive_type;
+ const char *drive_bus;
+ gboolean drive_uses_removable_media;
+ const char *volume_fs_label;
+ guint64 volume_size;
+ gboolean volume_is_disc;
+ gboolean volume_disc_has_audio;
+ gboolean volume_disc_has_data;
+ const char *volume_disc_type;
+ gboolean volume_disc_is_blank;
+ gboolean is_audio_player;
+ const char *icon_from_hal;
+ const char *volume_icon_from_hal;
+ const char *name_from_hal;
+ const char *volume_name_from_hal;
+ gboolean is_crypto;
+ gboolean is_crypto_cleartext;
+
+ volume = m->device;
+ drive = m->drive_device;
+
+ drive_type = hal_device_get_property_string (drive, "storage.drive_type");
+ drive_bus = hal_device_get_property_string (drive, "storage.bus");
+ drive_uses_removable_media = hal_device_get_property_bool (drive, "storage.removable");
+ volume_fs_label = hal_device_get_property_string (volume, "volume.label");
+ volume_size = hal_device_get_property_uint64 (volume, "volume.size");
+ volume_is_disc = hal_device_get_property_bool (volume, "volume.is_disc");
+ volume_disc_has_audio = hal_device_get_property_bool (volume, "volume.disc.has_audio");
+ volume_disc_has_data = hal_device_get_property_bool (volume, "volume.disc.has_data");
+ volume_disc_is_blank = hal_device_get_property_bool (volume, "volume.disc.is_blank");
+ volume_disc_type = hal_device_get_property_string (volume, "volume.disc.type");
+ is_audio_player = hal_device_has_capability (drive, "portable_audio_player");
+ icon_from_hal = hal_device_get_property_string (drive, "info.desktop.icon");
+ volume_icon_from_hal = hal_device_get_property_string (volume, "info.desktop.icon");
+ name_from_hal = hal_device_get_property_string (drive, "info.desktop.name");
+ volume_name_from_hal = hal_device_get_property_string (volume, "info.desktop.name");
+
+ is_crypto = FALSE;
+ is_crypto_cleartext = FALSE;
+ if (strcmp (hal_device_get_property_string (volume, "volume.fsusage"), "crypto") == 0)
+ is_crypto = TRUE;
+
+ if (strlen (hal_device_get_property_string (volume, "volume.crypto_luks.clear.backing_volume")) > 0)
+ is_crypto_cleartext = TRUE;
+
+ /*g_warning ("drive_type='%s'", drive_type); */
+ /*g_warning ("drive_bus='%s'", drive_bus); */
+ /*g_warning ("drive_uses_removable_media=%d", drive_uses_removable_media); */
+
+ icon_name_fallback = NULL;
+
+ if (strlen (volume_icon_from_hal) > 0)
+ icon_name = volume_icon_from_hal;
+ else if (strlen (icon_from_hal) > 0)
+ icon_name = icon_from_hal;
+ else if (is_audio_player)
+ icon_name = "multimedia-player";
+ else if (strcmp (drive_type, "disk") == 0)
+ {
+ if (strcmp (drive_bus, "ide") == 0)
+ icon_name = "drive-harddisk-ata";
+ else if (strcmp (drive_bus, "scsi") == 0)
+ icon_name = "drive-harddisk-scsi";
+ else if (strcmp (drive_bus, "ieee1394") == 0)
+ icon_name = "drive-harddisk-ieee1394";
+ else if (strcmp (drive_bus, "usb") == 0)
+ icon_name = "drive-harddisk-usb";
+ else
+ icon_name = "drive-harddisk";
+ }
+ else if (strcmp (drive_type, "cdrom") == 0)
+ icon_name = get_disc_icon (volume_disc_type);
+ else if (strcmp (drive_type, "floppy") == 0)
+ icon_name = "media-floppy";
+ else if (strcmp (drive_type, "tape") == 0)
+ icon_name = "media-tape";
+ else if (strcmp (drive_type, "compact_flash") == 0)
+ icon_name = "media-flash-cf";
+ else if (strcmp (drive_type, "memory_stick") == 0)
+ icon_name = "media-flash-ms";
+ else if (strcmp (drive_type, "smart_media") == 0)
+ icon_name = "media-flash-sm";
+ else if (strcmp (drive_type, "sd_mmc") == 0)
+ icon_name = "media-flash-sd";
+ else
+ icon_name = "drive-harddisk";
+
+ /* Create default fallbacks for the icon_name by default
+ * with get_themed_icon_with_fallbacks () */
+ icon_name_fallback = icon_name;
+
+ /* Note: we are not chaning the default fallbacks
+ * so we get all the fallbacks if the media-encrytped
+ * icon is not there */
+ if (is_crypto || is_crypto_cleartext)
+ icon_name = "media-encrypted";
+
+ if (strlen (volume_name_from_hal) > 0)
+ name = g_strdup (volume_name_from_hal);
+ else if (strlen (name_from_hal) > 0)
+ name = g_strdup (name_from_hal);
+ else if (volume_fs_label != NULL && strlen (volume_fs_label) > 0)
+ name = g_strdup (volume_fs_label);
+ else if (volume_is_disc)
+ {
+ if (volume_disc_has_audio)
+ {
+ if (volume_disc_has_data)
+ name = g_strdup (_("Mixed Audio/Data Disc"));
+ else
+ name = g_strdup (_("Audio Disc"));
+ }
+ else
+ name = g_strdup (get_disc_name (volume_disc_type, volume_disc_is_blank));
+ }
+ else
+ {
+ char *size;
+
+ size = format_size_for_display (volume_size);
+ /* Translators: %s is the size of the mount (e.g. 512 MB) */
+ name = g_strdup_printf (_("%s Media"), size);
+ g_free (size);
+ }
+
+ if (m->override_name != NULL)
+ {
+ m->name = g_strdup (m->override_name);
+ g_free (name);
+ }
+ else
+ m->name = name;
+
+ if (m->override_icon != NULL)
+ m->icon = g_object_ref (m->override_icon);
+ else
+ m->icon = get_themed_icon_with_fallbacks (icon_name,
+ icon_name_fallback);
+
+ /* If this is a CD-ROM, begin searching for an icon specified in
+ * autorun.inf.
+ **/
+ if (strcmp (drive_type, "cdrom") == 0 && !m->searched_for_icon)
+ _g_find_mount_icon (m);
+}
+
+
+static void
+update_from_hal (GHalMount *m, gboolean emit_changed)
+{
+ char *old_name;
+ GIcon *old_icon;
+
+ G_LOCK (hal_mount);
+
+ old_name = g_strdup (m->name);
+ old_icon = m->icon != NULL ? g_object_ref (m->icon) : NULL;
+
+ g_free (m->name);
+ if (m->icon != NULL)
+ g_object_unref (m->icon);
+ do_update_from_hal (m);
+
+ if (emit_changed)
+ {
+ if (old_name == NULL ||
+ old_icon == NULL ||
+ strcmp (old_name, m->name) != 0 ||
+ (! g_icon_equal (old_icon, m->icon)))
+ g_idle_add (changed_in_idle, g_object_ref (m));
+ }
+ g_free (old_name);
+ if (old_icon != NULL)
+ g_object_unref (old_icon);
+
+ G_UNLOCK (hal_mount);
+}
+
+static void
+hal_changed (HalDevice *device, const char *key, gpointer user_data)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (user_data);
+
+ /*g_warning ("mounthal modifying %s (property %s changed)", hal_mount->device_path, key); */
+ update_from_hal (hal_mount, TRUE);
+}
+
+static void
+compute_uuid (GHalMount *mount)
+{
+ const char *fs_uuid;
+ const char *fs_label;
+
+ /* use the FS uuid before falling back to the FS label */
+
+ fs_uuid = hal_device_get_property_string (mount->device, "volume.uuid");
+ fs_label = hal_device_get_property_string (mount->device, "volume.label");
+
+ if (strlen (fs_uuid) == 0)
+ {
+ if (strlen (fs_label) == 0)
+ mount->uuid = NULL;
+ else
+ mount->uuid = g_strdup (fs_label);
+ }
+ else
+ mount->uuid = g_strdup (fs_uuid);
+}
+
+
+GHalMount *
+g_hal_mount_new_for_hal_device (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ GFile *override_root,
+ const char *override_name,
+ GIcon *override_icon,
+ gboolean cannot_unmount,
+ HalPool *pool,
+ GHalVolume *volume)
+{
+ HalDevice *drive_device;
+ const char *storage_udi;
+ GHalMount *mount;
+
+ storage_udi = hal_device_get_property_string (device, "block.storage_device");
+ if (storage_udi == NULL)
+ goto fail;
+
+ /* g_warning ("storage_udi = %s", storage_udi); */
+
+ drive_device = hal_pool_get_device_by_udi (pool, storage_udi);
+ if (drive_device == NULL)
+ goto fail;
+
+ /* g_warning ("drive_device = %p", drive_device); */
+
+ mount = g_object_new (G_TYPE_HAL_MOUNT, NULL);
+ mount->volume_monitor = volume_monitor;
+ g_object_add_weak_pointer (G_OBJECT (mount->volume_monitor), (gpointer) &(mount->volume_monitor));
+ mount->device_path = g_strdup (hal_device_get_property_string (device, "block.device"));
+ mount->mount_path = g_strdup ("/");
+ mount->device = g_object_ref (device);
+ mount->drive_device = g_object_ref (drive_device);
+ mount->override_root = override_root != NULL ? g_object_ref (override_root) : NULL;
+ mount->override_icon = override_icon != NULL ? g_object_ref (override_icon) : NULL;
+ mount->override_name = g_strdup (override_name);
+ mount->cannot_unmount = cannot_unmount;
+
+ g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, mount, 0);
+ g_signal_connect_object (drive_device, "hal_property_changed", (GCallback) hal_changed, mount, 0);
+
+ compute_uuid (mount);
+ update_from_hal (mount, FALSE);
+
+ /* need to do this last */
+ mount->volume = volume;
+ if (volume != NULL)
+ g_hal_volume_set_mount (volume, mount);
+
+ return mount;
+
+ fail:
+ return NULL;
+}
+
+void
+g_hal_mount_override_name (GHalMount *mount, const char *name)
+{
+ G_LOCK (hal_mount);
+
+ g_free (mount->override_name);
+
+ if (name != NULL)
+ mount->override_name = g_strdup (name);
+ else
+ mount->override_name = NULL;
+
+ G_UNLOCK (hal_mount);
+
+ update_from_hal (mount, TRUE);
+}
+
+void
+g_hal_mount_override_icon (GHalMount *mount, GIcon *icon)
+{
+ G_LOCK (hal_mount);
+ if (mount->override_icon != NULL)
+ g_object_unref (mount->override_icon);
+
+ if (icon != NULL)
+ mount->override_icon = g_object_ref (icon);
+ else
+ mount->override_icon = NULL;
+
+ G_UNLOCK (hal_mount);
+
+ update_from_hal (mount, TRUE);
+}
+
+GHalMount *
+g_hal_mount_new (GVolumeMonitor *volume_monitor,
+ GUnixMountEntry *mount_entry,
+ HalPool *pool,
+ GHalVolume *volume)
+{
+ HalDevice *device;
+ HalDevice *drive_device;
+ const char *storage_udi;
+ GHalMount *mount;
+
+ /* If no volume for mount - Ignore internal things */
+ if (volume == NULL && !g_unix_mount_guess_should_display (mount_entry))
+ return NULL;
+
+ mount = g_object_new (G_TYPE_HAL_MOUNT, NULL);
+ mount->volume_monitor = volume_monitor;
+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(mount->volume_monitor));
+ mount->device_path = g_strdup (g_unix_mount_get_device_path (mount_entry));
+ mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry));
+ mount->device = NULL;
+ mount->drive_device = NULL;
+ mount->uuid = NULL;
+
+ if (pool != NULL)
+ {
+ device = hal_pool_get_device_by_capability_and_string (pool,
+ "volume",
+ "block.device",
+ mount->device_path);
+ /* g_warning ("device = %p for %s", device, mount->device_path); */
+ if (device != NULL)
+ {
+ /* g_warning ("udi = %s", hal_device_get_udi (device)); */
+
+ storage_udi = hal_device_get_property_string (device, "block.storage_device");
+ if (storage_udi == NULL)
+ goto not_hal;
+
+ /* g_warning ("storage_udi = %s", storage_udi); */
+
+ drive_device = hal_pool_get_device_by_udi (pool, storage_udi);
+ if (drive_device == NULL)
+ goto not_hal;
+
+ /* g_warning ("drive_device = %p", drive_device); */
+
+ mount->device = g_object_ref (device);
+ mount->drive_device = g_object_ref (drive_device);
+
+ g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, mount, 0);
+ g_signal_connect_object (drive_device, "hal_property_changed", (GCallback) hal_changed, mount, 0);
+
+ compute_uuid (mount);
+ update_from_hal (mount, FALSE);
+
+ goto was_hal;
+ }
+ }
+
+ not_hal:
+
+ if (volume != NULL)
+ {
+ g_object_unref (mount);
+ return NULL;
+ }
+
+ mount->name = g_unix_mount_guess_name (mount_entry);
+ mount->icon = g_unix_mount_guess_icon (mount_entry);
+
+ was_hal:
+
+ /* need to do this last */
+ mount->volume = volume;
+ if (volume != NULL)
+ g_hal_volume_set_mount (volume, mount);
+
+ return mount;
+}
+
+void
+g_hal_mount_unmounted (GHalMount *mount)
+{
+ G_LOCK (hal_mount);
+ if (mount->volume != NULL)
+ {
+ g_hal_volume_unset_mount (mount->volume, mount);
+ mount->volume = NULL;
+ g_idle_add (changed_in_idle, g_object_ref (mount));
+ }
+ G_UNLOCK (hal_mount);
+}
+
+void
+g_hal_mount_unset_volume (GHalMount *mount,
+ GHalVolume *volume)
+{
+ G_LOCK (hal_mount);
+ if (mount->volume == volume)
+ {
+ mount->volume = NULL;
+ g_idle_add (changed_in_idle, g_object_ref (mount));
+ }
+ G_UNLOCK (hal_mount);
+}
+
+static GFile *
+get_root (GHalMount *hal_mount)
+{
+ if (hal_mount->override_root != NULL)
+ return g_object_ref (hal_mount->override_root);
+ else
+ return g_file_new_for_path (hal_mount->mount_path);
+}
+
+static GFile *
+g_hal_mount_get_root (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GFile *root;
+
+ G_LOCK (hal_mount);
+ root = get_root (hal_mount);
+ G_UNLOCK (hal_mount);
+
+ return root;
+}
+
+static GIcon *
+g_hal_mount_get_icon (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GIcon *icon;
+
+ G_LOCK (hal_mount);
+ icon = g_object_ref (hal_mount->icon);
+ G_UNLOCK (hal_mount);
+
+ return icon;
+}
+
+static char *
+g_hal_mount_get_uuid (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ char *uuid;
+
+ G_LOCK (hal_mount);
+ uuid = g_strdup (hal_mount->uuid);
+ G_UNLOCK (hal_mount);
+
+ return uuid;
+}
+
+static char *
+g_hal_mount_get_name (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ char *name;
+
+ G_LOCK (hal_mount);
+ name = g_strdup (hal_mount->name);
+ G_UNLOCK (hal_mount);
+
+ return name;
+}
+
+gboolean
+g_hal_mount_has_uuid (GHalMount *mount,
+ const char *uuid)
+{
+ gboolean res;
+
+ G_LOCK (hal_mount);
+ res = FALSE;
+ if (mount->uuid != NULL)
+ res = strcmp (mount->uuid, uuid) == 0;
+ G_UNLOCK (hal_mount);
+
+ return res;
+}
+
+gboolean
+g_hal_mount_has_mount_path (GHalMount *mount,
+ const char *mount_path)
+{
+ gboolean res;
+
+ G_LOCK (hal_mount);
+ res = strcmp (mount->mount_path, mount_path) == 0;
+ G_UNLOCK (hal_mount);
+ return res;
+}
+
+gboolean
+g_hal_mount_has_udi (GHalMount *mount,
+ const char *udi)
+{
+ gboolean res;
+
+ G_LOCK (hal_mount);
+ res = FALSE;
+ if (mount->device != NULL)
+ res = strcmp (hal_device_get_udi (mount->device), udi) == 0;
+ G_UNLOCK (hal_mount);
+
+ return res;
+}
+
+static GDrive *
+g_hal_mount_get_drive (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GDrive *drive;
+
+ G_LOCK (hal_mount);
+ drive = NULL;
+ if (hal_mount->volume != NULL)
+ drive = g_volume_get_drive (G_VOLUME (hal_mount->volume));
+ G_UNLOCK (hal_mount);
+
+ return drive;
+}
+
+static GVolume *
+g_hal_mount_get_volume (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GVolume *volume;
+
+ G_LOCK (hal_mount);
+ volume = NULL;
+ if (hal_mount->volume)
+ volume = G_VOLUME (g_object_ref (hal_mount->volume));
+ G_UNLOCK (hal_mount);
+
+ return volume;
+}
+
+static gboolean
+g_hal_mount_can_unmount (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ gboolean res;
+
+ G_LOCK (hal_mount);
+ res = TRUE;
+ if (hal_mount->cannot_unmount)
+ res = FALSE;
+ G_UNLOCK (hal_mount);
+
+ return res;
+}
+
+static gboolean
+g_hal_mount_can_eject (GMount *mount)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GDrive *drive;
+ gboolean can_eject;
+
+ G_LOCK (hal_mount);
+ can_eject = FALSE;
+ if (hal_mount->volume != NULL)
+ {
+ drive = g_volume_get_drive (G_VOLUME (hal_mount->volume));
+ if (drive != NULL)
+ can_eject = g_drive_can_eject (drive);
+ }
+ G_UNLOCK (hal_mount);
+
+ return can_eject;
+}
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
+ int error_fd;
+ GIOChannel *error_channel;
+ guint error_channel_source_id;
+ GString *error_string;
+ gboolean using_legacy;
+} UnmountOp;
+
+static void
+unmount_cb (GPid pid, gint status, gpointer user_data)
+{
+ UnmountOp *data = user_data;
+ GSimpleAsyncResult *simple;
+
+ if (WEXITSTATUS (status) != 0)
+ {
+ if (data->using_legacy)
+ {
+ 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 (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ }
+ else
+ {
+ GError *error;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "You are not supposed to show G_IO_ERROR_FAILED_HANDLED in the UI");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ }
+ }
+ else
+ {
+ simple = g_simple_async_result_new (data->object,
+ 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_object_unref (data->object);
+ g_free (data);
+}
+
+static gboolean
+unmount_read_error (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ 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
+unmount_do (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ char **argv,
+ gboolean using_legacy)
+{
+ UnmountOp *data;
+ GPid child_pid;
+ GError *error;
+
+ data = g_new0 (UnmountOp, 1);
+ data->object = g_object_ref (mount);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->cancellable = cancellable;
+ data->using_legacy = using_legacy;
+
+ 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 (data->object,
+ 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 void
+g_hal_mount_unmount (GMount *mount,
+ GMountUnmountFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ char *argv[] = {"gnome-mount", "-u", "-b", "-d", NULL, NULL};
+ gboolean using_legacy = FALSE;
+ char *d, *m;
+
+ G_LOCK (hal_mount);
+ d = g_strdup (hal_mount->device_path);
+ m = g_strdup (hal_mount->mount_path);
+ G_UNLOCK (hal_mount);
+
+
+ if (hal_mount->device != NULL)
+ argv[4] = d;
+ else
+ {
+ using_legacy = TRUE;
+ argv[0] = "umount";
+ argv[1] = m;
+ argv[2] = NULL;
+ }
+
+ unmount_do (mount, cancellable, callback, user_data, argv, using_legacy);
+ g_free (d);
+ g_free (m);
+}
+
+static gboolean
+g_hal_mount_unmount_finish (GMount *mount,
+ GAsyncResult *result,
+ GError **error)
+{
+ return TRUE;
+}
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} EjectWrapperOp;
+
+static void
+eject_wrapper_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EjectWrapperOp *data = user_data;
+ data->callback (data->object, res, data->user_data);
+ g_object_unref (data->object);
+ g_free (data);
+}
+
+static void
+g_hal_mount_eject (GMount *mount,
+ GMountUnmountFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GDrive *drive;
+
+ G_LOCK (hal_mount);
+ drive = NULL;
+ if (hal_mount->volume != NULL)
+ drive = g_volume_get_drive (G_VOLUME (hal_mount->volume));
+ G_UNLOCK (hal_mount);
+
+ if (drive != NULL)
+ {
+ EjectWrapperOp *data;
+ data = g_new0 (EjectWrapperOp, 1);
+ data->object = g_object_ref (mount);
+ data->callback = callback;
+ data->user_data = user_data;
+ g_drive_eject (drive, flags, cancellable, eject_wrapper_callback, data);
+ g_object_unref (drive);
+ }
+}
+
+static gboolean
+g_hal_mount_eject_finish (GMount *mount,
+ GAsyncResult *result,
+ GError **error)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GDrive *drive;
+ gboolean res;
+
+ res = TRUE;
+
+ G_LOCK (hal_mount);
+ drive = NULL;
+ if (hal_mount->volume != NULL)
+ drive = g_volume_get_drive (G_VOLUME (hal_mount->volume));
+ G_UNLOCK (hal_mount);
+
+ if (drive != NULL)
+ {
+ res = g_drive_eject_finish (drive, result, error);
+ g_object_unref (drive);
+ }
+ return res;
+}
+
+/* TODO: handle force_rescan */
+static char **
+g_hal_mount_guess_content_type_sync (GMount *mount,
+ gboolean force_rescan,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ const char *disc_type;
+ char **x_content_types;
+ GFile *root;
+ GPtrArray *p;
+ char **result;
+ int n;
+ char **caps;
+ char *uri;
+
+ p = g_ptr_array_new ();
+
+ G_LOCK (hal_mount);
+
+ root = get_root (hal_mount);
+ uri = g_file_get_uri (root);
+ if (g_str_has_prefix (uri, "burn://"))
+ {
+ /* doesn't make sense to probe burn:/// - look at the disc type instead */
+ if (hal_mount->device != NULL)
+ {
+ disc_type = hal_device_get_property_string (hal_mount->device, "volume.disc.type");
+ if (disc_type != NULL)
+ {
+ if (g_str_has_prefix (disc_type, "dvd"))
+ g_ptr_array_add (p, g_strdup ("x-content/blank-dvd"));
+ else if (g_str_has_prefix (disc_type, "hddvd"))
+ g_ptr_array_add (p, g_strdup ("x-content/blank-hddvd"));
+ else if (g_str_has_prefix (disc_type, "bd"))
+ g_ptr_array_add (p, g_strdup ("x-content/blank-bd"));
+ else
+ g_ptr_array_add (p, g_strdup ("x-content/blank-cd")); /* assume CD */
+ }
+ }
+ }
+ else
+ {
+ /* sniff content type */
+ x_content_types = g_content_type_guess_for_tree (root);
+ if (x_content_types != NULL)
+ {
+ for (n = 0; x_content_types[n] != NULL; n++)
+ g_ptr_array_add (p, g_strdup (x_content_types[n]));
+ g_strfreev (x_content_types);
+ }
+ }
+ g_object_unref (root);
+ g_free (uri);
+
+ /* also add content types from hal capabilities */
+ if (hal_mount->drive_device != NULL)
+ {
+ caps = dupv_and_uniqify (hal_device_get_property_strlist (hal_mount->drive_device, "info.capabilities"));
+ if (caps != NULL)
+ {
+ for (n = 0; caps[n] != NULL; n++)
+ {
+ if (strcmp (caps[n], "portable_audio_player") == 0)
+ g_ptr_array_add (p, g_strdup ("x-content/audio-player"));
+ }
+ g_strfreev (caps);
+ }
+ }
+
+ if (p->len == 0)
+ {
+ result = NULL;
+ g_ptr_array_free (p, TRUE);
+ }
+ else
+ {
+ g_ptr_array_add (p, NULL);
+ result = (char **) g_ptr_array_free (p, FALSE);
+ }
+
+ G_UNLOCK (hal_mount);
+
+ return result;
+}
+
+/* since we're an out-of-process volume monitor we'll just do this sync */
+static void
+g_hal_mount_guess_content_type (GMount *mount,
+ gboolean force_rescan,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ /* TODO: handle force_rescan */
+ simple = g_simple_async_result_new (G_OBJECT (mount),
+ callback,
+ user_data,
+ NULL);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static char **
+g_hal_mount_guess_content_type_finish (GMount *mount,
+ GAsyncResult *result,
+ GError **error)
+{
+ /* TODO: handle force_rescan */
+ return g_hal_mount_guess_content_type_sync (mount, FALSE, NULL, error);
+}
+
+static void
+g_hal_mount_mount_iface_init (GMountIface *iface)
+{
+ iface->get_root = g_hal_mount_get_root;
+ iface->get_name = g_hal_mount_get_name;
+ iface->get_icon = g_hal_mount_get_icon;
+ iface->get_uuid = g_hal_mount_get_uuid;
+ iface->get_drive = g_hal_mount_get_drive;
+ iface->get_volume = g_hal_mount_get_volume;
+ iface->can_unmount = g_hal_mount_can_unmount;
+ iface->can_eject = g_hal_mount_can_eject;
+ iface->unmount = g_hal_mount_unmount;
+ iface->unmount_finish = g_hal_mount_unmount_finish;
+ iface->eject = g_hal_mount_eject;
+ iface->eject_finish = g_hal_mount_eject_finish;
+ iface->guess_content_type = g_hal_mount_guess_content_type;
+ iface->guess_content_type_finish = g_hal_mount_guess_content_type_finish;
+ iface->guess_content_type_sync = g_hal_mount_guess_content_type_sync;
+}
+
+#define INSENSITIVE_SEARCH_ITEMS_PER_CALLBACK 100
+
+static void
+enumerated_children_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data);
+
+static void
+more_files_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data);
+
+static void
+find_file_insensitive_exists_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data);
+
+typedef struct _InsensitiveFileSearchData
+{
+ GFile *root;
+ gchar *original_path;
+ gchar **split_path;
+ gint index;
+ GFileEnumerator *enumerator;
+ GFile *current_file;
+
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} InsensitiveFileSearchData;
+
+static void
+_g_find_file_insensitive_async (GFile *parent,
+ const gchar *name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ InsensitiveFileSearchData *data;
+ GFile *direct_file = g_file_get_child (parent, name);
+
+ data = g_new0 (InsensitiveFileSearchData, 1);
+ data->cancellable = cancellable;
+ data->callback = callback;
+ data->user_data = user_data;
+ data->root = g_object_ref (parent);
+ data->original_path = g_strdup (name);
+
+ g_file_query_info_async (direct_file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
+ cancellable,
+ find_file_insensitive_exists_callback, data);
+
+
+}
+
+static void
+clear_find_file_insensitive_state (InsensitiveFileSearchData *data)
+{
+ if (data->root)
+ g_object_unref (data->root);
+ g_free (data->original_path);
+ if (data->split_path)
+ g_strfreev (data->split_path);
+ if (data->enumerator)
+ g_object_unref (data->enumerator);
+ if (data->current_file)
+ g_object_unref (data->current_file);
+ g_free (data);
+}
+
+static void
+find_file_insensitive_exists_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GFileInfo *info;
+ InsensitiveFileSearchData *data = (InsensitiveFileSearchData *) (user_data);
+
+ /* The file exists and can be found with the given path, no need to search. */
+ if ((info = g_file_query_info_finish (G_FILE (source_object), res, NULL)))
+ {
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (source_object), g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ }
+
+ else
+ {
+ data->split_path = g_strsplit (data->original_path, G_DIR_SEPARATOR_S, -1);
+ data->index = 0;
+ data->enumerator = NULL;
+ data->current_file = g_object_ref (data->root);
+
+ /* Skip any empty components due to multiple slashes */
+ while (data->split_path[data->index] != NULL &&
+ *data->split_path[data->index] == 0)
+ data->index++;
+
+ g_file_enumerate_children_async (data->current_file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ 0, G_PRIORITY_DEFAULT,
+ data->cancellable,
+ enumerated_children_callback, data);
+ }
+
+ g_object_unref (source_object);
+}
+
+static void
+enumerated_children_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ GFileEnumerator *enumerator;
+ InsensitiveFileSearchData *data = (InsensitiveFileSearchData *) (user_data);
+
+ enumerator = g_file_enumerate_children_finish (G_FILE (source_object),
+ res, NULL);
+
+ if (enumerator == NULL)
+ {
+ GSimpleAsyncResult *simple;
+ GFile *file;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ file = g_file_get_child (data->root, data->original_path);
+
+ g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (file), g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ return;
+ }
+
+ data->enumerator = enumerator;
+ g_file_enumerator_next_files_async (enumerator,
+ INSENSITIVE_SEARCH_ITEMS_PER_CALLBACK,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ more_files_callback,
+ data);
+}
+
+static void
+more_files_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ InsensitiveFileSearchData *data = (InsensitiveFileSearchData *) (user_data);
+ GList *files, *l;
+ gchar *filename = NULL, *component, *case_folded_name,
+ *name_collation_key;
+ gboolean end_of_files, is_utf8;
+
+ files = g_file_enumerator_next_files_finish (data->enumerator,
+ res, NULL);
+
+ end_of_files = files == NULL;
+
+ component = data->split_path[data->index];
+ g_return_if_fail (component != NULL);
+
+ is_utf8 = (g_utf8_validate (component, -1, NULL));
+ if (is_utf8)
+ {
+ case_folded_name = g_utf8_casefold (component, -1);
+ name_collation_key = g_utf8_collate_key (case_folded_name, -1);
+ g_free (case_folded_name);
+ }
+
+ else
+ {
+ name_collation_key = g_ascii_strdown (component, -1);
+ }
+
+ for (l = files; l != NULL; l = l->next)
+ {
+ GFileInfo *info;
+ const gchar *this_name;
+ gchar *key;
+
+ info = l->data;
+ this_name = g_file_info_get_name (info);
+
+ if (is_utf8 && g_utf8_validate (this_name, -1, NULL))
+ {
+ gchar *case_folded;
+ case_folded = g_utf8_casefold (this_name, -1);
+ key = g_utf8_collate_key (case_folded, -1);
+ g_free (case_folded);
+ }
+ else
+ {
+ key = g_ascii_strdown (this_name, -1);
+ }
+
+ if (strcmp (key, name_collation_key) == 0)
+ filename = g_strdup (this_name);
+ g_free (key);
+
+ if (filename)
+ break;
+ }
+
+ g_list_foreach (files, (GFunc)g_object_unref, NULL);
+ g_list_free (files);
+ g_free (name_collation_key);
+
+ if (filename)
+ {
+ GFile *next_file;
+
+ g_file_enumerator_close_async (data->enumerator,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ NULL, NULL);
+ g_object_unref (data->enumerator);
+ data->enumerator = NULL;
+
+ /* Set the current file and continue searching */
+ next_file = g_file_get_child (data->current_file, filename);
+ g_free (filename);
+ g_object_unref (data->current_file);
+ data->current_file = next_file;
+
+ data->index++;
+ /* Skip any empty components due to multiple slashes */
+ while (data->split_path[data->index] != NULL &&
+ *data->split_path[data->index] == 0)
+ data->index++;
+
+ if (data->split_path[data->index] == NULL)
+ {
+ /* Search is complete, file was found */
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (data->current_file), g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ return;
+ }
+
+ /* Continue searching down the tree */
+ g_file_enumerate_children_async (data->current_file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ 0, G_PRIORITY_DEFAULT,
+ data->cancellable,
+ enumerated_children_callback,
+ data);
+ return;
+ }
+
+ if (end_of_files)
+ {
+ /* Could not find the given file, abort the search */
+ GSimpleAsyncResult *simple;
+ GFile *file;
+
+ g_object_unref (data->enumerator);
+ data->enumerator = NULL;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ file = g_file_get_child (data->root, data->original_path);
+ g_simple_async_result_set_op_res_gpointer (simple, file, g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ return;
+ }
+
+ /* Continue enumerating */
+ g_file_enumerator_next_files_async (data->enumerator,
+ INSENSITIVE_SEARCH_ITEMS_PER_CALLBACK,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ more_files_callback,
+ data);
+}
+
+static GFile *
+_g_find_file_insensitive_finish (GFile *parent,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ GFile *file;
+
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ file = G_FILE (g_simple_async_result_get_op_res_gpointer (simple));
+ return g_object_ref (file);
+}
+
diff --git a/gnome-2-24/monitor/hal/ghalmount.h b/gnome-2-24/monitor/hal/ghalmount.h
new file mode 100644
index 00000000..31981aed
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghalmount.h
@@ -0,0 +1,76 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#ifndef __G_HAL_MOUNT_H__
+#define __G_HAL_MOUNT_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "hal-pool.h"
+#include "ghalvolumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_HAL_MOUNT (g_hal_mount_get_type ())
+#define G_HAL_MOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_HAL_MOUNT, GHalMount))
+#define G_HAL_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_HAL_MOUNT, GHalMountClass))
+#define G_IS_HAL_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_HAL_MOUNT))
+#define G_IS_HAL_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_HAL_MOUNT))
+
+typedef struct _GHalMountClass GHalMountClass;
+
+struct _GHalMountClass {
+ GObjectClass parent_class;
+};
+
+GType g_hal_mount_get_type (void) G_GNUC_CONST;
+
+GHalMount * g_hal_mount_new_for_hal_device (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ GFile *override_root,
+ const char *override_name,
+ GIcon *override_icon,
+ gboolean cannot_unmount,
+ HalPool *pool,
+ GHalVolume *volume);
+GHalMount * g_hal_mount_new (GVolumeMonitor *volume_monitor,
+ GUnixMountEntry *mount_entry,
+ HalPool *pool,
+ GHalVolume *volume);
+gboolean g_hal_mount_has_mount_path (GHalMount *mount,
+ const char *mount_path);
+gboolean g_hal_mount_has_udi (GHalMount *mount,
+ const char *udi);
+gboolean g_hal_mount_has_uuid (GHalMount *mount,
+ const char *uuid);
+void g_hal_mount_unset_volume (GHalMount *mount,
+ GHalVolume *volume);
+void g_hal_mount_unmounted (GHalMount *mount);
+void g_hal_mount_override_name (GHalMount *mount,
+ const char *name);
+void g_hal_mount_override_icon (GHalMount *mount,
+ GIcon *icon);
+
+G_END_DECLS
+
+#endif /* __G_HAL_MOUNT_H__ */
diff --git a/gnome-2-24/monitor/hal/ghalvolume.c b/gnome-2-24/monitor/hal/ghalvolume.c
new file mode 100644
index 00000000..12579887
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghalvolume.c
@@ -0,0 +1,1068 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "ghaldrive.h"
+#include "ghalvolume.h"
+#include "ghalmount.h"
+
+#include "hal-utils.h"
+
+/* Protects all fields of GHalDrive that can change */
+G_LOCK_DEFINE_STATIC(hal_volume);
+
+struct _GHalVolume {
+ GObject parent;
+
+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */
+ GHalMount *mount; /* owned by volume monitor */
+ GHalDrive *drive; /* owned by volume monitor */
+
+ char *device_path;
+ char *mount_path;
+ char *uuid;
+ HalDevice *device;
+ HalDevice *drive_device;
+
+ /* set on creation if we won't create a GHalMount object ourselves
+ * and instead except to adopt one, with the given mount root,
+ * via adopt_orphan_mount()
+ */
+ GFile *foreign_mount_root;
+ GMount *foreign_mount;
+ gboolean is_mountable;
+ gboolean ignore_automount;
+
+ char *name;
+ char *icon;
+ char *icon_fallback;
+};
+
+static void g_hal_volume_volume_iface_init (GVolumeIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GHalVolume, g_hal_volume, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME,
+ g_hal_volume_volume_iface_init))
+
+static void
+g_hal_volume_finalize (GObject *object)
+{
+ GHalVolume *volume;
+
+ volume = G_HAL_VOLUME (object);
+
+ if (volume->mount != NULL)
+ g_hal_mount_unset_volume (volume->mount, volume);
+
+ if (volume->drive != NULL)
+ g_hal_drive_unset_volume (volume->drive, volume);
+
+ g_free (volume->mount_path);
+ g_free (volume->device_path);
+ g_free (volume->uuid);
+ if (volume->device != NULL)
+ g_object_unref (volume->device);
+ if (volume->drive_device != NULL)
+ g_object_unref (volume->drive_device);
+
+ if (volume->foreign_mount_root != NULL)
+ g_object_unref (volume->foreign_mount_root);
+
+ if (volume->foreign_mount != NULL)
+ g_object_unref (volume->foreign_mount);
+
+ if (volume->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (volume->volume_monitor), (gpointer) &(volume->volume_monitor));
+
+ g_free (volume->name);
+ g_free (volume->icon);
+ g_free (volume->icon_fallback);
+
+ if (G_OBJECT_CLASS (g_hal_volume_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_hal_volume_parent_class)->finalize) (object);
+}
+
+static void
+g_hal_volume_class_init (GHalVolumeClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_hal_volume_finalize;
+}
+
+static void
+g_hal_volume_init (GHalVolume *hal_volume)
+{
+}
+
+static gboolean
+changed_in_idle (gpointer data)
+{
+ GHalVolume *volume = data;
+
+ g_signal_emit_by_name (volume, "changed");
+ if (volume->volume_monitor != NULL)
+ g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume);
+ g_object_unref (volume);
+
+ return FALSE;
+}
+
+#define KILOBYTE_FACTOR 1000.0
+#define MEGABYTE_FACTOR (1000.0 * 1000.0)
+#define GIGABYTE_FACTOR (1000.0 * 1000.0 * 1000.0)
+
+/**
+ * format_size_for_display:
+ * @size: a number of octects
+ *
+ * Format a human readable string that can conveys how much storage a
+ * user-visible drive or piece of media can hold.
+ *
+ * As a matter of policy, we want this string to resemble what's on
+ * the packaging of the drive/media. Since all manufacturers use
+ * powers of 10, g_format_size_for_display() is not suitable here.
+ *
+ * TODO: we probably want to round to nearest power of two if @size is
+ * "close" (e.g. within 5%) - this is to avoid e.g. 63.4G when the
+ * packaging says "64G drive". We could also use per-drive or
+ * per-media quirks to make a better guess.
+ *
+ * Returns: A human readable string, caller must free it using
+ * g_free().
+ **/
+static char *
+format_size_for_display (guint64 size)
+{
+ char *str;
+ gdouble displayed_size;
+
+ if (size < MEGABYTE_FACTOR)
+ {
+ displayed_size = (double) size / KILOBYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f kB"), displayed_size);
+ }
+ else if (size < GIGABYTE_FACTOR)
+ {
+ displayed_size = (double) size / MEGABYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f MB"), displayed_size);
+ }
+ else
+ {
+ displayed_size = (double) size / GIGABYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f GB"), displayed_size);
+ }
+
+ return str;
+}
+
+static void
+do_update_from_hal (GHalVolume *mv)
+{
+ const char *drive_type;
+ const char *drive_bus;
+ gboolean drive_uses_removable_media;
+ const char *volume_fs_label;
+ guint64 volume_size;
+ gboolean volume_is_disc;
+ gboolean volume_disc_has_audio;
+ gboolean volume_disc_has_data;
+ const char *volume_disc_type;
+ gboolean volume_disc_is_blank;
+ const char *volume_fsusage;
+ const char *volume_fstype;
+ HalDevice *volume;
+ HalDevice *drive;
+ char *name;
+ char *size;
+ gboolean is_crypto;
+ gboolean is_crypto_cleartext;
+
+ volume = mv->device;
+ drive = mv->drive_device;
+
+ drive_type = hal_device_get_property_string (drive, "storage.drive_type");
+ drive_bus = hal_device_get_property_string (drive, "storage.bus");
+ drive_uses_removable_media = hal_device_get_property_bool (drive, "storage.removable");
+ volume_fs_label = hal_device_get_property_string (volume, "volume.label");
+ volume_size = hal_device_get_property_uint64 (volume, "volume.size");
+ volume_is_disc = hal_device_get_property_bool (volume, "volume.is_disc");
+ volume_disc_has_audio = hal_device_get_property_bool (volume, "volume.disc.has_audio");
+ volume_disc_has_data = hal_device_get_property_bool (volume, "volume.disc.has_data");
+ volume_disc_is_blank = hal_device_get_property_bool (volume, "volume.disc.is_blank");
+ volume_disc_type = hal_device_get_property_string (volume, "volume.disc.type");
+ volume_fsusage = hal_device_get_property_string (volume, "volume.fsusage");
+ volume_fstype = hal_device_get_property_string (volume, "volume.fstype");
+
+ is_crypto = FALSE;
+ is_crypto_cleartext = FALSE;
+ if (strcmp (hal_device_get_property_string (volume, "volume.fsusage"), "crypto") == 0)
+ is_crypto = TRUE;
+ if (strlen (hal_device_get_property_string (volume, "volume.crypto_luks.clear.backing_volume")) > 0)
+ is_crypto_cleartext = TRUE;
+
+ if (volume_is_disc && volume_disc_has_audio && mv->foreign_mount_root != NULL)
+ name = g_strdup (_("Audio Disc"));
+ else
+ {
+ if (strcmp (volume_fsusage, "crypto") == 0 && strcmp (volume_fstype, "crypto_LUKS") == 0)
+ {
+ size = format_size_for_display (volume_size);
+ /* Translators: %s is the size of the volume (e.g. 512 MB) */
+ name = g_strdup_printf (_("%s Encrypted Data"), size);
+ g_free (size);
+ }
+ else
+ {
+ if (volume_fs_label != NULL && strlen (volume_fs_label) > 0)
+ name = g_strdup (volume_fs_label);
+ else if (volume_is_disc)
+ {
+ if (volume_disc_has_audio)
+ {
+ if (volume_disc_has_data)
+ name = g_strdup (_("Mixed Audio/Data Disc"));
+ else
+ name = g_strdup (_("Audio Disc"));
+ }
+ else
+ name = g_strdup (get_disc_name (volume_disc_type, volume_disc_is_blank));
+ }
+ else
+ {
+ size = format_size_for_display (volume_size);
+ /* Translators: %s is the size of the volume (e.g. 512 MB) */
+ name = g_strdup_printf (_("%s Media"), size);
+ g_free (size);
+ }
+ }
+ }
+
+ mv->name = name;
+ mv->icon = _drive_get_icon (drive); /* use the drive icon since we're unmounted */
+
+ if (is_crypto || is_crypto_cleartext)
+ {
+ mv->icon_fallback = mv->icon;
+ mv->icon = g_strdup ("drive-encrypted");
+ }
+
+ if (hal_device_get_property_bool (volume, "volume.is_mounted"))
+ mv->mount_path = g_strdup (hal_device_get_property_string (volume, "volume.mount_point"));
+ else
+ mv->mount_path = NULL;
+
+ g_object_set_data_full (G_OBJECT (mv),
+ "hal-storage-device-capabilities",
+ dupv_and_uniqify (hal_device_get_property_strlist (mv->drive_device, "info.capabilities")),
+ (GDestroyNotify) g_strfreev);
+
+ if (volume_disc_type != NULL && strlen (volume_disc_type) == 0)
+ volume_disc_type = NULL;
+ g_object_set_data_full (G_OBJECT (mv),
+ "hal-volume.disc.type",
+ g_strdup (volume_disc_type),
+ (GDestroyNotify) g_free);
+}
+
+static void
+update_from_hal (GHalVolume *mv, gboolean emit_changed)
+{
+ char *old_name;
+ char *old_icon;
+ char *old_mount_path;
+
+ G_LOCK (hal_volume);
+
+ old_name = g_strdup (mv->name);
+ old_icon = g_strdup (mv->icon);
+ old_mount_path = g_strdup (mv->mount_path);
+
+ g_free (mv->name);
+ g_free (mv->icon);
+ g_free (mv->mount_path);
+ do_update_from_hal (mv);
+
+ if (emit_changed)
+ {
+ gboolean mount_path_changed;
+
+ if ((old_mount_path == NULL && mv->mount_path != NULL) ||
+ (old_mount_path != NULL && mv->mount_path == NULL) ||
+ (old_mount_path != NULL && mv->mount_path != NULL && strcmp (old_mount_path, mv->mount_path) != 0))
+ mount_path_changed = TRUE;
+ else
+ mount_path_changed = FALSE;
+
+ if (mount_path_changed ||
+ (old_name == NULL ||
+ old_icon == NULL ||
+ strcmp (old_name, mv->name) != 0 ||
+ strcmp (old_icon, mv->icon) != 0))
+ g_idle_add (changed_in_idle, g_object_ref (mv));
+ }
+ g_free (old_name);
+ g_free (old_icon);
+ g_free (old_mount_path);
+
+ G_UNLOCK (hal_volume);
+}
+
+static void
+hal_changed (HalDevice *device, const char *key, gpointer user_data)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (user_data);
+
+ /*g_warning ("hal modifying %s (property %s changed)", hal_volume->device_path, key);*/
+ update_from_hal (hal_volume, TRUE);
+}
+
+static void
+compute_uuid (GHalVolume *volume)
+{
+ const char *fs_uuid;
+ const char *fs_label;
+
+ /* use the FS uuid before falling back to the FS label */
+
+ fs_uuid = hal_device_get_property_string (volume->device, "volume.uuid");
+ fs_label = hal_device_get_property_string (volume->device, "volume.label");
+
+ if (strlen (fs_uuid) == 0)
+ {
+ if (strlen (fs_label) == 0)
+ volume->uuid = NULL;
+ else
+ volume->uuid = g_strdup (fs_label);
+ }
+ else
+ volume->uuid = g_strdup (fs_uuid);
+}
+
+GHalVolume *
+g_hal_volume_new (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ HalPool *pool,
+ GFile *foreign_mount_root,
+ gboolean is_mountable,
+ GHalDrive *drive)
+{
+ GHalVolume *volume;
+ HalDevice *drive_device;
+ const char *storage_udi;
+ const char *device_path;
+ gboolean ignore_automount;
+
+ ignore_automount = FALSE;
+
+ if (hal_device_has_capability (device, "block"))
+ {
+ storage_udi = hal_device_get_property_string (device, "block.storage_device");
+ if (storage_udi == NULL)
+ return NULL;
+
+ drive_device = hal_pool_get_device_by_udi (pool, storage_udi);
+ if (drive_device == NULL)
+ return NULL;
+
+ device_path = hal_device_get_property_string (device, "block.device");
+ }
+ else
+ {
+ return NULL;
+ }
+
+ if (drive_device &&
+ hal_device_has_property (drive_device, "storage.automount_enabled_hint") &&
+ !hal_device_get_property_bool (drive_device, "storage.automount_enabled_hint"))
+ ignore_automount = TRUE;
+
+ volume = g_object_new (G_TYPE_HAL_VOLUME, NULL);
+ volume->volume_monitor = volume_monitor;
+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor));
+ volume->mount_path = NULL;
+ volume->device_path = g_strdup (device_path);
+ volume->device = g_object_ref (device);
+ volume->drive_device = g_object_ref (drive_device);
+ volume->foreign_mount_root = foreign_mount_root != NULL ? g_object_ref (foreign_mount_root) : NULL;
+ volume->is_mountable = is_mountable;
+ volume->ignore_automount = ignore_automount || ! hal_device_is_recently_plugged_in (device);
+
+ g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, volume, 0);
+ g_signal_connect_object (drive_device, "hal_property_changed", (GCallback) hal_changed, volume, 0);
+
+ compute_uuid (volume);
+ update_from_hal (volume, FALSE);
+
+ /* need to do this last */
+ volume->drive = drive;
+ if (drive != NULL)
+ g_hal_drive_set_volume (drive, volume);
+
+ return volume;
+}
+
+/**
+ * g_hal_volume_removed:
+ * @volume:
+ *
+ **/
+void
+g_hal_volume_removed (GHalVolume *volume)
+{
+
+ G_LOCK (hal_volume);
+
+ if (volume->mount != NULL)
+ {
+ g_hal_mount_unset_volume (volume->mount, volume);
+ volume->mount = NULL;
+ }
+
+ if (volume->drive != NULL)
+ {
+ g_hal_drive_unset_volume (volume->drive, volume);
+ volume->drive = NULL;
+ }
+
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_set_mount (GHalVolume *volume,
+ GHalMount *mount)
+{
+ G_LOCK (hal_volume);
+ if (volume->mount != mount)
+ {
+
+ if (volume->mount != NULL)
+ g_hal_mount_unset_volume (volume->mount, volume);
+
+ volume->mount = mount;
+
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_unset_mount (GHalVolume *volume,
+ GHalMount *mount)
+{
+ G_LOCK (hal_volume);
+ if (volume->mount == mount)
+ {
+ volume->mount = NULL;
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_set_drive (GHalVolume *volume,
+ GHalDrive *drive)
+{
+ G_LOCK (hal_volume);
+ if (volume->drive != drive)
+ {
+ if (volume->drive != NULL)
+ g_hal_drive_unset_volume (volume->drive, volume);
+
+ volume->drive = drive;
+
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_unset_drive (GHalVolume *volume,
+ GHalDrive *drive)
+{
+ G_LOCK (hal_volume);
+ if (volume->drive == drive)
+ {
+ volume->drive = NULL;
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+static GIcon *
+g_hal_volume_get_icon (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GIcon *icon;
+ const char *name;
+ const char *fallback;
+
+ G_LOCK (hal_volume);
+ name = hal_volume->icon;
+
+ if (hal_volume->icon_fallback)
+ fallback = hal_volume->icon_fallback;
+ else /* if no custom fallbacks are set, use the icon to create them */
+ fallback = name;
+
+ icon = get_themed_icon_with_fallbacks (name, fallback);
+ G_UNLOCK (hal_volume);
+ return icon;
+}
+
+static char *
+g_hal_volume_get_name (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ char *name;
+
+ G_LOCK (hal_volume);
+ name = g_strdup (hal_volume->name);
+ G_UNLOCK (hal_volume);
+
+ return name;
+}
+
+static char *
+g_hal_volume_get_uuid (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ char *uuid;
+
+ G_LOCK (hal_volume);
+ uuid = g_strdup (hal_volume->uuid);
+ G_UNLOCK (hal_volume);
+
+ return uuid;
+}
+
+static gboolean
+g_hal_volume_can_mount (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = hal_volume->is_mountable;
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static gboolean
+g_hal_volume_can_eject (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->drive != NULL)
+ res = g_drive_can_eject (G_DRIVE (hal_volume->drive));
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static gboolean
+g_hal_volume_should_automount (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = ! (hal_volume->ignore_automount);
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static GDrive *
+g_hal_volume_get_drive (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GDrive *drive;
+
+ G_LOCK (hal_volume);
+ drive = NULL;
+ if (hal_volume->drive != NULL)
+ drive = g_object_ref (hal_volume->drive);
+ G_UNLOCK (hal_volume);
+
+ return drive;
+}
+
+static GMount *
+g_hal_volume_get_mount (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GMount *mount;
+
+ G_LOCK (hal_volume);
+ mount = NULL;
+ if (hal_volume->foreign_mount != NULL)
+ mount = g_object_ref (hal_volume->foreign_mount);
+ else if (hal_volume->mount != NULL)
+ mount = g_object_ref (hal_volume->mount);
+ G_UNLOCK (hal_volume);
+
+ return mount;
+}
+
+gboolean
+g_hal_volume_has_mount_path (GHalVolume *volume,
+ const char *mount_path)
+{
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (volume->mount_path != NULL)
+ res = strcmp (volume->mount_path, mount_path) == 0;
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+gboolean
+g_hal_volume_has_device_path (GHalVolume *volume,
+ const char *device_path)
+{
+ gboolean res;
+
+ res = FALSE;
+ G_LOCK (hal_volume);
+ if (volume->device_path != NULL)
+ res = strcmp (volume->device_path, device_path) == 0;
+ G_UNLOCK (hal_volume);
+ return res;
+}
+
+gboolean
+g_hal_volume_has_udi (GHalVolume *volume,
+ const char *udi)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->device != NULL)
+ res = strcmp (hal_device_get_udi (hal_volume->device), udi) == 0;
+ G_UNLOCK (hal_volume);
+ return res;
+}
+
+gboolean
+g_hal_volume_has_uuid (GHalVolume *volume,
+ const char *uuid)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->uuid != NULL)
+ res = strcmp (hal_volume->uuid, uuid) == 0;
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static void
+foreign_mount_unmounted (GMount *mount, gpointer user_data)
+{
+ GHalVolume *volume = G_HAL_VOLUME (user_data);
+ gboolean check;
+
+ G_LOCK (hal_volume);
+ check = volume->foreign_mount == mount;
+ G_UNLOCK (hal_volume);
+ if (check)
+ g_hal_volume_adopt_foreign_mount (volume, NULL);
+}
+
+void
+g_hal_volume_adopt_foreign_mount (GHalVolume *volume, GMount *foreign_mount)
+{
+ G_LOCK (hal_volume);
+ if (volume->foreign_mount != NULL)
+ g_object_unref (volume->foreign_mount);
+
+ if (foreign_mount != NULL)
+ {
+ volume->foreign_mount = g_object_ref (foreign_mount);
+ g_signal_connect_object (foreign_mount, "unmounted", (GCallback) foreign_mount_unmounted, volume, 0);
+ }
+ else
+ volume->foreign_mount = NULL;
+
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ G_UNLOCK (hal_volume);
+}
+
+gboolean
+g_hal_volume_has_foreign_mount_root (GHalVolume *volume,
+ GFile *mount_root)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->foreign_mount_root != NULL)
+ res = g_file_equal (hal_volume->foreign_mount_root, mount_root);
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
+} SpawnOp;
+
+static void
+spawn_cb (GPid pid, gint status, gpointer user_data)
+{
+ SpawnOp *data = user_data;
+ GSimpleAsyncResult *simple;
+
+ /* ensure that the #GHalMount corrosponding to the #GHalVolume we've
+ * mounted is made available before returning to the user
+ */
+ g_hal_volume_monitor_force_update (G_HAL_VOLUME_MONITOR (G_HAL_VOLUME (data->object)->volume_monitor));
+
+ if (WEXITSTATUS (status) != 0)
+ {
+ GError *error;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "You are not supposed to show G_IO_ERROR_FAILED_HANDLED in the UI");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ }
+ else
+ {
+ simple = g_simple_async_result_new (data->object,
+ data->callback,
+ data->user_data,
+ NULL);
+ }
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_object_unref (data->object);
+ g_free (data);
+}
+
+static void
+spawn_do (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ char **argv)
+{
+ SpawnOp *data;
+ GPid child_pid;
+ GError *error;
+
+ data = g_new0 (SpawnOp, 1);
+ data->object = g_object_ref (volume);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->cancellable = cancellable;
+
+ error = NULL;
+ if (!g_spawn_async (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,
+ &error))
+ {
+ g_simple_async_report_gerror_in_idle (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_object_unref (data->object);
+ g_error_free (error);
+ g_free (data);
+ return;
+ }
+
+ g_child_watch_add (child_pid, spawn_cb, data);
+}
+
+typedef struct
+{
+ GHalVolume *enclosing_volume;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} ForeignMountOp;
+
+static void
+mount_foreign_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ForeignMountOp *data = user_data;
+ data->callback (G_OBJECT (data->enclosing_volume), res, data->user_data);
+ g_object_unref (data->enclosing_volume);
+ g_free (data);
+}
+
+static void
+g_hal_volume_mount (GVolume *volume,
+ GMountMountFlags flags,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+
+ /*g_warning ("hal_volume_mount (can_mount=%d foreign=%p device_path=%s)",
+ g_hal_volume_can_mount (volume),
+ hal_volume->foreign_mount_root,
+ hal_volume->device_path);*/
+
+ G_LOCK (hal_volume);
+ if (hal_volume->foreign_mount_root != NULL)
+ {
+ ForeignMountOp *data;
+
+ data = g_new0 (ForeignMountOp, 1);
+ data->enclosing_volume = g_object_ref (hal_volume);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ g_file_mount_enclosing_volume (hal_volume->foreign_mount_root,
+ 0,
+ mount_operation,
+ cancellable,
+ mount_foreign_callback,
+ data);
+ }
+ else
+ {
+ char *argv[] = {"gnome-mount", "-b", "-d", NULL, NULL, NULL};
+ argv[3] = hal_volume->device_path;
+ /* ask for no dialogs if mount_operation is NULL */
+ if (mount_operation == NULL)
+ argv[4] = "-n";
+ spawn_do (volume, cancellable, callback, user_data, argv);
+ }
+ G_UNLOCK (hal_volume);
+}
+
+static gboolean
+g_hal_volume_mount_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = TRUE;
+
+ if (hal_volume->foreign_mount_root != NULL)
+ res = g_file_mount_enclosing_volume_finish (hal_volume->foreign_mount_root, result, error);
+
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} EjectWrapperOp;
+
+static void
+eject_wrapper_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EjectWrapperOp *data = user_data;
+ data->callback (data->object, res, data->user_data);
+ g_object_unref (data->object);
+ g_free (data);
+}
+
+static void
+g_hal_volume_eject (GVolume *volume,
+ GMountUnmountFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GHalDrive *drive;
+
+ /*g_warning ("hal_volume_eject");*/
+
+ drive = NULL;
+ G_LOCK (hal_volume);
+ if (hal_volume->drive != NULL)
+ drive = g_object_ref (hal_volume->drive);
+ G_UNLOCK (hal_volume);
+
+ if (drive != NULL)
+ {
+ EjectWrapperOp *data;
+ data = g_new0 (EjectWrapperOp, 1);
+ data->object = g_object_ref (volume);
+ data->callback = callback;
+ data->user_data = user_data;
+ g_drive_eject (G_DRIVE (drive), flags, cancellable, eject_wrapper_callback, data);
+ g_object_unref (drive);
+ }
+}
+
+static gboolean
+g_hal_volume_eject_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = TRUE;
+ if (hal_volume->drive != NULL)
+ res = g_drive_eject_finish (G_DRIVE (hal_volume->drive), result, error);
+ G_UNLOCK (hal_volume);
+ return res;
+}
+
+static char *
+g_hal_volume_get_identifier (GVolume *volume,
+ const char *kind)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ char *id;
+
+ G_LOCK (hal_volume);
+ id = NULL;
+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_HAL_UDI) == 0)
+ id = g_strdup (hal_device_get_udi (hal_volume->device));
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
+ id = g_strdup (hal_volume->device_path);
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0)
+ id = g_strdup (hal_device_get_property_string (hal_volume->device, "volume.label"));
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0)
+ id = g_strdup (hal_device_get_property_string (hal_volume->device, "volume.uuid"));
+ G_UNLOCK (hal_volume);
+
+ return id;
+}
+
+static char **
+g_hal_volume_enumerate_identifiers (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GPtrArray *res;
+ const char *label, *uuid;
+
+ G_LOCK (hal_volume);
+
+ res = g_ptr_array_new ();
+
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_HAL_UDI));
+
+ if (hal_volume->device_path && *hal_volume->device_path != 0)
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
+
+ label = hal_device_get_property_string (hal_volume->device, "volume.label");
+ uuid = hal_device_get_property_string (hal_volume->device, "volume.uuid");
+
+ if (label && *label != 0)
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL));
+
+ if (uuid && *uuid != 0)
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID));
+
+ /* Null-terminate */
+ g_ptr_array_add (res, NULL);
+
+ G_UNLOCK (hal_volume);
+
+ return (char **)g_ptr_array_free (res, FALSE);
+}
+
+static GFile *
+g_hal_volume_get_activation_root (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GFile *root = NULL;
+
+ G_LOCK (hal_volume);
+ if (hal_volume->foreign_mount_root != NULL)
+ root = g_object_ref (hal_volume->foreign_mount_root);
+ G_UNLOCK (hal_volume);
+
+ return root;
+}
+
+static void
+g_hal_volume_volume_iface_init (GVolumeIface *iface)
+{
+ iface->get_name = g_hal_volume_get_name;
+ iface->get_icon = g_hal_volume_get_icon;
+ iface->get_uuid = g_hal_volume_get_uuid;
+ iface->get_drive = g_hal_volume_get_drive;
+ iface->get_mount = g_hal_volume_get_mount;
+ iface->can_mount = g_hal_volume_can_mount;
+ iface->can_eject = g_hal_volume_can_eject;
+ iface->should_automount = g_hal_volume_should_automount;
+ iface->mount_fn = g_hal_volume_mount;
+ iface->mount_finish = g_hal_volume_mount_finish;
+ iface->eject = g_hal_volume_eject;
+ iface->eject_finish = g_hal_volume_eject_finish;
+ iface->get_identifier = g_hal_volume_get_identifier;
+ iface->enumerate_identifiers = g_hal_volume_enumerate_identifiers;
+ iface->get_activation_root = g_hal_volume_get_activation_root;
+}
diff --git a/gnome-2-24/monitor/hal/ghalvolume.h b/gnome-2-24/monitor/hal/ghalvolume.h
new file mode 100644
index 00000000..edbdfb31
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghalvolume.h
@@ -0,0 +1,84 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#ifndef __G_HAL_VOLUME_H__
+#define __G_HAL_VOLUME_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "hal-pool.h"
+#include "ghalvolumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_HAL_VOLUME (g_hal_volume_get_type ())
+#define G_HAL_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_HAL_VOLUME, GHalVolume))
+#define G_HAL_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_HAL_VOLUME, GHalVolumeClass))
+#define G_IS_HAL_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_HAL_VOLUME))
+#define G_IS_HAL_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_HAL_VOLUME))
+
+typedef struct _GHalVolumeClass GHalVolumeClass;
+
+struct _GHalVolumeClass {
+ GObjectClass parent_class;
+};
+
+GType g_hal_volume_get_type (void) G_GNUC_CONST;
+
+GHalVolume *g_hal_volume_new (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ HalPool *pool,
+ GFile *foreign_mount_root,
+ gboolean is_mountable,
+ GHalDrive *drive);
+
+gboolean g_hal_volume_has_mount_path (GHalVolume *volume,
+ const char *mount_path);
+gboolean g_hal_volume_has_device_path (GHalVolume *volume,
+ const char *device_path);
+gboolean g_hal_volume_has_udi (GHalVolume *volume,
+ const char *udi);
+gboolean g_hal_volume_has_uuid (GHalVolume *volume,
+ const char *uuid);
+
+gboolean g_hal_volume_has_foreign_mount_root (GHalVolume *volume,
+ GFile *mount_root);
+
+void g_hal_volume_adopt_foreign_mount (GHalVolume *volume,
+ GMount *foreign_mount);
+
+void g_hal_volume_set_mount (GHalVolume *volume,
+ GHalMount *mount);
+void g_hal_volume_unset_mount (GHalVolume *volume,
+ GHalMount *mount);
+
+void g_hal_volume_set_drive (GHalVolume *volume,
+ GHalDrive *drive);
+void g_hal_volume_unset_drive (GHalVolume *volume,
+ GHalDrive *drive);
+
+void g_hal_volume_removed (GHalVolume *volume);
+
+G_END_DECLS
+
+#endif /* __G_HAL_VOLUME_H__ */
diff --git a/gnome-2-24/monitor/hal/ghalvolumemonitor.c b/gnome-2-24/monitor/hal/ghalvolumemonitor.c
new file mode 100644
index 00000000..0a2a0877
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghalvolumemonitor.c
@@ -0,0 +1,1399 @@
+/* -*- 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#include <config.h>
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "ghalvolumemonitor.h"
+#include "ghalmount.h"
+#include "ghalvolume.h"
+#include "ghaldrive.h"
+#include "hal-pool.h"
+
+/* We use this static variable for enforcing a singleton pattern since
+ * the get_mount_for_mount_path() method on GNativeVolumeMonitor calls
+ * us without an instance.. and ideally we want to piggyback on an
+ * already existing instance.
+ *
+ * We avoid locking since GUnionVolumeMonitor, the only user of us,
+ * does locking.
+ */
+
+G_LOCK_DEFINE_STATIC(hal_vm);
+
+static GHalVolumeMonitor *the_volume_monitor = NULL;
+static HalPool *pool = NULL;
+
+struct _GHalVolumeMonitor {
+ GNativeVolumeMonitor parent;
+
+ GUnixMountMonitor *mount_monitor;
+
+ HalPool *pool;
+
+ GList *last_optical_disc_devices;
+ GList *last_drive_devices;
+ GList *last_volume_devices;
+ GList *last_mountpoints;
+ GList *last_mounts;
+
+ GList *drives;
+ GList *volumes;
+ GList *mounts;
+
+ /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */
+ GList *disc_volumes;
+ GList *disc_mounts;
+
+};
+
+static void mountpoints_changed (GUnixMountMonitor *mount_monitor,
+ gpointer user_data);
+static void mounts_changed (GUnixMountMonitor *mount_monitor,
+ gpointer user_data);
+static void hal_changed (HalPool *pool,
+ HalDevice *device,
+ gpointer user_data);
+static void update_all (GHalVolumeMonitor *monitor,
+ gboolean emit_changes);
+static void update_drives (GHalVolumeMonitor *monitor,
+ GList **added_drives,
+ GList **removed_drives);
+static void update_volumes (GHalVolumeMonitor *monitor,
+ GList **added_volumes,
+ GList **removed_volumes);
+static void update_mounts (GHalVolumeMonitor *monitor,
+ GList **added_mounts,
+ GList **removed_mounts);
+static void update_discs (GHalVolumeMonitor *monitor,
+ GList **added_volumes,
+ GList **removed_volumes,
+ GList **added_mounts,
+ GList **removed_mounts);
+
+
+G_DEFINE_TYPE (GHalVolumeMonitor, g_hal_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR)
+
+static void
+list_free (GList *objects)
+{
+ g_list_foreach (objects, (GFunc)g_object_unref, NULL);
+ g_list_free (objects);
+}
+
+static HalPool *
+get_hal_pool (void)
+{
+ char *cap_only[] = {"block", NULL};
+
+ if (pool == NULL)
+ pool = hal_pool_new (cap_only);
+
+ return pool;
+}
+
+static void
+g_hal_volume_monitor_dispose (GObject *object)
+{
+ GHalVolumeMonitor *monitor;
+
+ monitor = G_HAL_VOLUME_MONITOR (object);
+
+ G_LOCK (hal_vm);
+ the_volume_monitor = NULL;
+ G_UNLOCK (hal_vm);
+
+ if (G_OBJECT_CLASS (g_hal_volume_monitor_parent_class)->dispose)
+ (*G_OBJECT_CLASS (g_hal_volume_monitor_parent_class)->dispose) (object);
+}
+
+static void
+g_hal_volume_monitor_finalize (GObject *object)
+{
+ GHalVolumeMonitor *monitor;
+
+ monitor = G_HAL_VOLUME_MONITOR (object);
+
+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor);
+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor);
+ g_signal_handlers_disconnect_by_func (monitor->pool, hal_changed, monitor);
+
+ g_object_unref (monitor->mount_monitor);
+ g_object_unref (monitor->pool);
+
+ list_free (monitor->last_optical_disc_devices);
+ list_free (monitor->last_drive_devices);
+ list_free (monitor->last_volume_devices);
+ list_free (monitor->last_mountpoints);
+ g_list_foreach (monitor->last_mounts,
+ (GFunc)g_unix_mount_free, NULL);
+ g_list_free (monitor->last_mounts);
+
+ list_free (monitor->drives);
+ list_free (monitor->volumes);
+ list_free (monitor->mounts);
+
+ list_free (monitor->disc_volumes);
+ list_free (monitor->disc_mounts);
+
+ if (G_OBJECT_CLASS (g_hal_volume_monitor_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_hal_volume_monitor_parent_class)->finalize) (object);
+}
+
+static GList *
+get_mounts (GVolumeMonitor *volume_monitor)
+{
+ GHalVolumeMonitor *monitor;
+ GList *l, *ll;
+
+ monitor = G_HAL_VOLUME_MONITOR (volume_monitor);
+
+ G_LOCK (hal_vm);
+
+ l = g_list_copy (monitor->mounts);
+ ll = g_list_copy (monitor->disc_mounts);
+ l = g_list_concat (l, ll);
+
+ g_list_foreach (l, (GFunc)g_object_ref, NULL);
+
+ G_UNLOCK (hal_vm);
+
+ return l;
+}
+
+static GList *
+get_volumes (GVolumeMonitor *volume_monitor)
+{
+ GHalVolumeMonitor *monitor;
+ GList *l, *ll;
+
+ monitor = G_HAL_VOLUME_MONITOR (volume_monitor);
+
+ G_LOCK (hal_vm);
+
+ l = g_list_copy (monitor->volumes);
+ ll = g_list_copy (monitor->disc_volumes);
+ l = g_list_concat (l, ll);
+
+ g_list_foreach (l, (GFunc)g_object_ref, NULL);
+
+ G_UNLOCK (hal_vm);
+
+ return l;
+}
+
+static GList *
+get_connected_drives (GVolumeMonitor *volume_monitor)
+{
+ GHalVolumeMonitor *monitor;
+ GList *l;
+
+ monitor = G_HAL_VOLUME_MONITOR (volume_monitor);
+
+ G_LOCK (hal_vm);
+
+ l = g_list_copy (monitor->drives);
+ g_list_foreach (l, (GFunc)g_object_ref, NULL);
+
+ G_UNLOCK (hal_vm);
+
+ return l;
+}
+
+static GVolume *
+get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+ GHalVolumeMonitor *monitor;
+ GHalVolume *volume;
+ GList *l;
+
+ monitor = G_HAL_VOLUME_MONITOR (volume_monitor);
+
+ G_LOCK (hal_vm);
+
+ volume = NULL;
+
+ for (l = monitor->volumes; l != NULL; l = l->next)
+ {
+ volume = l->data;
+ if (g_hal_volume_has_uuid (volume, uuid))
+ goto found;
+ }
+
+ for (l = monitor->disc_volumes; l != NULL; l = l->next)
+ {
+ volume = l->data;
+ if (g_hal_volume_has_uuid (volume, uuid))
+ goto found;
+ }
+
+ G_UNLOCK (hal_vm);
+
+ return NULL;
+
+ found:
+
+ g_object_ref (volume);
+
+ G_UNLOCK (hal_vm);
+
+ return (GVolume *)volume;
+}
+
+static GMount *
+get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+ GHalVolumeMonitor *monitor;
+ GHalMount *mount;
+ GList *l;
+
+ monitor = G_HAL_VOLUME_MONITOR (volume_monitor);
+
+ G_LOCK (hal_vm);
+
+ mount = NULL;
+
+ for (l = monitor->mounts; l != NULL; l = l->next)
+ {
+ mount = l->data;
+ if (g_hal_mount_has_uuid (mount, uuid))
+ goto found;
+ }
+
+ for (l = monitor->disc_mounts; l != NULL; l = l->next)
+ {
+ mount = l->data;
+ if (g_hal_mount_has_uuid (mount, uuid))
+ goto found;
+ }
+
+ G_UNLOCK (hal_vm);
+
+ return NULL;
+
+ found:
+
+ g_object_ref (mount);
+
+ G_UNLOCK (hal_vm);
+
+ return (GMount *)mount;
+}
+
+static GMount *
+get_mount_for_mount_path (const char *mount_path,
+ GCancellable *cancellable)
+{
+ GMount *mount;
+ GHalMount *hal_mount;
+ GHalVolumeMonitor *volume_monitor;
+
+ G_LOCK (hal_vm);
+ volume_monitor = NULL;
+ if (the_volume_monitor != NULL)
+ volume_monitor = g_object_ref (the_volume_monitor);
+ G_UNLOCK (hal_vm);
+
+ if (volume_monitor == NULL)
+ {
+ /* Dammit, no monitor is set up.. so we have to create one, find
+ * what the user asks for and throw it away again.
+ *
+ * What a waste - especially considering that there's IO
+ * involved in doing this: connect to the system message bus;
+ * IPC to hald...
+ */
+ volume_monitor = G_HAL_VOLUME_MONITOR (g_hal_volume_monitor_new ());
+ }
+
+ mount = NULL;
+
+ /* creation of the volume monitor might actually fail */
+ if (volume_monitor != NULL)
+ {
+ GList *l;
+
+ G_LOCK (hal_vm);
+
+ for (l = volume_monitor->mounts; l != NULL; l = l->next)
+ {
+ hal_mount = l->data;
+
+ if (g_hal_mount_has_mount_path (hal_mount, mount_path))
+ {
+ mount = g_object_ref (hal_mount);
+ break;
+ }
+ }
+
+ G_UNLOCK (hal_vm);
+
+ g_object_unref (volume_monitor);
+ }
+
+ return (GMount *)mount;
+}
+
+static void
+mountpoints_changed (GUnixMountMonitor *mount_monitor,
+ gpointer user_data)
+{
+ GHalVolumeMonitor *monitor = G_HAL_VOLUME_MONITOR (user_data);
+
+ update_all (monitor, TRUE);
+}
+
+static void
+mounts_changed (GUnixMountMonitor *mount_monitor,
+ gpointer user_data)
+{
+ GHalVolumeMonitor *monitor = G_HAL_VOLUME_MONITOR (user_data);
+
+ update_all (monitor, TRUE);
+}
+
+void
+g_hal_volume_monitor_force_update (GHalVolumeMonitor *monitor)
+{
+ update_all (monitor, TRUE);
+}
+
+static void
+hal_changed (HalPool *pool,
+ HalDevice *device,
+ gpointer user_data)
+{
+ GHalVolumeMonitor *monitor = G_HAL_VOLUME_MONITOR (user_data);
+
+ /*g_warning ("hal changed");*/
+
+ update_all (monitor, TRUE);
+}
+
+static GObject *
+g_hal_volume_monitor_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ GHalVolumeMonitor *monitor;
+ GHalVolumeMonitorClass *klass;
+ GObjectClass *parent_class;
+
+ G_LOCK (hal_vm);
+ if (the_volume_monitor != NULL)
+ {
+ object = g_object_ref (the_volume_monitor);
+ G_UNLOCK (hal_vm);
+ return object;
+ }
+ G_UNLOCK (hal_vm);
+
+ /*g_warning ("creating hal vm");*/
+
+ object = NULL;
+
+ /* Invoke parent constructor. */
+ klass = G_HAL_VOLUME_MONITOR_CLASS (g_type_class_peek (G_TYPE_HAL_VOLUME_MONITOR));
+ parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
+ object = parent_class->constructor (type,
+ n_construct_properties,
+ construct_properties);
+
+ monitor = G_HAL_VOLUME_MONITOR (object);
+ monitor->pool = g_object_ref (get_hal_pool ());
+
+ monitor->mount_monitor = g_unix_mount_monitor_new ();
+
+ g_signal_connect (monitor->mount_monitor,
+ "mounts_changed", G_CALLBACK (mounts_changed),
+ monitor);
+
+ g_signal_connect (monitor->mount_monitor,
+ "mountpoints_changed", G_CALLBACK (mountpoints_changed),
+ monitor);
+
+ g_signal_connect (monitor->pool,
+ "device_added", G_CALLBACK (hal_changed),
+ monitor);
+
+ g_signal_connect (monitor->pool,
+ "device_removed", G_CALLBACK (hal_changed),
+ monitor);
+
+ update_all (monitor, FALSE);
+
+ G_LOCK (hal_vm);
+ the_volume_monitor = monitor;
+ G_UNLOCK (hal_vm);
+
+ return object;
+}
+
+static void
+g_hal_volume_monitor_init (GHalVolumeMonitor *monitor)
+{
+}
+
+static gboolean
+is_supported (void)
+{
+ return get_hal_pool() != NULL;
+}
+
+static GVolume *
+adopt_orphan_mount (GMount *mount, GVolumeMonitor *monitor)
+{
+ GList *l;
+ GFile *mount_root;
+ GVolume *ret;
+
+ /* This is called by the union volume monitor which does
+ have a ref to this. So its guaranteed to live, unfortunately
+ the pointer is not passed as an argument :/
+ */
+ ret = NULL;
+
+ G_LOCK (hal_vm);
+ if (the_volume_monitor == NULL)
+ {
+ G_UNLOCK (hal_vm);
+ return NULL;
+ }
+
+ mount_root = g_mount_get_root (mount);
+
+ /* cdda:// as foreign mounts */
+ for (l = the_volume_monitor->disc_volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+
+ if (g_hal_volume_has_foreign_mount_root (volume, mount_root))
+ {
+ g_hal_volume_adopt_foreign_mount (volume, mount);
+ ret = g_object_ref (volume);
+ goto found;
+ }
+ }
+
+ found:
+ g_object_unref (mount_root);
+
+ G_UNLOCK (hal_vm);
+ return ret;
+}
+
+static void
+g_hal_volume_monitor_class_init (GHalVolumeMonitorClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
+ GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass);
+
+ gobject_class->constructor = g_hal_volume_monitor_constructor;
+ gobject_class->finalize = g_hal_volume_monitor_finalize;
+ gobject_class->dispose = g_hal_volume_monitor_dispose;
+
+ monitor_class->get_mounts = get_mounts;
+ monitor_class->get_volumes = get_volumes;
+ monitor_class->get_connected_drives = get_connected_drives;
+ monitor_class->get_volume_for_uuid = get_volume_for_uuid;
+ monitor_class->get_mount_for_uuid = get_mount_for_uuid;
+ monitor_class->adopt_orphan_mount = adopt_orphan_mount;
+ monitor_class->is_supported = is_supported;
+
+ native_class->get_mount_for_mount_path = get_mount_for_mount_path;
+}
+
+/**
+ * g_hal_volume_monitor_new:
+ *
+ * Returns: a new #GVolumeMonitor.
+ **/
+GVolumeMonitor *
+g_hal_volume_monitor_new (void)
+{
+ GHalVolumeMonitor *monitor;
+
+ monitor = g_object_new (G_TYPE_HAL_VOLUME_MONITOR, NULL);
+
+ return G_VOLUME_MONITOR (monitor);
+}
+
+static void
+diff_sorted_lists (GList *list1,
+ GList *list2,
+ GCompareFunc compare,
+ GList **added,
+ GList **removed)
+{
+ int order;
+
+ *added = *removed = NULL;
+
+ while (list1 != NULL &&
+ list2 != NULL)
+ {
+ order = (*compare) (list1->data, list2->data);
+ if (order < 0)
+ {
+ *removed = g_list_prepend (*removed, list1->data);
+ list1 = list1->next;
+ }
+ else if (order > 0)
+ {
+ *added = g_list_prepend (*added, list2->data);
+ list2 = list2->next;
+ }
+ else
+ { /* same item */
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+ }
+
+ while (list1 != NULL)
+ {
+ *removed = g_list_prepend (*removed, list1->data);
+ list1 = list1->next;
+ }
+ while (list2 != NULL)
+ {
+ *added = g_list_prepend (*added, list2->data);
+ list2 = list2->next;
+ }
+}
+
+static GHalVolume *
+lookup_volume_for_mount_path (GHalVolumeMonitor *monitor,
+ const char *mount_path)
+{
+ GList *l;
+ GHalVolume *found;
+
+ found = NULL;
+
+ for (l = monitor->volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+
+ if (g_hal_volume_has_mount_path (volume, mount_path))
+ {
+ found = volume;
+ break;
+ }
+ }
+
+ return found;
+}
+
+static GHalVolume *
+lookup_volume_for_device_path (GHalVolumeMonitor *monitor,
+ const char *device_path)
+{
+ GList *l;
+
+ for (l = monitor->volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+
+ if (g_hal_volume_has_device_path (volume, device_path))
+ return volume;
+ }
+
+ return NULL;
+}
+
+
+
+static GHalMount *
+find_mount_by_mount_path (GHalVolumeMonitor *monitor,
+ const char *mount_path)
+{
+ GList *l;
+
+ for (l = monitor->mounts; l != NULL; l = l->next)
+ {
+ GHalMount *mount = l->data;
+
+ if (g_hal_mount_has_mount_path (mount, mount_path))
+ return mount;
+ }
+
+ return NULL;
+}
+
+static GHalVolume *
+find_volume_by_udi (GHalVolumeMonitor *monitor, const char *udi)
+{
+ GList *l;
+
+ for (l = monitor->volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+
+ if (g_hal_volume_has_udi (volume, udi))
+ return volume;
+ }
+
+ return NULL;
+}
+
+static GHalDrive *
+find_drive_by_udi (GHalVolumeMonitor *monitor, const char *udi)
+{
+ GList *l;
+
+ for (l = monitor->drives; l != NULL; l = l->next)
+ {
+ GHalDrive *drive = l->data;
+
+ if (g_hal_drive_has_udi (drive, udi))
+ return drive;
+ }
+
+ return NULL;
+}
+
+static GHalMount *
+find_disc_mount_by_udi (GHalVolumeMonitor *monitor, const char *udi)
+{
+ GList *l;
+
+ for (l = monitor->disc_mounts; l != NULL; l = l->next)
+ {
+ GHalMount *mount = l->data;
+
+ if (g_hal_mount_has_udi (mount, udi))
+ return mount;
+ }
+
+ return NULL;
+}
+
+static GHalVolume *
+find_disc_volume_by_udi (GHalVolumeMonitor *monitor, const char *udi)
+{
+ GList *l;
+
+ for (l = monitor->disc_volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+
+ if (g_hal_volume_has_udi (volume, udi))
+ return volume;
+ }
+
+ return NULL;
+}
+
+static gint
+hal_device_compare (HalDevice *a, HalDevice *b)
+{
+ return strcmp (hal_device_get_udi (a), hal_device_get_udi (b));
+}
+
+/* TODO: move to gio */
+static gboolean
+_g_unix_mount_point_guess_should_display (GUnixMountPoint *mount_point)
+{
+ const char *mount_path;
+
+ mount_path = g_unix_mount_point_get_mount_path (mount_point);
+
+ /* Never display internal mountpoints */
+ if (g_unix_is_mount_path_system_internal (mount_path))
+ return FALSE;
+
+ /* Only display things in /media (which are generally user mountable)
+ and home dir (fuse stuff) */
+ if (g_str_has_prefix (mount_path, "/media/"))
+ return TRUE;
+
+ if (g_str_has_prefix (mount_path, g_get_home_dir ()))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static GUnixMountPoint *
+get_mount_point_for_device (HalDevice *d, GList *fstab_mount_points)
+{
+ GList *l;
+ const char *device_file;
+ const char *device_mount_point;
+
+ device_mount_point = hal_device_get_property_string (d, "volume.mount_point");
+
+ device_file = hal_device_get_property_string (d, "block.device");
+
+ for (l = fstab_mount_points; l != NULL; l = l->next)
+ {
+ GUnixMountPoint *mount_point = l->data;
+ const char *device_path;
+ const char *mount_path;
+
+ mount_path = g_unix_mount_point_get_mount_path (mount_point);
+ if (device_mount_point != NULL &&
+ mount_path != NULL &&
+ strcmp (device_mount_point, mount_path) == 0)
+ return mount_point;
+
+ device_path = g_unix_mount_point_get_device_path (mount_point);
+ if (g_str_has_prefix (device_path, "LABEL="))
+ {
+ if (strcmp (device_path + 6, hal_device_get_property_string (d, "volume.label")) == 0)
+ return mount_point;
+ }
+ else if (g_str_has_prefix (device_path, "UUID="))
+ {
+ if (g_ascii_strcasecmp (device_path + 5, hal_device_get_property_string (d, "volume.uuid")) == 0)
+ return mount_point;
+ }
+ else
+ {
+ char resolved_device_path[PATH_MAX];
+ /* handle symlinks such as /dev/disk/by-uuid/47C2-1994 */
+ if (realpath (device_path, resolved_device_path) != NULL &&
+ strcmp (resolved_device_path, device_file) == 0)
+ return mount_point;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+should_mount_be_ignored (HalPool *pool, HalDevice *d)
+{
+ const char *device_mount_point;
+
+ device_mount_point = hal_device_get_property_string (d, "volume.mount_point");
+ if (device_mount_point != NULL && strlen (device_mount_point) > 0)
+ {
+ GUnixMountEntry *mount_entry;
+
+ /*g_warning ("device_mount_point = '%s'", device_mount_point);*/
+
+ mount_entry = g_unix_mount_at (device_mount_point, NULL);
+ if (mount_entry != NULL) {
+ if (!g_unix_mount_guess_should_display (mount_entry))
+ {
+ g_unix_mount_free (mount_entry);
+ return TRUE;
+ }
+ g_unix_mount_free (mount_entry);
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+should_volume_be_ignored (HalPool *pool, HalDevice *d, GList *fstab_mount_points)
+{
+ gboolean volume_ignore;
+ const char *volume_fsusage;
+ GUnixMountPoint *mount_point;
+
+ volume_fsusage = hal_device_get_property_string (d, "volume.fsusage");
+ volume_ignore = hal_device_get_property_bool (d, "volume.ignore");
+
+ if (volume_fsusage == NULL)
+ {
+ /*g_warning ("no volume.fsusage property. Refusing to ignore");*/
+ return FALSE;
+ }
+
+ if (volume_ignore)
+ return TRUE;
+
+ if (strcmp (volume_fsusage, "filesystem") != 0)
+ {
+ /* no file system on the volume... blank and audio discs are handled in update_discs() */
+
+ /* check if it's a LUKS crypto volume */
+ if (strcmp (volume_fsusage, "crypto") == 0)
+ {
+ if (strcmp (hal_device_get_property_string (d, "volume.fstype"), "crypto_LUKS") == 0)
+ {
+ HalDevice *cleartext_device;
+
+ /* avoid showing cryptotext volume if it's corresponding cleartext volume is available */
+ cleartext_device = hal_pool_get_device_by_capability_and_string (pool,
+ "block",
+ "volume.crypto_luks.clear.backing_volume",
+ hal_device_get_udi (d));
+
+ if (cleartext_device == NULL)
+ {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+ }
+
+ mount_point = get_mount_point_for_device (d, fstab_mount_points);
+ if (mount_point != NULL && !_g_unix_mount_point_guess_should_display (mount_point))
+ return TRUE;
+
+ if (hal_device_get_property_bool (d, "volume.is_mounted"))
+ return should_mount_be_ignored (pool, d);
+
+ return FALSE;
+}
+
+static gboolean
+should_drive_be_ignored (HalPool *pool, HalDevice *d, GList *fstab_mount_points)
+{
+ GList *volumes, *l;
+ const char *drive_udi;
+ gboolean all_volumes_ignored, got_volumes;
+
+ /* never ignore drives with removable media */
+ if (hal_device_get_property_bool (d, "storage.removable"))
+ return FALSE;
+
+ drive_udi = hal_device_get_udi (d);
+
+ volumes = hal_pool_find_by_capability (pool, "volume");
+
+ all_volumes_ignored = TRUE;
+ got_volumes = FALSE;
+ for (l = volumes; l != NULL; l = l->next)
+ {
+ HalDevice *volume_dev = l->data;
+ if (strcmp (drive_udi, hal_device_get_property_string (volume_dev, "block.storage_device")) == 0)
+ {
+ got_volumes = TRUE;
+ if (!should_volume_be_ignored (pool, volume_dev, fstab_mount_points) ||
+ hal_device_get_property_bool (volume_dev, "volume.disc.has_audio") ||
+ hal_device_get_property_bool (volume_dev, "volume.disc.is_blank"))
+ {
+ all_volumes_ignored = FALSE;
+ break;
+ }
+ }
+ }
+
+ return got_volumes && all_volumes_ignored;
+}
+
+static void
+list_emit (GHalVolumeMonitor *monitor,
+ const char *monitor_signal,
+ const char *object_signal,
+ GList *objects)
+{
+ GList *l;
+
+ for (l = objects; l != NULL; l = l->next)
+ {
+ g_signal_emit_by_name (monitor, monitor_signal, l->data);
+ if (object_signal)
+ g_signal_emit_by_name (l->data, object_signal);
+ }
+}
+
+typedef struct {
+ GHalVolumeMonitor *monitor;
+ GList *added_drives, *removed_drives;
+ GList *added_volumes, *removed_volumes;
+ GList *added_mounts, *removed_mounts;
+} ChangedLists;
+
+
+static gboolean
+emit_lists_in_idle (gpointer data)
+{
+ ChangedLists *lists = data;
+
+ list_emit (lists->monitor,
+ "drive_disconnected", NULL,
+ lists->removed_drives);
+ list_emit (lists->monitor,
+ "drive_connected", NULL,
+ lists->added_drives);
+
+ list_emit (lists->monitor,
+ "volume_removed", "removed",
+ lists->removed_volumes);
+ list_emit (lists->monitor,
+ "volume_added", NULL,
+ lists->added_volumes);
+
+ list_emit (lists->monitor,
+ "mount_removed", "unmounted",
+ lists->removed_mounts);
+ list_emit (lists->monitor,
+ "mount_added", NULL,
+ lists->added_mounts);
+
+ list_free (lists->removed_drives);
+ list_free (lists->added_drives);
+ list_free (lists->removed_volumes);
+ list_free (lists->added_volumes);
+ list_free (lists->removed_mounts);
+ list_free (lists->added_mounts);
+ g_object_unref (lists->monitor);
+ g_free (lists);
+
+ return FALSE;
+}
+
+/* Must be called from idle if emit_changes, with no locks held */
+static void
+update_all (GHalVolumeMonitor *monitor,
+ gboolean emit_changes)
+{
+ ChangedLists *lists;
+ GList *added_drives, *removed_drives;
+ GList *added_volumes, *removed_volumes;
+ GList *added_mounts, *removed_mounts;
+
+ added_drives = NULL;
+ removed_drives = NULL;
+ added_volumes = NULL;
+ removed_volumes = NULL;
+ added_mounts = NULL;
+ removed_mounts = NULL;
+
+ G_LOCK (hal_vm);
+ update_drives (monitor, &added_drives, &removed_drives);
+ update_volumes (monitor, &added_volumes, &removed_volumes);
+ update_mounts (monitor, &added_mounts, &removed_mounts);
+ update_discs (monitor,
+ &added_volumes, &removed_volumes,
+ &added_mounts, &removed_mounts);
+ G_UNLOCK (hal_vm);
+
+ if (emit_changes)
+ {
+ lists = g_new0 (ChangedLists, 1);
+ lists->monitor = g_object_ref (monitor);
+ lists->added_drives = added_drives;
+ lists->removed_drives = removed_drives;
+ lists->added_volumes = added_volumes;
+ lists->removed_volumes = removed_volumes;
+ lists->added_mounts = added_mounts;
+ lists->removed_mounts = removed_mounts;
+
+ g_idle_add (emit_lists_in_idle, lists);
+ }
+ else
+ {
+ list_free (removed_drives);
+ list_free (added_drives);
+ list_free (removed_volumes);
+ list_free (added_volumes);
+ list_free (removed_mounts);
+ list_free (added_mounts);
+ }
+}
+
+static void
+update_drives (GHalVolumeMonitor *monitor,
+ GList **added_drives,
+ GList **removed_drives)
+{
+ GList *new_drive_devices;
+ GList *removed, *added;
+ GList *l, *ll;
+ GHalDrive *drive;
+ GList *fstab_mount_points;
+
+ fstab_mount_points = g_unix_mount_points_get (NULL);
+
+ new_drive_devices = hal_pool_find_by_capability (monitor->pool, "storage");
+
+ /* remove devices we want to ignore - we do it here so we get to reevaluate
+ * on the next update whether they should still be ignored
+ */
+ for (l = new_drive_devices; l != NULL; l = ll)
+ {
+ HalDevice *d = l->data;
+ ll = l->next;
+ if (should_drive_be_ignored (monitor->pool, d, fstab_mount_points))
+ new_drive_devices = g_list_delete_link (new_drive_devices, l);
+ }
+
+ g_list_foreach (new_drive_devices, (GFunc) g_object_ref, NULL);
+
+ new_drive_devices = g_list_sort (new_drive_devices, (GCompareFunc) hal_device_compare);
+ diff_sorted_lists (monitor->last_drive_devices,
+ new_drive_devices, (GCompareFunc) hal_device_compare,
+ &added, &removed);
+
+ for (l = removed; l != NULL; l = l->next)
+ {
+ HalDevice *d = l->data;
+
+ drive = find_drive_by_udi (monitor, hal_device_get_udi (d));
+ if (drive != NULL)
+ {
+ /*g_warning ("hal removing drive %s", hal_device_get_property_string (d, "block.device"));*/
+ g_hal_drive_disconnected (drive);
+ monitor->drives = g_list_remove (monitor->drives, drive);
+ *removed_drives = g_list_prepend (*removed_drives, drive);
+ }
+ }
+
+ for (l = added; l != NULL; l = l->next)
+ {
+ HalDevice *d = l->data;
+
+ drive = find_drive_by_udi (monitor, hal_device_get_udi (d));
+ if (drive == NULL)
+ {
+ /*g_warning ("hal adding drive %s", hal_device_get_property_string (d, "block.device"));*/
+ drive = g_hal_drive_new (G_VOLUME_MONITOR (monitor), d, monitor->pool);
+ if (drive != NULL)
+ {
+ monitor->drives = g_list_prepend (monitor->drives, drive);
+ *added_drives = g_list_prepend (*added_drives, g_object_ref (drive));
+ }
+ }
+ }
+
+ g_list_free (added);
+ g_list_free (removed);
+ list_free (monitor->last_drive_devices);
+ monitor->last_drive_devices = new_drive_devices;
+
+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL);
+ g_list_free (fstab_mount_points);
+}
+
+static void
+update_volumes (GHalVolumeMonitor *monitor,
+ GList **added_volumes,
+ GList **removed_volumes)
+{
+ GList *new_volume_devices;
+ GList *removed, *added;
+ GList *l, *ll;
+ GHalVolume *volume;
+ GHalDrive *drive;
+ GList *fstab_mount_points;
+
+ fstab_mount_points = g_unix_mount_points_get (NULL);
+
+ new_volume_devices = hal_pool_find_by_capability (monitor->pool, "volume");
+
+ /* remove devices we want to ignore - we do it here so we get to reevaluate
+ * on the next update whether they should still be ignored
+ */
+ for (l = new_volume_devices; l != NULL; l = ll)
+ {
+ HalDevice *d = l->data;
+ ll = l->next;
+ if (should_volume_be_ignored (monitor->pool, d, fstab_mount_points))
+ new_volume_devices = g_list_delete_link (new_volume_devices, l);
+ }
+
+ g_list_foreach (new_volume_devices, (GFunc) g_object_ref, NULL);
+
+ new_volume_devices = g_list_sort (new_volume_devices, (GCompareFunc) hal_device_compare);
+ diff_sorted_lists (monitor->last_volume_devices,
+ new_volume_devices, (GCompareFunc) hal_device_compare,
+ &added, &removed);
+
+ for (l = removed; l != NULL; l = l->next)
+ {
+ HalDevice *d = l->data;
+
+ volume = find_volume_by_udi (monitor, hal_device_get_udi (d));
+ if (volume != NULL)
+ {
+ /*g_warning ("hal removing vol %s", hal_device_get_property_string (d, "block.device"));*/
+ g_hal_volume_removed (volume);
+ monitor->volumes = g_list_remove (monitor->volumes, volume);
+
+ *removed_volumes = g_list_prepend (*removed_volumes, volume);
+ }
+ }
+
+ for (l = added; l != NULL; l = l->next)
+ {
+ HalDevice *d = l->data;
+
+ volume = find_volume_by_udi (monitor, hal_device_get_udi (d));
+ if (volume == NULL)
+ {
+ drive = find_drive_by_udi (monitor, hal_device_get_property_string (d, "block.storage_device"));
+
+ /*g_warning ("hal adding vol %s (drive %p)", hal_device_get_property_string (d, "block.device"), drive);*/
+ volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor),
+ d,
+ monitor->pool,
+ NULL,
+ TRUE,
+ drive);
+ if (volume != NULL)
+ {
+ monitor->volumes = g_list_prepend (monitor->volumes, volume);
+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
+ }
+ }
+ }
+
+ g_list_free (added);
+ g_list_free (removed);
+ list_free (monitor->last_volume_devices);
+ monitor->last_volume_devices = new_volume_devices;
+
+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL);
+ g_list_free (fstab_mount_points);
+}
+
+static void
+update_mounts (GHalVolumeMonitor *monitor,
+ GList **added_mounts,
+ GList **removed_mounts)
+{
+ GList *new_mounts;
+ GList *removed, *added;
+ GList *l, *ll;
+ GHalMount *mount;
+ GHalVolume *volume;
+ const char *device_path;
+ const char *mount_path;
+
+ new_mounts = g_unix_mounts_get (NULL);
+
+ /* remove mounts we want to ignore - we do it here so we get to reevaluate
+ * on the next update whether they should still be ignored
+ */
+ for (l = new_mounts; l != NULL; l = ll)
+ {
+ GUnixMountEntry *mount_entry = l->data;
+ ll = l->next;
+
+ /* keep in sync with should_mount_be_ignored() */
+ if (!g_unix_mount_guess_should_display (mount_entry))
+ {
+ g_unix_mount_free (mount_entry);
+ new_mounts = g_list_delete_link (new_mounts, l);
+ }
+ }
+
+ new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare);
+
+ diff_sorted_lists (monitor->last_mounts,
+ new_mounts, (GCompareFunc) g_unix_mount_compare,
+ &added, &removed);
+
+ for (l = removed; l != NULL; l = l->next)
+ {
+ GUnixMountEntry *mount_entry = l->data;
+
+ mount = find_mount_by_mount_path (monitor, g_unix_mount_get_mount_path (mount_entry));
+ /*g_warning ("hal removing mount %s (%p)", g_unix_mount_get_device_path (mount_entry), mount);*/
+ if (mount)
+ {
+ g_hal_mount_unmounted (mount);
+ monitor->mounts = g_list_remove (monitor->mounts, mount);
+
+ *removed_mounts = g_list_prepend (*removed_mounts, mount);
+ }
+ }
+
+ for (l = added; l != NULL; l = l->next)
+ {
+ GUnixMountEntry *mount_entry = l->data;
+
+ device_path = g_unix_mount_get_device_path (mount_entry);
+ mount_path = g_unix_mount_get_mount_path (mount_entry);
+ volume = lookup_volume_for_device_path (monitor, device_path);
+ if (volume == NULL)
+ volume = lookup_volume_for_mount_path (monitor, mount_path);
+
+ /*g_warning ("hal adding mount %s (vol %p)", g_unix_mount_get_device_path (mount_entry), volume);*/
+ mount = g_hal_mount_new (G_VOLUME_MONITOR (monitor), mount_entry, monitor->pool, volume);
+ if (mount)
+ {
+ monitor->mounts = g_list_prepend (monitor->mounts, mount);
+ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount));
+ }
+ }
+
+ g_list_free (added);
+ g_list_free (removed);
+ g_list_foreach (monitor->last_mounts,
+ (GFunc)g_unix_mount_free, NULL);
+ g_list_free (monitor->last_mounts);
+ monitor->last_mounts = new_mounts;
+}
+
+static void
+update_discs (GHalVolumeMonitor *monitor,
+ GList **added_volumes,
+ GList **removed_volumes,
+ GList **added_mounts,
+ GList **removed_mounts)
+{
+ GList *new_optical_disc_devices;
+ GList *removed, *added;
+ GList *l, *ll;
+ GHalDrive *drive;
+ GHalVolume *volume;
+ GHalMount *mount;
+ const char *udi;
+ const char *drive_udi;
+
+ /* we also need to generate GVolume + GMount objects for
+ *
+ * - optical discs that have audio
+ * - optical discs that are blank
+ *
+ */
+
+ new_optical_disc_devices = hal_pool_find_by_capability (monitor->pool, "volume.disc");
+ for (l = new_optical_disc_devices; l != NULL; l = ll)
+ {
+ HalDevice *d = l->data;
+ ll = l->next;
+ if (! (hal_device_get_property_bool (d, "volume.disc.is_blank") ||
+ hal_device_get_property_bool (d, "volume.disc.has_audio")))
+ {
+ /* filter out everything but discs that are blank or has audio */
+ new_optical_disc_devices = g_list_delete_link (new_optical_disc_devices, l);
+ }
+ }
+
+ g_list_foreach (new_optical_disc_devices, (GFunc) g_object_ref, NULL);
+
+ new_optical_disc_devices = g_list_sort (new_optical_disc_devices, (GCompareFunc) hal_device_compare);
+ diff_sorted_lists (monitor->last_optical_disc_devices,
+ new_optical_disc_devices, (GCompareFunc) hal_device_compare,
+ &added, &removed);
+
+ for (l = removed; l != NULL; l = l->next)
+ {
+ HalDevice *d = l->data;
+
+ udi = hal_device_get_udi (d);
+ /*g_warning ("audio/blank disc removing %s", udi);*/
+
+ mount = find_disc_mount_by_udi (monitor, udi);
+ if (mount != NULL)
+ {
+ g_hal_mount_unmounted (mount);
+ monitor->disc_mounts = g_list_remove (monitor->disc_mounts, mount);
+ *removed_mounts = g_list_prepend (*removed_mounts, mount);
+ }
+
+ volume = find_disc_volume_by_udi (monitor, udi);
+ if (volume != NULL)
+ {
+ g_hal_volume_removed (volume);
+ monitor->disc_volumes = g_list_remove (monitor->disc_volumes, volume);
+ *removed_volumes = g_list_prepend (*removed_volumes, volume);
+ }
+ }
+
+ for (l = added; l != NULL; l = l->next)
+ {
+ HalDevice *d = l->data;
+
+ udi = hal_device_get_udi (d);
+ /*g_warning ("audio/blank disc adding %s", udi);*/
+
+ drive_udi = hal_device_get_property_string (d, "block.storage_device");
+ drive = find_drive_by_udi (monitor, drive_udi);
+ if (drive != NULL)
+ {
+ mount = NULL;
+ if (hal_device_get_property_bool (d, "volume.disc.is_blank"))
+ {
+ volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor),
+ d, monitor->pool,
+ NULL,
+ FALSE,
+ drive);
+ if (volume != NULL)
+ {
+ GFile *root;
+ root = g_file_new_for_uri ("burn:///");
+ mount = g_hal_mount_new_for_hal_device (G_VOLUME_MONITOR (monitor),
+ d,
+ root,
+ NULL,
+ NULL,
+ TRUE,
+ monitor->pool,
+ volume);
+ g_object_unref (root);
+ }
+ }
+ else
+ {
+ char *uri;
+ char *device_basename;
+ GFile *foreign_mount_root;
+
+ /* the gvfsd-cdda backend uses URI's like these */
+ device_basename = g_path_get_basename (hal_device_get_property_string (d, "block.device"));
+ uri = g_strdup_printf ("cdda://%s", device_basename);
+ foreign_mount_root = g_file_new_for_uri (uri);
+ g_free (device_basename);
+ g_free (uri);
+
+ volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor),
+ d,
+ monitor->pool,
+ foreign_mount_root,
+ TRUE,
+ drive);
+ g_object_unref (foreign_mount_root);
+ mount = NULL;
+ }
+
+ if (volume != NULL)
+ {
+ monitor->disc_volumes = g_list_prepend (monitor->disc_volumes, volume);
+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
+
+ if (mount != NULL)
+ {
+ monitor->disc_mounts = g_list_prepend (monitor->disc_mounts, mount);
+ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount));
+ }
+ }
+ }
+ }
+
+ g_list_free (added);
+ g_list_free (removed);
+ list_free (monitor->last_optical_disc_devices);
+ monitor->last_optical_disc_devices = new_optical_disc_devices;
+}
diff --git a/gnome-2-24/monitor/hal/ghalvolumemonitor.h b/gnome-2-24/monitor/hal/ghalvolumemonitor.h
new file mode 100644
index 00000000..a8397030
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghalvolumemonitor.h
@@ -0,0 +1,58 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#ifndef __G_HAL_VOLUME_MONITOR_H__
+#define __G_HAL_VOLUME_MONITOR_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_HAL_VOLUME_MONITOR (g_hal_volume_monitor_get_type ())
+#define G_HAL_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_HAL_VOLUME_MONITOR, GHalVolumeMonitor))
+#define G_HAL_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_HAL_VOLUME_MONITOR, GHalVolumeMonitorClass))
+#define G_IS_HAL_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_HAL_VOLUME_MONITOR))
+#define G_IS_HAL_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_HAL_VOLUME_MONITOR))
+
+typedef struct _GHalVolumeMonitor GHalVolumeMonitor;
+typedef struct _GHalVolumeMonitorClass GHalVolumeMonitorClass;
+
+/* Forward definitions */
+typedef struct _GHalDrive GHalDrive;
+typedef struct _GHalVolume GHalVolume;
+typedef struct _GHalMount GHalMount;
+
+struct _GHalVolumeMonitorClass {
+ GNativeVolumeMonitorClass parent_class;
+
+};
+
+GType g_hal_volume_monitor_get_type (void) G_GNUC_CONST;
+
+GVolumeMonitor *g_hal_volume_monitor_new (void);
+void g_hal_volume_monitor_force_update (GHalVolumeMonitor *monitor);
+
+G_END_DECLS
+
+#endif /* __G_HAL_VOLUME_MONITOR_H__ */
diff --git a/gnome-2-24/monitor/hal/hal-device.c b/gnome-2-24/monitor/hal/hal-device.c
new file mode 100644
index 00000000..9f0b5bc3
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-device.c
@@ -0,0 +1,297 @@
+/* hal-device.c
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include "hal-device.h"
+#include "hal-marshal.h"
+
+struct _HalDevicePrivate
+{
+ LibHalContext *hal_ctx;
+ LibHalPropertySet *properties;
+ char *udi;
+ GTimeVal time_added;
+};
+
+enum {
+ HAL_PROPERTY_CHANGED,
+ HAL_CONDITION,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (HalDevice, hal_device, G_TYPE_OBJECT)
+
+static void
+hal_device_finalize (HalDevice *device)
+{
+ if (device->priv->properties != NULL)
+ libhal_free_property_set (device->priv->properties);
+ g_free (device->priv->udi);
+
+ if (G_OBJECT_CLASS (hal_device_parent_class)->finalize)
+ (* G_OBJECT_CLASS (hal_device_parent_class)->finalize) (G_OBJECT (device));
+}
+
+static void
+hal_device_class_init (HalDeviceClass *klass)
+{
+ GObjectClass *obj_class = (GObjectClass *) klass;
+
+ obj_class->finalize = (GObjectFinalizeFunc) hal_device_finalize;
+
+ signals[HAL_PROPERTY_CHANGED] =
+ g_signal_new ("hal_property_changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalDeviceClass, hal_property_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+
+ signals[HAL_CONDITION] =
+ g_signal_new ("hal_condition",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalDeviceClass, hal_condition),
+ NULL, NULL,
+ hal_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+}
+
+static void
+hal_device_init (HalDevice *device)
+{
+ device->priv = g_new0 (HalDevicePrivate, 1);
+ g_get_current_time (&(device->priv->time_added));
+}
+
+const char *
+hal_device_get_property_string (HalDevice *device, const char *key)
+{
+ const char *ret;
+
+ ret = libhal_ps_get_string (device->priv->properties, key);
+ if (ret != NULL)
+ return ret;
+
+ /* play it safe and don't make clients crash */
+ return "";
+}
+
+int
+hal_device_get_property_int (HalDevice *device, const char *key)
+{
+ return libhal_ps_get_int32 (device->priv->properties, key);
+}
+
+double
+hal_device_get_property_double (HalDevice *device, const char *key)
+{
+ return libhal_ps_get_double (device->priv->properties, key);
+}
+
+guint64
+hal_device_get_property_uint64 (HalDevice *device, const char *key)
+{
+ return libhal_ps_get_uint64 (device->priv->properties, key);
+}
+
+gboolean
+hal_device_get_property_bool (HalDevice *device, const char *key)
+{
+ return libhal_ps_get_bool (device->priv->properties, key);
+}
+
+char **
+hal_device_get_property_strlist (HalDevice *device, const char *key)
+{
+ static char * empty[1] = {NULL};
+ char **ret;
+
+ ret = (char **) libhal_ps_get_strlist (device->priv->properties, key);
+ if (ret != NULL)
+ return (char **) ret;
+
+ /* play it safe and don't make clients crash */
+ return empty;
+}
+
+gboolean
+hal_device_has_capability (HalDevice *device, const char *capability)
+{
+ int n;
+ char **caps;
+ gboolean ret;
+
+ ret = FALSE;
+ caps = hal_device_get_property_strlist (device, "info.capabilities");
+ if (caps == NULL)
+ goto out;
+
+ for (n = 0; caps[n] != NULL; n++)
+ {
+ if (g_ascii_strcasecmp (caps[n], capability) == 0)
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ out:
+ return ret;
+}
+
+gboolean
+hal_device_has_interface (HalDevice *device, const char *interface)
+{
+ int n;
+ char **ifs;
+ gboolean ret;
+
+ ret = FALSE;
+ ifs = hal_device_get_property_strlist (device, "info.interfaces");
+ if (ifs == NULL)
+ goto out;
+
+ for (n = 0; ifs[n] != NULL; n++)
+ {
+ if (g_ascii_strcasecmp (ifs[n], interface) == 0)
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+
+out:
+ return ret;
+}
+
+gboolean
+hal_device_has_property (HalDevice *device, const char *key)
+{
+ gboolean ret;
+ LibHalPropertySetIterator it;
+
+ ret = FALSE;
+ if (device->priv->properties == NULL)
+ goto out;
+
+ libhal_psi_init (&it, device->priv->properties);
+
+ while (libhal_psi_has_more (&it))
+ {
+ char *pkey = libhal_psi_get_key (&it);
+
+ if (pkey != NULL && g_ascii_strcasecmp (pkey, key) == 0)
+ {
+ ret = TRUE;
+ break;
+ }
+ libhal_psi_next (&it);
+ }
+
+ out:
+ return ret;
+}
+
+
+HalDevice *
+hal_device_new_from_udi (LibHalContext *hal_ctx, const char *udi)
+{
+ HalDevice *device;
+
+ device = HAL_DEVICE (g_object_new (HAL_TYPE_DEVICE, NULL));
+ device->priv->udi = g_strdup (udi);
+ device->priv->hal_ctx = hal_ctx;
+ device->priv->properties = libhal_device_get_all_properties (hal_ctx, udi, NULL);
+ return device;
+}
+
+HalDevice *
+hal_device_new_from_udi_and_properties (LibHalContext *hal_ctx,
+ char *udi,
+ LibHalPropertySet *properties)
+{
+ HalDevice *device;
+
+ device = HAL_DEVICE (g_object_new (HAL_TYPE_DEVICE, NULL));
+ device->priv->udi = g_strdup (udi);
+ device->priv->hal_ctx = hal_ctx;
+ device->priv->properties = properties;
+ return device;
+}
+
+void
+_hal_device_hal_property_changed (HalDevice *device, const char *key);
+
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail);
+
+void
+_hal_device_hal_property_changed (HalDevice *device, const char *key)
+{
+ LibHalPropertySet *new_props;
+
+ new_props = libhal_device_get_all_properties (device->priv->hal_ctx, device->priv->udi, NULL);
+ if (new_props != NULL)
+ {
+ libhal_free_property_set (device->priv->properties);
+ device->priv->properties = new_props;
+ g_signal_emit (device, signals[HAL_PROPERTY_CHANGED], 0, key);
+ }
+}
+
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail)
+{
+ g_signal_emit (device, signals[HAL_CONDITION], 0, name, detail);
+}
+
+const char *
+hal_device_get_udi (HalDevice *device)
+{
+ return device->priv->udi;
+}
+
+LibHalPropertySet *
+hal_device_get_properties (HalDevice *device)
+{
+ return device->priv->properties;
+}
+
+gboolean
+hal_device_is_recently_plugged_in (HalDevice *device)
+{
+ GTimeVal now;
+ glong delta_msec;
+
+ g_get_current_time (&now);
+
+ delta_msec = (now.tv_sec - device->priv->time_added.tv_sec) * 1000 +
+ (now.tv_usec - device->priv->time_added.tv_usec) / 1000;
+
+ return delta_msec < 2000;
+}
diff --git a/gnome-2-24/monitor/hal/hal-device.h b/gnome-2-24/monitor/hal/hal-device.h
new file mode 100644
index 00000000..8e91aa63
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-device.h
@@ -0,0 +1,93 @@
+/* hal-device.h
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * 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.
+ */
+
+#ifndef HAL_DEVICE_H
+#define HAL_DEVICE_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <libhal.h>
+
+#define HAL_TYPE_DEVICE (hal_device_get_type ())
+#define HAL_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), HAL_TYPE_DEVICE, HalDevice))
+#define HAL_DEVICE_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), HAL_DEVICE, HalDeviceClass))
+#define HAL_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), HAL_TYPE_DEVICE))
+#define HAL_IS_DEVICE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), HAL_TYPE_DEVICE))
+#define HAL_DEVICE_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), HAL_TYPE_DEVICE, HalDeviceClass))
+
+
+typedef struct _HalDevice HalDevice;
+typedef struct _HalDeviceClass HalDeviceClass;
+
+struct _HalDevicePrivate;
+typedef struct _HalDevicePrivate HalDevicePrivate;
+
+struct _HalDevice
+{
+ GObject parent;
+
+ /* private */
+ HalDevicePrivate *priv;
+};
+
+struct _HalDeviceClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*hal_property_changed) (HalDevice *device, const char *key);
+ void (*hal_condition) (HalDevice *device, const char *name, const char *detail);
+};
+
+
+GType hal_device_get_type (void);
+
+HalDevice * hal_device_new_from_udi (LibHalContext *hal_ctx,
+ const char *udi);
+
+HalDevice * hal_device_new_from_udi_and_properties (LibHalContext *hal_ctx,
+ char *udi,
+ LibHalPropertySet *properties);
+
+const char * hal_device_get_udi (HalDevice *device);
+LibHalPropertySet * hal_device_get_properties (HalDevice *device);
+const char * hal_device_get_property_string (HalDevice *device,
+ const char *key);
+int hal_device_get_property_int (HalDevice *device,
+ const char *key);
+guint64 hal_device_get_property_uint64 (HalDevice *device,
+ const char *key);
+double hal_device_get_property_double (HalDevice *device,
+ const char *key);
+gboolean hal_device_get_property_bool (HalDevice *device,
+ const char *key);
+char ** hal_device_get_property_strlist (HalDevice *device,
+ const char *key);
+
+gboolean hal_device_has_property (HalDevice *device,
+ const char *key);
+gboolean hal_device_has_capability (HalDevice *device,
+ const char *capability);
+gboolean hal_device_has_interface (HalDevice *device,
+ const char *interface);
+
+gboolean hal_device_is_recently_plugged_in (HalDevice *device);
+
+#endif /* HAL_DEVICE_H */
diff --git a/gnome-2-24/monitor/hal/hal-marshal.list b/gnome-2-24/monitor/hal/hal-marshal.list
new file mode 100644
index 00000000..52c82338
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-marshal.list
@@ -0,0 +1,3 @@
+VOID:OBJECT,STRING
+VOID:OBJECT,STRING,STRING
+VOID:STRING,STRING
diff --git a/gnome-2-24/monitor/hal/hal-pool.c b/gnome-2-24/monitor/hal/hal-pool.c
new file mode 100644
index 00000000..770effd9
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-pool.c
@@ -0,0 +1,458 @@
+/* hal-pool.c
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <gdbusutils.h>
+
+#include "hal-pool.h"
+#include "hal-marshal.h"
+
+enum {
+ DEVICE_ADDED,
+ DEVICE_REMOVED,
+ DEVICE_PROPERTY_CHANGED,
+ DEVICE_CONDITION,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _HalPoolPrivate
+{
+ char **cap_only;
+
+ DBusConnection *dbus_connection;
+ LibHalContext *hal_ctx;
+ GHashTable *devices;
+};
+
+G_DEFINE_TYPE (HalPool, hal_pool, G_TYPE_OBJECT)
+
+static void
+hal_pool_finalize (HalPool *pool)
+{
+ g_strfreev (pool->priv->cap_only);
+
+ dbus_bus_remove_match (pool->priv->dbus_connection,
+ "type='signal',"
+ "interface='org.freedesktop.Hal.Device',"
+ "sender='org.freedesktop.Hal'", NULL);
+ libhal_ctx_shutdown (pool->priv->hal_ctx, NULL);
+ dbus_connection_close (pool->priv->dbus_connection);
+ dbus_connection_unref (pool->priv->dbus_connection);
+
+ if (G_OBJECT_CLASS (hal_pool_parent_class)->finalize)
+ (* G_OBJECT_CLASS (hal_pool_parent_class)->finalize) (G_OBJECT (pool));
+}
+
+static void
+hal_pool_class_init (HalPoolClass *klass)
+{
+ GObjectClass *obj_class = (GObjectClass *) klass;
+
+ obj_class->finalize = (GObjectFinalizeFunc) hal_pool_finalize;
+
+ g_type_class_ref (HAL_TYPE_DEVICE);
+
+ signals[DEVICE_ADDED] =
+ g_signal_new ("device_added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalPoolClass, device_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ HAL_TYPE_DEVICE);
+
+ signals[DEVICE_REMOVED] =
+ g_signal_new ("device_removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalPoolClass, device_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ HAL_TYPE_DEVICE);
+
+ signals[DEVICE_PROPERTY_CHANGED] =
+ g_signal_new ("device_property_changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalPoolClass, device_property_changed),
+ NULL, NULL,
+ hal_marshal_VOID__OBJECT_STRING,
+ G_TYPE_NONE, 2,
+ HAL_TYPE_DEVICE,
+ G_TYPE_STRING);
+
+ signals[DEVICE_CONDITION] =
+ g_signal_new ("device_condition",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalPoolClass, device_condition),
+ NULL, NULL,
+ hal_marshal_VOID__OBJECT_STRING_STRING,
+ G_TYPE_NONE, 3,
+ HAL_TYPE_DEVICE,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+}
+
+static void
+hal_pool_init (HalPool *pool)
+{
+ pool->priv = g_new0 (HalPoolPrivate, 1);
+ pool->priv->hal_ctx = NULL;
+}
+
+static gboolean
+has_cap_only (HalPool *pool, HalDevice *device)
+{
+ const char *subsys;
+ unsigned int n;
+
+ for (n = 0; pool->priv->cap_only != NULL && pool->priv->cap_only[n] != NULL; n++)
+ {
+ if (hal_device_has_capability (device, pool->priv->cap_only[n]))
+ return TRUE;
+
+ subsys = hal_device_get_property_string (device, "info.subsystem");
+
+ if (subsys != NULL && strcmp (subsys, pool->priv->cap_only[n]) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+hal_pool_add_device_by_udi (HalPool *pool,
+ const char *udi,
+ gboolean emit_signal)
+{
+ HalDevice *device;
+
+ device = hal_device_new_from_udi (pool->priv->hal_ctx, udi);
+ if (device != NULL)
+ {
+ if (!has_cap_only (pool, device))
+ g_object_unref (device);
+ else
+ {
+ g_hash_table_insert (pool->priv->devices, g_strdup (udi), device);
+ if (emit_signal)
+ g_signal_emit (pool, signals[DEVICE_ADDED], 0, device);
+ }
+ }
+}
+
+#ifdef HAVE_HAL_FAST_INIT
+static void
+hal_pool_add_device_by_udi_and_properties (HalPool *pool,
+ char *udi,
+ LibHalPropertySet *properties,
+ gboolean emit_signal)
+{
+ HalDevice *device;
+
+ device = hal_device_new_from_udi_and_properties (pool->priv->hal_ctx, udi, properties);
+ if (device != NULL)
+ {
+ if (!has_cap_only (pool, device))
+ g_object_unref (device);
+ else
+ {
+ g_hash_table_insert (pool->priv->devices, g_strdup (udi), device);
+ if (emit_signal)
+ g_signal_emit (pool, signals[DEVICE_ADDED], 0, device);
+ }
+ }
+}
+#endif
+
+static void
+_hal_device_added (LibHalContext *hal_ctx, const char *udi)
+{
+ HalPool *pool;
+
+ pool = HAL_POOL (libhal_ctx_get_user_data (hal_ctx));
+ hal_pool_add_device_by_udi (pool, udi, TRUE);
+}
+
+static void
+_hal_device_removed (LibHalContext *hal_ctx, const char *udi)
+{
+ HalPool *pool;
+ HalDevice *device;
+
+ pool = HAL_POOL (libhal_ctx_get_user_data (hal_ctx));
+ if ((device = hal_pool_get_device_by_udi (pool, udi)) != NULL)
+ {
+ g_object_ref (device);
+ g_hash_table_remove (pool->priv->devices, udi);
+ g_signal_emit (pool, signals[DEVICE_REMOVED], 0, device);
+ g_object_unref (device);
+ }
+}
+
+void
+_hal_device_hal_property_changed (HalDevice *device, const char *key);
+
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail);
+
+static void
+_hal_property_modified (LibHalContext *ctx,
+ const char *udi,
+ const char *key,
+ dbus_bool_t is_removed,
+ dbus_bool_t is_added)
+{
+ HalPool *pool;
+ HalDevice *device;
+
+ pool = HAL_POOL (libhal_ctx_get_user_data (ctx));
+
+ device = hal_pool_get_device_by_udi (pool, udi);
+ if (device != NULL)
+ {
+ _hal_device_hal_property_changed (device, key);
+ g_signal_emit (pool, signals[DEVICE_PROPERTY_CHANGED], 0, device, key);
+ }
+}
+
+static void
+_hal_condition (LibHalContext *ctx,
+ const char *udi,
+ const char *condition_name,
+ const char *condition_detail)
+{
+ HalPool *pool;
+ HalDevice *device;
+
+ pool = HAL_POOL (libhal_ctx_get_user_data (ctx));
+
+ device = hal_pool_get_device_by_udi (pool, udi);
+ if (device != NULL)
+ {
+ _hal_device_hal_condition (device, condition_name, condition_detail);
+ g_signal_emit (pool, signals[DEVICE_CONDITION], 0, device, condition_name, condition_detail);
+ }
+}
+
+LibHalContext *
+hal_pool_get_hal_ctx (HalPool *pool)
+{
+ return pool->priv->hal_ctx;
+}
+
+DBusConnection *
+hal_pool_get_dbus_connection (HalPool *pool)
+{
+ return pool->priv->dbus_connection;
+}
+
+HalPool *
+hal_pool_new (char **cap_only)
+{
+ int i;
+ char **devices;
+ int num_devices;
+ HalPool *pool;
+ LibHalContext *hal_ctx;
+ DBusError error;
+ DBusConnection *dbus_connection;
+#ifdef HAVE_HAL_FAST_INIT
+ LibHalPropertySet **properties;
+#endif
+
+ pool = NULL;
+
+ dbus_error_init (&error);
+ /* see discussion on gtk-devel-list (Subject: Re: gvfs hal volume monitoring backend) on
+ * why this is private
+ */
+ dbus_connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error);
+ if (dbus_error_is_set (&error))
+ {
+ dbus_error_free (&error);
+ goto out;
+ }
+
+ dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
+
+ hal_ctx = libhal_ctx_new ();
+ if (hal_ctx == NULL)
+ {
+ dbus_connection_close (dbus_connection);
+ dbus_connection_unref (dbus_connection);
+ goto out;
+ }
+
+ _g_dbus_connection_integrate_with_main (dbus_connection);
+ libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
+
+ if (!libhal_ctx_init (hal_ctx, &error))
+ {
+ dbus_connection_close (dbus_connection);
+ dbus_connection_unref (dbus_connection);
+ dbus_error_free (&error);
+ goto out;
+ }
+
+ pool = HAL_POOL (g_object_new (HAL_TYPE_POOL, NULL));
+ pool->priv->dbus_connection = dbus_connection;
+ pool->priv->hal_ctx = hal_ctx;
+ pool->priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ pool->priv->cap_only = g_strdupv (cap_only);
+
+ /* Gah, unfortunately we have to watch all devices as HAL's PropertyModified signal
+ * doesn't include the capabilities...
+ */
+ dbus_bus_add_match (dbus_connection,
+ "type='signal',"
+ "interface='org.freedesktop.Hal.Device',"
+ "sender='org.freedesktop.Hal'", NULL);
+ libhal_ctx_set_device_added (hal_ctx, _hal_device_added);
+ libhal_ctx_set_device_removed (hal_ctx, _hal_device_removed);
+ libhal_ctx_set_device_property_modified (hal_ctx, _hal_property_modified);
+ libhal_ctx_set_device_condition (hal_ctx, _hal_condition);
+ libhal_ctx_set_user_data (hal_ctx, pool);
+
+#ifdef HAVE_HAL_FAST_INIT
+ /* First try new O(1) algorithm to get all devices and properties in a single call..
+ *
+ * This method is only available in post hal 0.5.10.
+ */
+ if (libhal_get_all_devices_with_properties (pool->priv->hal_ctx,
+ &num_devices,
+ &devices,
+ &properties,
+ NULL))
+ {
+ for (i = 0; i < num_devices; i++)
+ hal_pool_add_device_by_udi_and_properties (pool, devices[i], properties[i], FALSE);
+ libhal_free_string_array (devices);
+ free (properties); /* hal_pool_add_device_by_udi_and_properties steals the given properties */
+ goto out;
+ }
+#endif
+
+ /* fallback to using O(n) algorithm; will work on any hal 0.5.x release */
+ devices = libhal_get_all_devices (pool->priv->hal_ctx, &num_devices, NULL);
+ if (devices != NULL)
+ {
+ for (i = 0; i < num_devices; i++)
+ {
+ char *device_udi;
+ device_udi = devices[i];
+ hal_pool_add_device_by_udi (pool, device_udi, FALSE);
+ }
+ libhal_free_string_array (devices);
+ goto out;
+ }
+
+ /* FAIL! */
+
+ g_object_unref (pool);
+ return NULL;
+
+ out:
+ return pool;
+}
+
+HalDevice *
+hal_pool_get_device_by_udi (HalPool *pool, const char *udi)
+{
+ return g_hash_table_lookup (pool->priv->devices, udi);
+}
+
+HalDevice *
+hal_pool_get_device_by_capability_and_string (HalPool *pool,
+ const char *capability,
+ const char *key,
+ const char *value)
+{
+ GList *i;
+ GList *devices;
+ HalDevice *result;
+
+ result = NULL;
+ devices = NULL;
+
+ if (pool->priv->devices == NULL)
+ goto out;
+
+ devices = g_hash_table_get_values (pool->priv->devices);
+ for (i = devices; i != NULL; i = i->next)
+ {
+ HalDevice *d = i->data;
+ const char *s;
+
+ if (!hal_device_has_capability (d, capability))
+ continue;
+
+ s = hal_device_get_property_string (d, key);
+ if (s == NULL)
+ continue;
+
+ if (strcmp (s, value) == 0)
+ {
+ result = d;
+ goto out;
+ }
+ }
+
+out:
+ if (devices != NULL)
+ g_list_free (devices);
+ return result;
+}
+
+GList *
+hal_pool_find_by_capability (HalPool *pool, const char *capability)
+{
+ GList *i;
+ GList *j;
+ GList *devices;
+
+ devices = NULL;
+
+ if (pool->priv->devices == NULL)
+ goto out;
+
+ devices = g_hash_table_get_values (pool->priv->devices);
+ for (i = devices; i != NULL; i = j)
+ {
+ HalDevice *d = i->data;
+
+ j = i->next;
+
+ if (!hal_device_has_capability (d, capability))
+ devices = g_list_delete_link (devices, i);
+ }
+
+ out:
+ return devices;
+}
diff --git a/gnome-2-24/monitor/hal/hal-pool.h b/gnome-2-24/monitor/hal/hal-pool.h
new file mode 100644
index 00000000..04c8687d
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-pool.h
@@ -0,0 +1,74 @@
+/* hal-pool.h
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * 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.
+ */
+
+#if !defined(HAL_POOL_H)
+#define HAL_POOL_H
+
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+#include "hal-device.h"
+
+#define HAL_TYPE_POOL (hal_pool_get_type ())
+#define HAL_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), HAL_TYPE_POOL, HalPool))
+#define HAL_POOL_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), HAL_POOL, HalPoolClass))
+#define HAL_IS_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), HAL_TYPE_POOL))
+#define HAL_IS_POOL_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), HAL_TYPE_POOL))
+#define HAL_POOL_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), HAL_TYPE_POOL, HalPoolClass))
+
+
+typedef struct _HalPool HalPool;
+typedef struct _HalPoolClass HalPoolClass;
+
+struct _HalPoolPrivate;
+typedef struct _HalPoolPrivate HalPoolPrivate;
+
+struct _HalPool
+{
+ GObject parent;
+
+ /* private */
+ HalPoolPrivate *priv;
+};
+
+struct _HalPoolClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*device_added) (HalPool *pool, HalDevice *device);
+ void (*device_removed) (HalPool *pool, HalDevice *device);
+ void (*device_property_changed) (HalPool *pool, HalDevice *device, const char *key);
+ void (*device_condition) (HalPool *pool, HalDevice *device, const char *name, const char *detail);
+};
+
+GType hal_pool_get_type (void);
+HalPool * hal_pool_new (char **cap_only);
+LibHalContext * hal_pool_get_hal_ctx (HalPool *pool);
+DBusConnection * hal_pool_get_dbus_connection (HalPool *pool);
+HalDevice * hal_pool_get_device_by_udi (HalPool *pool,
+ const char *udi);
+HalDevice * hal_pool_get_device_by_capability_and_string (HalPool *pool,
+ const char *capability,
+ const char *key,
+ const char *value);
+GList * hal_pool_find_by_capability (HalPool *pool,
+ const char *capability);
+
+#endif /* HAL_POOL_H */
diff --git a/gnome-2-24/monitor/hal/hal-utils.c b/gnome-2-24/monitor/hal/hal-utils.c
new file mode 100644
index 00000000..6bf0cd8c
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-utils.c
@@ -0,0 +1,171 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ * Christian Kellner <gicmo@gnome.org>
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "string.h"
+
+#include "hal-utils.h"
+
+static const struct {
+ const char *disc_type;
+ const char *icon_name;
+ char *ui_name;
+ char *ui_name_blank;
+} disc_data[] = {
+ {"cd_rom", "media-optical-cd-rom", N_("CD-ROM Disc"), N_("Blank CD-ROM Disc")},
+ {"cd_r", "media-optical-cd-r", N_("CD-R Disc"), N_("Blank CD-R Disc")},
+ {"cd_rw", "media-optical-cd-rw", N_("CD-RW Disc"), N_("Blank CD-RW Disc")},
+ {"dvd_rom", "media-optical-dvd-rom", N_("DVD-ROM Disc"), N_("Blank DVD-ROM Disc")},
+ {"dvd_ram", "media-optical-dvd-ram", N_("DVD-RAM Disc"), N_("Blank DVD-RAM Disc")},
+ {"dvd_r", "media-optical-dvd-r", N_("DVD-ROM Disc"), N_("Blank DVD-ROM Disc")},
+ {"dvd_rw", "media-optical-dvd-rw", N_("DVD-RW Disc"), N_("Blank DVD-RW Disc")},
+ {"dvd_plus_r", "media-optical-dvd-r-plus", N_("DVD+R Disc"), N_("Blank DVD+R Disc")},
+ {"dvd_plus_rw", "media-optical-dvd-rw-plus", N_("DVD+RW Disc"), N_("Blank DVD+RW Disc")},
+ {"dvd_plus_r_dl", "media-optical-dvd-dl-r-plus", N_("DVD+R DL Disc"), N_("Blank DVD+R DL Disc")},
+ {"bd_rom", "media-optical-bd-rom", N_("Blu-Ray Disc"), N_("Blank Blu-Ray Disc")},
+ {"bd_r", "media-optical-bd-r", N_("Blu-Ray R Disc"), N_("Blank Blu-Ray R Disc")},
+ {"bd_re", "media-optical-bd-re", N_("Blu-Ray RW Disc"), N_("Blank Blu-Ray RW Disc")},
+ {"hddvd_rom", "media-optical-hddvd-rom", N_("HD DVD Disc"), N_("Blank HD DVD Disc")},
+ {"hddvd_r", "media-optical-hddvd-r", N_("HD DVD-R Disc"), N_("Blank HD DVD-R Disc")},
+ {"hddvd_rw", "media-optical-hddvd-rw", N_("HD DVD-RW Disc"), N_("Blank HD DVD-RW Disc")},
+ {"mo", "media-optical-mo", N_("MO Disc"), N_("Blank MO Disc")},
+ {NULL, "media-optical", N_("Disc"), N_("Blank Disc")}
+};
+
+const char *
+get_disc_icon (const char *disc_type)
+{
+ int n;
+
+ for (n = 0; disc_data[n].disc_type != NULL; n++)
+ {
+ if (strcmp (disc_data[n].disc_type, disc_type) == 0)
+ break;
+ }
+
+ return disc_data[n].icon_name;
+}
+
+const char *
+get_disc_name (const char *disc_type, gboolean is_blank)
+{
+ int n;
+
+ for (n = 0; disc_data[n].disc_type != NULL; n++)
+ {
+ if (strcmp (disc_data[n].disc_type, disc_type) == 0)
+ break;
+ }
+
+ if (is_blank)
+ return dgettext (GETTEXT_PACKAGE, disc_data[n].ui_name_blank);
+ else
+ return dgettext (GETTEXT_PACKAGE, disc_data[n].ui_name);
+}
+
+/*
+ * Creates a GThemedIcon from icon_name and creates default
+ * fallbacks from fallbacks. Is smart in the case that icon_name
+ * and fallbacks are identically.
+ * Note: See the GThemedIcon documentation for more information
+ * on default fallbacks
+ */
+GIcon *
+get_themed_icon_with_fallbacks (const char *icon_name,
+ const char *fallbacks)
+{
+ int i = 0, dashes = 0;
+ const char *p;
+ char *dashp;
+ char *last;
+ char **names;
+ GIcon *icon;
+
+ if (G_UNLIKELY (icon_name == NULL))
+ return NULL;
+
+ if (fallbacks == NULL)
+ return g_themed_icon_new (icon_name);
+
+ p = fallbacks;
+ while (*p)
+ {
+ if (*p == '-')
+ dashes++;
+ p++;
+ }
+
+ if (strcmp (icon_name, fallbacks))
+ {
+ names = g_new (char *, dashes + 3);
+ names[i++] = g_strdup (icon_name);
+ }
+ else
+ names = g_new (char *, dashes + 2);
+
+ names[i++] = last = g_strdup (fallbacks);
+
+ while ((dashp = strrchr (last, '-')) != NULL)
+ names[i++] = last = g_strndup (last, dashp - last);
+
+ names[i++] = NULL;
+ icon = g_themed_icon_new_from_names (names, -1);
+ g_strfreev (names);
+
+ return icon;
+}
+
+char **
+dupv_and_uniqify (char **str_array)
+{
+ int n, m, o;
+ int len;
+ char **result;
+
+ result = g_strdupv (str_array);
+ len = g_strv_length (result);
+
+ for (n = 0; n < len; n++)
+ {
+ char *s = result[n];
+ for (m = n + 1; m < len; m++)
+ {
+ char *p = result[m];
+ if (strcmp (s, p) == 0)
+ {
+ for (o = m + 1; o < len; o++)
+ result[o - 1] = result[o];
+ len--;
+ result[len] = NULL;
+ m--;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/gnome-2-24/monitor/hal/hal-utils.h b/gnome-2-24/monitor/hal/hal-utils.h
new file mode 100644
index 00000000..fd737ca2
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-utils.h
@@ -0,0 +1,42 @@
+/* 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: David Zeuthen <davidz@redhat.com>
+ * Chrsitian Kellner <gicmo@gnome.org>
+ */
+
+#ifndef __HAL_UTILS_H__
+#define __HAL_UTILS_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+const char * get_disc_icon (const char *disc_type);
+const char * get_disc_name (const char *disc_type, gboolean is_blank);
+
+GIcon * get_themed_icon_with_fallbacks (const char *icon_name,
+ const char *fallbacks);
+
+char **dupv_and_uniqify (char **str_array);
+
+G_END_DECLS
+
+#endif /* __HAL_UTILS_H__ */
diff --git a/gnome-2-24/monitor/hal/hal-volume-monitor-daemon.c b/gnome-2-24/monitor/hal/hal-volume-monitor-daemon.c
new file mode 100644
index 00000000..6f83175d
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal-volume-monitor-daemon.c
@@ -0,0 +1,43 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2008 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: David Zeuthen <davidz@redhat.com>
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <gio/gio.h>
+
+#include <gvfsproxyvolumemonitordaemon.h>
+
+#include "ghalvolumemonitor.h"
+
+int
+main (int argc, char *argv[])
+{
+ g_vfs_proxy_volume_monitor_daemon_init ();
+ return g_vfs_proxy_volume_monitor_daemon_main (argc,
+ argv,
+ "org.gtk.Private.HalVolumeMonitor",
+ G_TYPE_HAL_VOLUME_MONITOR);
+}
diff --git a/gnome-2-24/monitor/hal/hal.monitor b/gnome-2-24/monitor/hal/hal.monitor
new file mode 100644
index 00000000..c287f853
--- /dev/null
+++ b/gnome-2-24/monitor/hal/hal.monitor
@@ -0,0 +1,5 @@
+[RemoteVolumeMonitor]
+Name=GProxyVolumeMonitorHal
+DBusName=org.gtk.Private.HalVolumeMonitor
+IsNative=true
+NativePriority=2
diff --git a/gnome-2-24/monitor/hal/org.gtk.Private.HalVolumeMonitor.service.in b/gnome-2-24/monitor/hal/org.gtk.Private.HalVolumeMonitor.service.in
new file mode 100644
index 00000000..c785241d
--- /dev/null
+++ b/gnome-2-24/monitor/hal/org.gtk.Private.HalVolumeMonitor.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gtk.Private.HalVolumeMonitor
+Exec=@libexecdir@/gvfs-hal-volume-monitor