Hi, Here's the first half of the gphoto2 support for gvfs. This patch adds support for creating/destroying GVolume objects in the volume monitor representing connected cameras supported by gphoto2. The other half is the actual backend code; I'll submit that later.
Here's a screenshot showing three gphoto2 supported devices. http://people.freedesktop.org/~david/gvfs-gphoto2-1.png David
Index: ChangeLog =================================================================== --- ChangeLog (revision 1147) +++ ChangeLog (working copy) @@ -1,3 +1,23 @@ +2008-01-18 David Zeuthen <[EMAIL PROTECTED]> + + The volume monitor bits of gphoto2 support. The actual backend + will follow later. Right now the code is only enabled on Linux, + need trivial changes to work on other operating systems. + + * hal/ghalvolume.c: (do_update_from_hal_for_camera), + (update_from_hal), (g_hal_volume_new): + * hal/ghalvolumemonitor.c: (get_hal_pool), + (g_hal_volume_monitor_finalize), (get_volumes), + (mountpoints_changed), (mounts_changed), + (g_hal_volume_monitor_force_update), (hal_changed), + (g_hal_volume_monitor_constructor), (find_camera_volume_by_udi), + (update_cameras): + * hal/ghalvolumemonitor.h: + * hal/hal-pool.c: (hal_pool_finalize), (has_cap_only), + (hal_pool_add_device_by_udi), + (hal_pool_add_device_by_udi_and_properties), (hal_pool_new): + * hal/hal-pool.h: + 2008-01-17 Christian Kellner <[EMAIL PROTECTED]> * daemon/gvfsbackenddav.c: Index: hal/ghalvolume.c =================================================================== --- hal/ghalvolume.c (revision 1147) +++ hal/ghalvolume.c (working copy) @@ -289,7 +289,37 @@ (GDestroyNotify) g_free); } +#ifdef _WITH_GPHOTO2 static void +do_update_from_hal_for_camera (GHalVolume *v) +{ + const char *vendor; + const char *product; + + vendor = hal_device_get_property_string (v->drive_device, "usb_device.vendor"); + product = hal_device_get_property_string (v->drive_device, "usb_device.product"); + + if (vendor == NULL) + { + if (product != NULL) + v->name = g_strdup (product); + else + v->name = g_strdup (_("Camera")); + } + else + { + if (product != NULL) + v->name = g_strdup_printf ("%s %s", vendor, product); + else + v->name = g_strdup_printf (_("%s Camera"), vendor); + } + + v->icon = g_strdup ("camera"); + v->mount_path = NULL; +} +#endif + +static void update_from_hal (GHalVolume *mv, gboolean emit_changed) { char *old_name; @@ -303,7 +333,14 @@ g_free (mv->name); g_free (mv->icon); g_free (mv->mount_path); - do_update_from_hal (mv); +#ifdef _WITH_GPHOTO2 + if (hal_device_has_capability (mv->device, "camera")) + do_update_from_hal_for_camera (mv); + else + do_update_from_hal (mv); +#else + do_update_from_hal (mv); +#endif if (emit_changed) { @@ -380,20 +417,53 @@ GHalVolume *volume; HalDevice *drive_device; const char *storage_udi; + const char *device_path; - storage_udi = hal_device_get_property_string (device, "block.storage_device"); - if (storage_udi == NULL) - return NULL; + 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; - + 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"); + } +#ifdef _WITH_GPHOTO2 + else if (hal_device_has_capability (device, "camera")) + { + /* OK, so we abuse storage_udi and drive_device for the USB main + * device that holds this interface... + */ + storage_udi = hal_device_get_property_string (device, "info.parent"); + if (storage_udi == NULL) + return NULL; + + drive_device = hal_pool_get_device_by_udi (pool, storage_udi); + if (drive_device == NULL) + return NULL; + + /* TODO: other OS'es? Will address this with DK aka HAL 2.0 */ + device_path = hal_device_get_property_string (drive_device, "linux.device_file"); + if (strlen (device_path) == 0) + device_path = NULL; + + if (foreign_mount_root == NULL) + return NULL; + } +#endif + else + { + return NULL; + } + 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 (hal_device_get_property_string (device, "block.device")); + 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; Index: hal/hal-pool.c =================================================================== --- hal/hal-pool.c (revision 1147) +++ hal/hal-pool.c (working copy) @@ -42,7 +42,7 @@ struct _HalPoolPrivate { - char *cap_only; + char **cap_only; DBusConnection *dbus_connection; LibHalContext *hal_ctx; @@ -54,7 +54,7 @@ static void hal_pool_finalize (HalPool *pool) { - g_free (pool->priv->cap_only); + g_strfreev (pool->priv->cap_only); dbus_bus_remove_match (pool->priv->dbus_connection, "type='signal'," @@ -134,6 +134,25 @@ pool->priv->hal_ctx = NULL; } +static gboolean +has_cap_only (HalPool *pool, HalDevice *device) +{ + unsigned int n; + + if (pool->priv->cap_only) + return TRUE; + + for (n = 0; pool->priv->cap_only[n] != NULL; n++) + { + if (hal_device_has_capability (device, pool->priv->cap_only[n])) + { + return TRUE; + } + } + + return FALSE; +} + static void hal_pool_add_device_by_udi (HalPool *pool, const char *udi, @@ -144,7 +163,7 @@ if (device != NULL) { - if (pool->priv->cap_only != NULL && !hal_device_has_capability (device, pool->priv->cap_only)) + if (!has_cap_only (pool, device)) { g_object_unref (device); } @@ -169,7 +188,7 @@ if (device != NULL) { - if (pool->priv->cap_only != NULL && !hal_device_has_capability (device, pool->priv->cap_only)) + if (!has_cap_only (pool, device)) { g_object_unref (device); } @@ -266,7 +285,7 @@ } HalPool * -hal_pool_new (const char *cap_only) +hal_pool_new (char **cap_only) { int i; char **devices; @@ -311,7 +330,7 @@ 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_strdup (cap_only); + 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... Index: hal/ghalvolumemonitor.c =================================================================== --- hal/ghalvolumemonitor.c (revision 1147) +++ hal/ghalvolumemonitor.c (working copy) @@ -54,6 +54,7 @@ HalPool *pool; + GList *last_camera_devices;; GList *last_optical_disc_devices; GList *last_drive_devices; GList *last_volume_devices; @@ -67,6 +68,9 @@ /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */ GList *disc_volumes; GList *disc_mounts; + + /* Digital cameras (e.g. gphoto2) are kept here */ + GList *camera_volumes; }; static void mountpoints_changed (GUnixMountMonitor *mount_monitor, @@ -80,6 +84,7 @@ static void update_volumes (GHalVolumeMonitor *monitor); static void update_mounts (GHalVolumeMonitor *monitor); static void update_discs (GHalVolumeMonitor *monitor); +static void update_cameras (GHalVolumeMonitor *monitor); #define g_hal_volume_monitor_get_type g_hal_volume_monitor_get_type G_DEFINE_DYNAMIC_TYPE (GHalVolumeMonitor, g_hal_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR); @@ -87,8 +92,10 @@ static HalPool * get_hal_pool (void) { + char *cap_only[] = {"block", "camera", NULL}; + if (pool == NULL) - pool = hal_pool_new ("block"); + pool = hal_pool_new (cap_only); return pool; } @@ -109,6 +116,8 @@ g_object_unref (monitor->mount_monitor); g_object_unref (monitor->pool); + g_list_foreach (monitor->last_camera_devices, (GFunc)g_object_unref, NULL); + g_list_free (monitor->last_optical_disc_devices); g_list_foreach (monitor->last_optical_disc_devices, (GFunc)g_object_unref, NULL); g_list_free (monitor->last_optical_disc_devices); g_list_foreach (monitor->last_drive_devices, (GFunc)g_object_unref, NULL); @@ -131,6 +140,8 @@ g_list_free (monitor->disc_volumes); g_list_foreach (monitor->disc_mounts, (GFunc)g_object_unref, NULL); g_list_free (monitor->disc_mounts); + g_list_foreach (monitor->camera_volumes, (GFunc)g_object_unref, NULL); + g_list_free (monitor->camera_volumes); if (G_OBJECT_CLASS (g_hal_volume_monitor_parent_class)->finalize) (*G_OBJECT_CLASS (g_hal_volume_monitor_parent_class)->finalize) (object); @@ -164,6 +175,8 @@ l = g_list_copy (monitor->volumes); ll = g_list_copy (monitor->disc_volumes); l = g_list_concat (l, ll); + ll = g_list_copy (monitor->camera_volumes); + l = g_list_concat (l, ll); g_list_foreach (l, (GFunc)g_object_ref, NULL); @@ -306,6 +319,7 @@ update_volumes (monitor); update_mounts (monitor); update_discs (monitor); + update_cameras (monitor); } static void @@ -318,6 +332,7 @@ update_volumes (monitor); update_mounts (monitor); update_discs (monitor); + update_cameras (monitor); } void @@ -327,6 +342,7 @@ update_volumes (monitor); update_mounts (monitor); update_discs (monitor); + update_cameras (monitor); } static void @@ -342,6 +358,7 @@ update_volumes (monitor); update_mounts (monitor); update_discs (monitor); + update_cameras (monitor); } static GObject * @@ -396,6 +413,7 @@ update_volumes (monitor); update_mounts (monitor); update_discs (monitor); + update_cameras (monitor); the_volume_monitor = monitor; @@ -651,6 +669,24 @@ return NULL; } +#ifdef _WITH_GPHOTO2 +static GHalVolume * +find_camera_volume_by_udi (GHalVolumeMonitor *monitor, const char *udi) +{ + GList *l; + + for (l = monitor->camera_volumes; l != NULL; l = l->next) + { + GHalVolume *volume = l->data; + + if (g_hal_volume_has_udi (volume, udi)) + return volume; + } + + return NULL; +} +#endif + static gint hal_device_compare (HalDevice *a, HalDevice *b) { @@ -1028,6 +1064,90 @@ monitor->last_optical_disc_devices = new_optical_disc_devices; } +static void +update_cameras (GHalVolumeMonitor *monitor) +{ +#ifdef _WITH_GPHOTO2 + GList *new_camera_devices; + GList *removed, *added; + GList *l, *ll; + GHalVolume *volume; + const char *udi; + + new_camera_devices = hal_pool_find_by_capability (monitor->pool, "camera"); + for (l = new_camera_devices; l != NULL; l = ll) + { + ll = l->next; + HalDevice *d = l->data; + /*g_warning ("got %s", hal_device_get_udi (d));*/ + if (! hal_device_get_property_bool (d, "camera.libgphoto2.support")) + { + /*g_warning ("ignoring %s", hal_device_get_udi (d));*/ + /* filter out everything that isn't supported by libgphoto2 */ + new_camera_devices = g_list_delete_link (new_camera_devices, l); + } + } + g_list_foreach (new_camera_devices, (GFunc) g_object_ref, NULL); + + new_camera_devices = g_list_sort (new_camera_devices, (GCompareFunc) hal_device_compare); + diff_sorted_lists (monitor->last_camera_devices, + new_camera_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 ("camera removing %s", udi);*/ + + volume = find_camera_volume_by_udi (monitor, udi); + if (volume != NULL) + { + g_hal_volume_removed (volume); + monitor->camera_volumes = g_list_remove (monitor->camera_volumes, volume); + g_signal_emit_by_name (monitor, "volume_removed", volume); + g_signal_emit_by_name (volume, "removed"); + g_object_unref (volume); + } + } + + for (l = added; l != NULL; l = l->next) + { + HalDevice *d = l->data; + char *uri; + GFile *foreign_mount_root; + int usb_bus_num; + int usb_device_num; + + usb_bus_num = hal_device_get_property_int (d, "usb.bus_number"); + usb_device_num = hal_device_get_property_int (d, "usb.linux.device_number"); + + uri = g_strdup_printf ("gphoto2://usb:%03d,%03d", usb_bus_num, usb_device_num); + /*g_warning ("uri is '%s'", uri);*/ + foreign_mount_root = g_file_new_for_uri (uri); + g_free (uri); + + udi = hal_device_get_udi (d); + /*g_warning ("camera adding %s", udi);*/ + + volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor), d, monitor->pool, foreign_mount_root, TRUE, NULL); + g_object_unref (foreign_mount_root); + if (volume != NULL) + { + monitor->camera_volumes = g_list_prepend (monitor->camera_volumes, volume); + g_signal_emit_by_name (monitor, "volume_added", volume); + } + } + + g_list_free (added); + g_list_free (removed); + g_list_foreach (monitor->last_camera_devices, (GFunc)g_object_unref, NULL); + g_list_free (monitor->last_camera_devices); + monitor->last_camera_devices = new_camera_devices; +#endif +} + void g_hal_volume_monitor_register (GIOModule *module) { Index: hal/hal-pool.h =================================================================== --- hal/hal-pool.h (revision 1147) +++ hal/hal-pool.h (working copy) @@ -62,7 +62,7 @@ GType hal_pool_get_type (void); void hal_pool_register (GIOModule *module); -HalPool * hal_pool_new (const char *cap_only); +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, Index: hal/ghalvolumemonitor.h =================================================================== --- hal/ghalvolumemonitor.h (revision 1147) +++ hal/ghalvolumemonitor.h (working copy) @@ -29,6 +29,11 @@ #include <gio/gio.h> #include <gio/gunixmounts.h> +/* TODO: need to use different properties on HAL for other OS's (!) */ +#ifdef __linux__ +#define _WITH_GPHOTO2 +#endif + G_BEGIN_DECLS #define G_TYPE_HAL_VOLUME_MONITOR (g_hal_volume_monitor_get_type ())
_______________________________________________ gnome-vfs-list mailing list gnome-vfs-list@gnome.org http://mail.gnome.org/mailman/listinfo/gnome-vfs-list