From 953132a87aed73507042a6279b343523741a1800 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 24 Sep 2008 12:40:53 +0000 Subject: Tagged for release 1.0.1 svn path=/tags/GVFS_1_0_1/; revision=2025 --- gnome-2-24/monitor/hal/Makefile.am | 62 + gnome-2-24/monitor/hal/ghaldrive.c | 1009 +++++++++++++ gnome-2-24/monitor/hal/ghaldrive.h | 62 + gnome-2-24/monitor/hal/ghalmount.c | 1592 ++++++++++++++++++++ gnome-2-24/monitor/hal/ghalmount.h | 76 + gnome-2-24/monitor/hal/ghalvolume.c | 1068 +++++++++++++ gnome-2-24/monitor/hal/ghalvolume.h | 84 ++ gnome-2-24/monitor/hal/ghalvolumemonitor.c | 1399 +++++++++++++++++ gnome-2-24/monitor/hal/ghalvolumemonitor.h | 58 + gnome-2-24/monitor/hal/hal-device.c | 297 ++++ gnome-2-24/monitor/hal/hal-device.h | 93 ++ gnome-2-24/monitor/hal/hal-marshal.list | 3 + gnome-2-24/monitor/hal/hal-pool.c | 458 ++++++ gnome-2-24/monitor/hal/hal-pool.h | 74 + gnome-2-24/monitor/hal/hal-utils.c | 171 +++ gnome-2-24/monitor/hal/hal-utils.h | 42 + gnome-2-24/monitor/hal/hal-volume-monitor-daemon.c | 43 + gnome-2-24/monitor/hal/hal.monitor | 5 + .../org.gtk.Private.HalVolumeMonitor.service.in | 3 + 19 files changed, 6599 insertions(+) create mode 100644 gnome-2-24/monitor/hal/Makefile.am create mode 100644 gnome-2-24/monitor/hal/ghaldrive.c create mode 100644 gnome-2-24/monitor/hal/ghaldrive.h create mode 100644 gnome-2-24/monitor/hal/ghalmount.c create mode 100644 gnome-2-24/monitor/hal/ghalmount.h create mode 100644 gnome-2-24/monitor/hal/ghalvolume.c create mode 100644 gnome-2-24/monitor/hal/ghalvolume.h create mode 100644 gnome-2-24/monitor/hal/ghalvolumemonitor.c create mode 100644 gnome-2-24/monitor/hal/ghalvolumemonitor.h create mode 100644 gnome-2-24/monitor/hal/hal-device.c create mode 100644 gnome-2-24/monitor/hal/hal-device.h create mode 100644 gnome-2-24/monitor/hal/hal-marshal.list create mode 100644 gnome-2-24/monitor/hal/hal-pool.c create mode 100644 gnome-2-24/monitor/hal/hal-pool.h create mode 100644 gnome-2-24/monitor/hal/hal-utils.c create mode 100644 gnome-2-24/monitor/hal/hal-utils.h create mode 100644 gnome-2-24/monitor/hal/hal-volume-monitor-daemon.c create mode 100644 gnome-2-24/monitor/hal/hal.monitor create mode 100644 gnome-2-24/monitor/hal/org.gtk.Private.HalVolumeMonitor.service.in (limited to 'gnome-2-24/monitor/hal') 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 + */ + +#include + +#include +#include +#include + +#include +#include + +#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 + */ + +#ifndef __G_HAL_DRIVE_H__ +#define __G_HAL_DRIVE_H__ + +#include +#include + +#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 + */ + +#include + +#include +#include +#include + +#include +#include +#include + +#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 + */ + +#ifndef __G_HAL_MOUNT_H__ +#define __G_HAL_MOUNT_H__ + +#include +#include + +#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 + */ + +#include + +#include +#include +#include + +#include +#include +#include + +#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 + */ + +#ifndef __G_HAL_VOLUME_H__ +#define __G_HAL_VOLUME_H__ + +#include +#include + +#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 + */ + +#include + +#include +#include +#include + +#include +#include +#include + +#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 + */ + +#ifndef __G_HAL_VOLUME_MONITOR_H__ +#define __G_HAL_VOLUME_MONITOR_H__ + +#include +#include +#include + +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 +#include +#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 +#include +#include + +#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 +#include +#include +#include + +#include + +#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 +#include +#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 + * Christian Kellner + */ + +#include + +#include +#include +#include + +#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 + * Chrsitian Kellner + */ + +#ifndef __HAL_UTILS_H__ +#define __HAL_UTILS_H__ + +#include +#include + +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 + */ + +#include + +#include +#include +#include +#include + +#include + +#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 -- cgit v1.2.1