gvfs r1827 - in trunk: . monitor monitor/gphoto2 monitor/hal po



Author: davidz
Date: Mon Jul 21 21:23:37 2008
New Revision: 1827
URL: http://svn.gnome.org/viewvc/gvfs?rev=1827&view=rev

Log:
2008-07-21  David Zeuthen  <davidz redhat com>

	* configure.ac:
	* monitor/Makefile.am:
	* monitor/hal/*:
	* monitor/gphoto2/*:
	Separate the hal and gphoto2 volume monitors - this is in part
	needed to solve bug #520123.



Added:
   trunk/monitor/gphoto2/
   trunk/monitor/gphoto2/Makefile.am
   trunk/monitor/gphoto2/ggphoto2volume.c
   trunk/monitor/gphoto2/ggphoto2volume.h
   trunk/monitor/gphoto2/ggphoto2volumemonitor.c
   trunk/monitor/gphoto2/ggphoto2volumemonitor.h
   trunk/monitor/gphoto2/gphoto2-volume-monitor-daemon.c
   trunk/monitor/gphoto2/gphoto2.monitor
   trunk/monitor/gphoto2/hal-device.c
   trunk/monitor/gphoto2/hal-device.h
   trunk/monitor/gphoto2/hal-marshal.c
   trunk/monitor/gphoto2/hal-marshal.h
   trunk/monitor/gphoto2/hal-marshal.list
   trunk/monitor/gphoto2/hal-pool.c
   trunk/monitor/gphoto2/hal-pool.h
   trunk/monitor/gphoto2/hal-utils.c
   trunk/monitor/gphoto2/hal-utils.h
   trunk/monitor/gphoto2/org.gtk.Private.GPhoto2VolumeMonitor.service.in
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/monitor/Makefile.am
   trunk/monitor/hal/ghalvolume.c
   trunk/monitor/hal/ghalvolumemonitor.c
   trunk/po/POTFILES.in

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Mon Jul 21 21:23:37 2008
@@ -557,6 +557,7 @@
 monitor/Makefile
 monitor/proxy/Makefile
 monitor/hal/Makefile
+monitor/gphoto2/Makefile
 gconf/Makefile
 programs/Makefile
 test/Makefile

Modified: trunk/monitor/Makefile.am
==============================================================================
--- trunk/monitor/Makefile.am	(original)
+++ trunk/monitor/Makefile.am	Mon Jul 21 21:23:37 2008
@@ -4,3 +4,7 @@
 if USE_HAL
 SUBDIRS += hal
 endif
+
+if USE_GPHOTO2
+SUBDIRS += gphoto2
+endif

Added: trunk/monitor/gphoto2/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/Makefile.am	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,60 @@
+
+NULL =
+
+libexec_PROGRAMS = gvfs-gphoto2-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_gphoto2_volume_monitor_SOURCES =			\
+	hal-utils.c 		hal-utils.h 		\
+	hal-marshal.c		hal-marshal.h		\
+	hal-device.c		hal-device.h		\
+	hal-pool.c		hal-pool.h		\
+	gphoto2-volume-monitor-daemon.c			\
+	ggphoto2volume.c	ggphoto2volume.h	\
+	ggphoto2volumemonitor.c	ggphoto2volumemonitor.h	\
+	$(NULL)
+
+gvfs_gphoto2_volume_monitor_CFLAGS =		\
+	-DG_LOG_DOMAIN=\"GVFS-GPhoto2\"		\
+	-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_gphoto2_volume_monitor_LDFLAGS =	\
+	$(NULL)
+
+gvfs_gphoto2_volume_monitor_LDADD  =		     			      \
+	$(GLIB_LIBS)                                 			      \
+	$(HAL_LIBS)                                  			      \
+	$(top_builddir)/common/libgvfscommon-noin.la 			      \
+	$(top_builddir)/monitor/proxy/libgvfsproxyvolumemonitordaemon-noin.la \
+	$(NULL)
+
+remote_volume_monitorsdir = $(datadir)/gvfs/remote-volume-monitors
+remote_volume_monitors_DATA = gphoto2.monitor
+
+servicedir       = $(datadir)/dbus-1/services
+service_in_files = org.gtk.Private.GPhoto2VolumeMonitor.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) gphoto2.monitor

Added: trunk/monitor/gphoto2/ggphoto2volume.c
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/ggphoto2volume.c	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,575 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "ggphoto2volume.h"
+
+#include "hal-utils.h"
+
+/* Protects all fields of GHalDrive that can change */
+G_LOCK_DEFINE_STATIC(gphoto2_volume);
+
+struct _GGPhoto2Volume {
+  GObject parent;
+
+  GVolumeMonitor *volume_monitor; /* owned by volume monitor */
+
+  char *device_path;
+  HalDevice *device;
+  HalDevice *drive_device;
+
+  GFile *foreign_mount_root;
+  GMount *foreign_mount;
+
+  char *name;
+  char *icon;
+};
+
+static void g_gphoto2_volume_volume_iface_init (GVolumeIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GGPhoto2Volume, g_gphoto2_volume, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME,
+                                               g_gphoto2_volume_volume_iface_init))
+
+static void
+g_gphoto2_volume_finalize (GObject *object)
+{
+  GGPhoto2Volume *volume;
+
+  volume = G_GPHOTO2_VOLUME (object);
+
+  if (volume->device != NULL)
+    g_object_unref (volume->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);
+
+  if (G_OBJECT_CLASS (g_gphoto2_volume_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_gphoto2_volume_parent_class)->finalize) (object);
+}
+
+static void
+g_gphoto2_volume_class_init (GGPhoto2VolumeClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = g_gphoto2_volume_finalize;
+}
+
+static void
+g_gphoto2_volume_init (GGPhoto2Volume *gphoto2_volume)
+{
+}
+
+static gboolean
+changed_in_idle (gpointer data)
+{
+  GGPhoto2Volume *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;
+}
+
+static 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;
+}
+
+static void
+do_update_from_hal_for_camera (GGPhoto2Volume *v)
+{
+  const char *vendor;
+  const char *product;
+  const char *icon_from_hal;
+  const char *name_from_hal;
+  gboolean is_audio_player;
+
+  vendor = hal_device_get_property_string (v->drive_device, "usb_device.vendor");
+  product = hal_device_get_property_string (v->drive_device, "usb_device.product");
+  icon_from_hal = hal_device_get_property_string (v->device, "info.desktop.icon");
+  name_from_hal = hal_device_get_property_string (v->device, "info.desktop.name");
+
+  is_audio_player = hal_device_has_capability (v->device, "portable_audio_player");
+
+  v->name = NULL;
+  if (strlen (name_from_hal) > 0)
+    v->name = g_strdup (name_from_hal);
+  else if (vendor == NULL)
+    {
+      if (product != NULL)
+        v->name = g_strdup (product);
+    }
+  else
+    {
+      if (product != NULL)
+        v->name = g_strdup_printf ("%s %s", vendor, product);
+      else
+        {
+          if (is_audio_player)
+            {
+              /* Translators: %s is the device vendor */
+              v->name = g_strdup_printf (_("%s Audio Player"), vendor);
+            }
+          else
+            {
+              /* Translators: %s is the device vendor */
+              v->name = g_strdup_printf (_("%s Camera"), vendor);
+            }
+        }
+    }
+  if (v->name == NULL)
+    {
+      if (is_audio_player)
+        v->name = g_strdup (_("Audio Player"));
+      else
+        v->name = g_strdup (_("Camera"));
+    }
+
+  if (strlen (icon_from_hal) > 0)
+    v->icon = g_strdup (icon_from_hal);
+  else if (is_audio_player)
+    v->icon = g_strdup ("multimedia-player");
+  else
+    v->icon = g_strdup ("camera");
+
+  g_object_set_data_full (G_OBJECT (v),
+                          "hal-storage-device-capabilities",
+                          dupv_and_uniqify (hal_device_get_property_strlist (v->device, "info.capabilities")),
+                          (GDestroyNotify) g_strfreev);
+}
+
+static void
+update_from_hal (GGPhoto2Volume *mv, gboolean emit_changed)
+{
+  char *old_name;
+  char *old_icon;
+
+  G_LOCK (gphoto2_volume);
+
+  old_name = g_strdup (mv->name);
+  old_icon = g_strdup (mv->icon);
+
+  g_free (mv->name);
+  g_free (mv->icon);
+
+  do_update_from_hal_for_camera (mv);
+
+  if (emit_changed)
+    {
+      if (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_UNLOCK (gphoto2_volume);
+}
+
+static void
+hal_changed (HalDevice *device, const char *key, gpointer user_data)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (user_data);
+
+  /*g_warning ("hal modifying %s (property %s changed)", gphoto2_volume->device_path, key);*/
+  update_from_hal (gphoto2_volume, TRUE);
+}
+
+GGPhoto2Volume *
+g_gphoto2_volume_new (GVolumeMonitor   *volume_monitor,
+                      HalDevice        *device,
+                      HalPool          *pool,
+                      GFile            *foreign_mount_root)
+{
+  GGPhoto2Volume *volume;
+  HalDevice *drive_device;
+  const char *storage_udi;
+  const char *device_path;
+
+  g_return_val_if_fail (volume_monitor != NULL, NULL);
+  g_return_val_if_fail (device != NULL, NULL);
+  g_return_val_if_fail (pool != NULL, NULL);
+  g_return_val_if_fail (foreign_mount_root != NULL, NULL);
+
+  if (!hal_device_has_capability (device, "camera") ||
+      (hal_device_has_capability (device, "portable_audio_player") &&
+       hal_device_get_property_bool (device, "camera.libgphoto2.support")))
+    return NULL;
+
+  /* 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;
+
+  volume = g_object_new (G_TYPE_GPHOTO2_VOLUME, NULL);
+  volume->volume_monitor = volume_monitor;
+  g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor));
+  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;
+
+  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);
+
+  update_from_hal (volume, FALSE);
+
+  return volume;
+}
+
+void
+g_gphoto2_volume_removed (GGPhoto2Volume *volume)
+{
+  ;
+}
+
+static GIcon *
+g_gphoto2_volume_get_icon (GVolume *volume)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  GIcon *icon;
+
+  G_LOCK (gphoto2_volume);
+  icon = g_themed_icon_new (gphoto2_volume->icon);
+  G_UNLOCK (gphoto2_volume);
+  return icon;
+}
+
+static char *
+g_gphoto2_volume_get_name (GVolume *volume)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  char *name;
+
+  G_LOCK (gphoto2_volume);
+  name = g_strdup (gphoto2_volume->name);
+  G_UNLOCK (gphoto2_volume);
+
+  return name;
+}
+
+static char *
+g_gphoto2_volume_get_uuid (GVolume *volume)
+{
+  return NULL;
+}
+
+static gboolean
+g_gphoto2_volume_can_mount (GVolume *volume)
+{
+  return TRUE;
+}
+
+static gboolean
+g_gphoto2_volume_can_eject (GVolume *volume)
+{
+  return FALSE;
+}
+
+static gboolean
+g_gphoto2_volume_should_automount (GVolume *volume)
+{
+  return TRUE;
+}
+
+static GDrive *
+g_gphoto2_volume_get_drive (GVolume *volume)
+{
+  return NULL;
+}
+
+static GMount *
+g_gphoto2_volume_get_mount (GVolume *volume)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  GMount *mount;
+
+  G_LOCK (gphoto2_volume);
+  mount = NULL;
+  if (gphoto2_volume->foreign_mount != NULL)
+    mount = g_object_ref (gphoto2_volume->foreign_mount);
+  G_UNLOCK (gphoto2_volume);
+
+  return mount;
+}
+
+gboolean
+g_gphoto2_volume_has_udi (GGPhoto2Volume  *volume,
+                      const char  *udi)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  gboolean res;
+
+  G_LOCK (gphoto2_volume);
+  res = FALSE;
+  if (gphoto2_volume->device != NULL)
+    res = strcmp (hal_device_get_udi (gphoto2_volume->device), udi) == 0;
+  G_UNLOCK (gphoto2_volume);
+  return res;
+}
+
+static void
+foreign_mount_unmounted (GMount *mount, gpointer user_data)
+{
+  GGPhoto2Volume *volume = G_GPHOTO2_VOLUME (user_data);
+  gboolean check;
+
+  G_LOCK (gphoto2_volume);
+  check = volume->foreign_mount == mount;
+  G_UNLOCK (gphoto2_volume);
+  if (check)
+    g_gphoto2_volume_adopt_foreign_mount (volume, NULL);
+}
+
+void
+g_gphoto2_volume_adopt_foreign_mount (GGPhoto2Volume *volume, GMount *foreign_mount)
+{
+  G_LOCK (gphoto2_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 (gphoto2_volume);
+}
+
+gboolean
+g_gphoto2_volume_has_foreign_mount_root (GGPhoto2Volume       *volume,
+                                     GFile            *mount_root)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  gboolean res;
+
+  G_LOCK (gphoto2_volume);
+  res = FALSE;
+  if (gphoto2_volume->foreign_mount_root != NULL)
+    res = g_file_equal (gphoto2_volume->foreign_mount_root, mount_root);
+  G_UNLOCK (gphoto2_volume);
+
+  return res;
+}
+
+
+
+typedef struct
+{
+  GGPhoto2Volume *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_free (data);
+}
+
+static void
+g_gphoto2_volume_mount (GVolume             *volume,
+                    GMountMountFlags     flags,
+                    GMountOperation     *mount_operation,
+                    GCancellable        *cancellable,
+                    GAsyncReadyCallback  callback,
+                    gpointer             user_data)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  ForeignMountOp *data;
+
+  /*g_warning ("gphoto2_volume_mount (can_mount=%d foreign=%p device_path=%s)",
+              g_gphoto2_volume_can_mount (volume),
+              gphoto2_volume->foreign_mount_root,
+              gphoto2_volume->device_path);*/
+
+  G_LOCK (gphoto2_volume);
+
+  data = g_new0 (ForeignMountOp, 1);
+  data->enclosing_volume = gphoto2_volume;
+  data->callback = callback;
+  data->user_data = user_data;
+
+  g_file_mount_enclosing_volume (gphoto2_volume->foreign_mount_root,
+                                 0,
+                                 mount_operation,
+                                 cancellable,
+                                 mount_foreign_callback,
+                                 data);
+
+  G_UNLOCK (gphoto2_volume);
+}
+
+static gboolean
+g_gphoto2_volume_mount_finish (GVolume       *volume,
+                           GAsyncResult  *result,
+                           GError       **error)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  gboolean res;
+
+  G_LOCK (gphoto2_volume);
+  res = g_file_mount_enclosing_volume_finish (gphoto2_volume->foreign_mount_root, result, error);
+  G_UNLOCK (gphoto2_volume);
+
+  return res;
+}
+
+static char *
+g_gphoto2_volume_get_identifier (GVolume              *volume,
+                             const char          *kind)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  char *id;
+
+  G_LOCK (gphoto2_volume);
+  id = NULL;
+  if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_HAL_UDI) == 0)
+    id = g_strdup (hal_device_get_udi (gphoto2_volume->device));
+  else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
+    id = g_strdup (gphoto2_volume->device_path);
+  G_UNLOCK (gphoto2_volume);
+
+  return id;
+}
+
+static char **
+g_gphoto2_volume_enumerate_identifiers (GVolume *volume)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+  GPtrArray *res;
+
+  G_LOCK (gphoto2_volume);
+
+  res = g_ptr_array_new ();
+
+  g_ptr_array_add (res,
+                   g_strdup (G_VOLUME_IDENTIFIER_KIND_HAL_UDI));
+
+  if (gphoto2_volume->device_path && *gphoto2_volume->device_path != 0)
+    g_ptr_array_add (res,
+                     g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
+
+  /* Null-terminate */
+  g_ptr_array_add (res, NULL);
+
+  G_UNLOCK (gphoto2_volume);
+
+  return (char **)g_ptr_array_free (res, FALSE);
+}
+
+static GFile *
+g_gphoto2_volume_get_activation_root (GVolume *volume)
+{
+  GGPhoto2Volume *gphoto2_volume = G_GPHOTO2_VOLUME (volume);
+
+  return g_object_ref (gphoto2_volume->foreign_mount_root);
+}
+
+static void
+g_gphoto2_volume_volume_iface_init (GVolumeIface *iface)
+{
+  iface->get_name = g_gphoto2_volume_get_name;
+  iface->get_icon = g_gphoto2_volume_get_icon;
+  iface->get_uuid = g_gphoto2_volume_get_uuid;
+  iface->get_drive = g_gphoto2_volume_get_drive;
+  iface->get_mount = g_gphoto2_volume_get_mount;
+  iface->can_mount = g_gphoto2_volume_can_mount;
+  iface->can_eject = g_gphoto2_volume_can_eject;
+  iface->should_automount = g_gphoto2_volume_should_automount;
+  iface->mount_fn = g_gphoto2_volume_mount;
+  iface->mount_finish = g_gphoto2_volume_mount_finish;
+  iface->eject = NULL;
+  iface->eject_finish = NULL;
+  iface->get_identifier = g_gphoto2_volume_get_identifier;
+  iface->enumerate_identifiers = g_gphoto2_volume_enumerate_identifiers;
+  iface->get_activation_root = g_gphoto2_volume_get_activation_root;
+}

Added: trunk/monitor/gphoto2/ggphoto2volume.h
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/ggphoto2volume.h	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,66 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_GPHOTO2_VOLUME_H__
+#define __G_GPHOTO2_VOLUME_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "hal-pool.h"
+#include "ggphoto2volumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_GPHOTO2_VOLUME        (g_gphoto2_volume_get_type ())
+#define G_GPHOTO2_VOLUME(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GPHOTO2_VOLUME, GGPhoto2Volume))
+#define G_GPHOTO2_VOLUME_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GPHOTO2_VOLUME, GGPhoto2VolumeClass))
+#define G_IS_GPHOTO2_VOLUME(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GPHOTO2_VOLUME))
+#define G_IS_GPHOTO2_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GPHOTO2_VOLUME))
+
+typedef struct _GGPhoto2VolumeClass GGPhoto2VolumeClass;
+
+struct _GGPhoto2VolumeClass {
+   GObjectClass parent_class;
+};
+
+GType g_gphoto2_volume_get_type (void) G_GNUC_CONST;
+
+GGPhoto2Volume *g_gphoto2_volume_new            (GVolumeMonitor   *volume_monitor,
+                                                 HalDevice        *device,
+                                                 HalPool          *pool,
+                                                 GFile            *foreign_mount_root);
+
+gboolean    g_gphoto2_volume_has_udi        (GGPhoto2Volume       *volume,
+                                             const char       *udi);
+
+gboolean    g_gphoto2_volume_has_foreign_mount_root (GGPhoto2Volume       *volume,
+                                                     GFile            *mount_root);
+
+void        g_gphoto2_volume_adopt_foreign_mount (GGPhoto2Volume *volume,
+                                                  GMount *foreign_mount);
+
+void        g_gphoto2_volume_removed        (GGPhoto2Volume       *volume);
+
+G_END_DECLS
+
+#endif /* __G_GPHOTO2_VOLUME_H__ */

Added: trunk/monitor/gphoto2/ggphoto2volumemonitor.c
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/ggphoto2volumemonitor.c	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,564 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <config.h>
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "ggphoto2volumemonitor.h"
+#include "ggphoto2volume.h"
+
+#include "hal-pool.h"
+
+G_LOCK_DEFINE_STATIC(hal_vm);
+
+static GGPhoto2VolumeMonitor *the_volume_monitor = NULL;
+static HalPool *pool = NULL;
+
+struct _GGPhoto2VolumeMonitor {
+  GNativeVolumeMonitor parent;
+
+  GUnixMountMonitor *mount_monitor;
+
+  HalPool *pool;
+
+  GList *last_camera_devices;
+
+  GList *camera_volumes;
+};
+
+static void hal_changed              (HalPool    *pool,
+                                      HalDevice  *device,
+                                      gpointer    user_data);
+
+static void update_all (GGPhoto2VolumeMonitor *monitor,
+                        gboolean emit_changes);
+
+static void update_cameras           (GGPhoto2VolumeMonitor *monitor,
+                                      GList **added_volumes,
+                                      GList **removed_volumes);
+
+
+G_DEFINE_TYPE (GGPhoto2VolumeMonitor, g_gphoto2_volume_monitor, G_TYPE_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[] = {"camera", "portable_audio_player", "usb_device", NULL};
+
+  if (pool == NULL)
+    pool = hal_pool_new (cap_only);
+
+  return pool;
+}
+
+static void
+g_gphoto2_volume_monitor_dispose (GObject *object)
+{
+  GGPhoto2VolumeMonitor *monitor;
+
+  monitor = G_GPHOTO2_VOLUME_MONITOR (object);
+
+  G_LOCK (hal_vm);
+  the_volume_monitor = NULL;
+  G_UNLOCK (hal_vm);
+
+  if (G_OBJECT_CLASS (g_gphoto2_volume_monitor_parent_class)->dispose)
+    (*G_OBJECT_CLASS (g_gphoto2_volume_monitor_parent_class)->dispose) (object);
+}
+
+static void
+g_gphoto2_volume_monitor_finalize (GObject *object)
+{
+  GGPhoto2VolumeMonitor *monitor;
+
+  monitor = G_GPHOTO2_VOLUME_MONITOR (object);
+
+  g_signal_handlers_disconnect_by_func (monitor->pool, hal_changed, monitor);
+
+  g_object_unref (monitor->pool);
+
+  list_free (monitor->last_camera_devices);
+  list_free (monitor->camera_volumes);
+
+  if (G_OBJECT_CLASS (g_gphoto2_volume_monitor_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_gphoto2_volume_monitor_parent_class)->finalize) (object);
+}
+
+static GList *
+get_mounts (GVolumeMonitor *volume_monitor)
+{
+  return NULL;
+}
+
+static GList *
+get_volumes (GVolumeMonitor *volume_monitor)
+{
+  GGPhoto2VolumeMonitor *monitor;
+  GList *l;
+
+  monitor = G_GPHOTO2_VOLUME_MONITOR (volume_monitor);
+
+  G_LOCK (hal_vm);
+
+  l = g_list_copy (monitor->camera_volumes);
+  g_list_foreach (l, (GFunc)g_object_ref, NULL);
+
+  G_UNLOCK (hal_vm);
+
+  return l;
+}
+
+static GList *
+get_connected_drives (GVolumeMonitor *volume_monitor)
+{
+  return NULL;
+}
+
+static GVolume *
+get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+  return NULL;
+}
+
+static GMount *
+get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+  return NULL;
+}
+
+static void
+hal_changed (HalPool    *pool,
+             HalDevice  *device,
+             gpointer    user_data)
+{
+  GGPhoto2VolumeMonitor *monitor = G_GPHOTO2_VOLUME_MONITOR (user_data);
+
+  /*g_warning ("hal changed");*/
+
+  update_all (monitor, TRUE);
+}
+
+static GObject *
+g_gphoto2_volume_monitor_constructor (GType                  type,
+                                  guint                  n_construct_properties,
+                                  GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+  GGPhoto2VolumeMonitor *monitor;
+  GGPhoto2VolumeMonitorClass *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_GPHOTO2_VOLUME_MONITOR_CLASS (g_type_class_peek (G_TYPE_GPHOTO2_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_GPHOTO2_VOLUME_MONITOR (object);
+  monitor->pool = g_object_ref (get_hal_pool ());
+
+  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_gphoto2_volume_monitor_init (GGPhoto2VolumeMonitor *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);
+
+  /* gphoto2:// are foreign mounts */
+  for (l = the_volume_monitor->camera_volumes; l != NULL; l = l->next)
+    {
+      GGPhoto2Volume *volume = l->data;
+
+      if (g_gphoto2_volume_has_foreign_mount_root (volume, mount_root))
+        {
+          g_gphoto2_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_gphoto2_volume_monitor_class_init (GGPhoto2VolumeMonitorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
+
+  gobject_class->constructor = g_gphoto2_volume_monitor_constructor;
+  gobject_class->finalize = g_gphoto2_volume_monitor_finalize;
+  gobject_class->dispose = g_gphoto2_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;
+}
+
+/**
+ * g_gphoto2_volume_monitor_new:
+ *
+ * Returns:  a new #GVolumeMonitor.
+ **/
+GVolumeMonitor *
+g_gphoto2_volume_monitor_new (void)
+{
+  GGPhoto2VolumeMonitor *monitor;
+
+  monitor = g_object_new (G_TYPE_GPHOTO2_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 GGPhoto2Volume *
+find_camera_volume_by_udi (GGPhoto2VolumeMonitor *monitor, const char *udi)
+{
+  GList *l;
+
+  for (l = monitor->camera_volumes; l != NULL; l = l->next)
+    {
+      GGPhoto2Volume *volume = l->data;
+
+      if (g_gphoto2_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));
+}
+
+static void
+list_emit (GGPhoto2VolumeMonitor *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 {
+  GGPhoto2VolumeMonitor *monitor;
+  GList *added_volumes, *removed_volumes;
+} ChangedLists;
+
+
+static gboolean
+emit_lists_in_idle (gpointer data)
+{
+  ChangedLists *lists = data;
+
+  list_emit (lists->monitor,
+             "volume_removed", "removed",
+             lists->removed_volumes);
+  list_emit (lists->monitor,
+             "volume_added", NULL,
+             lists->added_volumes);
+
+  list_free (lists->removed_volumes);
+  list_free (lists->added_volumes);
+  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 (GGPhoto2VolumeMonitor *monitor,
+            gboolean emit_changes)
+{
+  ChangedLists *lists;
+  GList *added_volumes, *removed_volumes;
+
+  added_volumes = NULL;
+  removed_volumes = NULL;
+
+  G_LOCK (hal_vm);
+  update_cameras (monitor, &added_volumes, &removed_volumes);
+  G_UNLOCK (hal_vm);
+
+  if (emit_changes)
+    {
+      lists = g_new0 (ChangedLists, 1);
+      lists->monitor = g_object_ref (monitor);
+      lists->added_volumes = added_volumes;
+      lists->removed_volumes = removed_volumes;
+
+      g_idle_add (emit_lists_in_idle, lists);
+    }
+  else
+    {
+      list_free (removed_volumes);
+      list_free (added_volumes);
+    }
+}
+
+static void
+update_cameras (GGPhoto2VolumeMonitor *monitor,
+                GList **added_volumes,
+                GList **removed_volumes)
+{
+  GList *new_camera_devices;
+  GList *new_mtp_devices;
+  GList *removed, *added;
+  GList *l, *ll;
+  GGPhoto2Volume *volume;
+  const char *udi;
+
+  new_mtp_devices = hal_pool_find_by_capability (monitor->pool, "portable_audio_player");
+  for (l = new_mtp_devices; l != NULL; l = ll)
+    {
+      HalDevice *d = l->data;
+      ll = l->next;
+      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_mtp_devices = g_list_delete_link (new_mtp_devices, l);
+        }
+    }
+
+  new_camera_devices = hal_pool_find_by_capability (monitor->pool, "camera");
+  new_camera_devices = g_list_concat (new_camera_devices, new_mtp_devices);
+  for (l = new_camera_devices; l != NULL; l = ll)
+    {
+      HalDevice *d = l->data;
+      ll = l->next;
+      /*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_gphoto2_volume_removed (volume);
+          monitor->camera_volumes = g_list_remove (monitor->camera_volumes, volume);
+          *removed_volumes = g_list_prepend (*removed_volumes, 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;
+      gboolean found;
+
+      /* Look for the device in the added volumes, so as
+       * not to add devices that are both audio players, and cameras */
+      found = FALSE;
+      for (ll = *added_volumes; ll; ll = ll->next)
+        {
+          if (g_gphoto2_volume_has_udi (ll->data, hal_device_get_udi (d)) != FALSE)
+            {
+              found = TRUE;
+              break;
+            }
+        }
+
+      if (found)
+        continue;
+
+      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_gphoto2_volume_new (G_VOLUME_MONITOR (monitor),
+                                     d,
+                                     monitor->pool,
+                                     foreign_mount_root);
+      g_object_unref (foreign_mount_root);
+      if (volume != NULL)
+        {
+          monitor->camera_volumes = g_list_prepend (monitor->camera_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_camera_devices);
+  monitor->last_camera_devices = new_camera_devices;
+}

Added: trunk/monitor/gphoto2/ggphoto2volumemonitor.h
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/ggphoto2volumemonitor.h	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,54 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_GPHOTO2_VOLUME_MONITOR_H__
+#define __G_GPHOTO2_VOLUME_MONITOR_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_GPHOTO2_VOLUME_MONITOR        (g_gphoto2_volume_monitor_get_type ())
+#define G_GPHOTO2_VOLUME_MONITOR(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GPHOTO2_VOLUME_MONITOR, GGPhoto2VolumeMonitor))
+#define G_GPHOTO2_VOLUME_MONITOR_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GPHOTO2_VOLUME_MONITOR, GGPhoto2VolumeMonitorClass))
+#define G_IS_GPHOTO2_VOLUME_MONITOR(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GPHOTO2_VOLUME_MONITOR))
+#define G_IS_GPHOTO2_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GPHOTO2_VOLUME_MONITOR))
+
+typedef struct _GGPhoto2VolumeMonitor GGPhoto2VolumeMonitor;
+typedef struct _GGPhoto2VolumeMonitorClass GGPhoto2VolumeMonitorClass;
+
+/* Forward definitions */
+typedef struct _GGPhoto2Volume GGPhoto2Volume;
+
+struct _GGPhoto2VolumeMonitorClass {
+  GVolumeMonitorClass parent_class;
+};
+
+GType g_gphoto2_volume_monitor_get_type (void) G_GNUC_CONST;
+
+GVolumeMonitor *g_gphoto2_volume_monitor_new                          (void);
+void            g_gphoto2_volume_monitor_force_update                 (GGPhoto2VolumeMonitor *monitor);
+
+G_END_DECLS
+
+#endif /* __G_GPHOTO2_VOLUME_MONITOR_H__ */

Added: trunk/monitor/gphoto2/gphoto2-volume-monitor-daemon.c
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/gphoto2-volume-monitor-daemon.c	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,43 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <gio/gio.h>
+
+#include <gvfsproxyvolumemonitordaemon.h>
+
+#include "ggphoto2volumemonitor.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.GPhoto2VolumeMonitor",
+                                                 G_TYPE_GPHOTO2_VOLUME_MONITOR);
+}

Added: trunk/monitor/gphoto2/gphoto2.monitor
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/gphoto2.monitor	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,4 @@
+[RemoteVolumeMonitor]
+Name=GProxyVolumeMonitorGPhoto2
+DBusName=org.gtk.Private.GPhoto2VolumeMonitor
+IsNative=false

Added: trunk/monitor/gphoto2/hal-device.c
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-device.c	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,297 @@
+/* hal-device.c
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include "hal-device.h"
+#include "hal-marshal.h"
+
+struct _HalDevicePrivate
+{
+  LibHalContext *hal_ctx;
+  LibHalPropertySet *properties;
+  char *udi;
+  GTimeVal time_added;
+};
+
+enum {
+  HAL_PROPERTY_CHANGED,
+  HAL_CONDITION,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (HalDevice, hal_device, G_TYPE_OBJECT)
+
+static void
+hal_device_finalize (HalDevice *device)
+{
+  if (device->priv->properties != NULL)
+    libhal_free_property_set (device->priv->properties);
+  g_free (device->priv->udi);
+  
+  if (G_OBJECT_CLASS (hal_device_parent_class)->finalize)
+    (* G_OBJECT_CLASS (hal_device_parent_class)->finalize) (G_OBJECT (device));
+}
+
+static void
+hal_device_class_init (HalDeviceClass *klass)
+{
+  GObjectClass *obj_class = (GObjectClass *) klass;
+  
+  obj_class->finalize = (GObjectFinalizeFunc) hal_device_finalize;
+
+  signals[HAL_PROPERTY_CHANGED] =
+    g_signal_new ("hal_property_changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (HalDeviceClass, hal_property_changed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_STRING);
+
+  signals[HAL_CONDITION] =
+    g_signal_new ("hal_condition",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (HalDeviceClass, hal_condition),
+                  NULL, NULL,
+                  hal_marshal_VOID__STRING_STRING,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_STRING,
+                  G_TYPE_STRING);
+}
+
+static void
+hal_device_init (HalDevice *device)
+{
+  device->priv = g_new0 (HalDevicePrivate, 1);
+  g_get_current_time (&(device->priv->time_added));
+}
+
+const char *
+hal_device_get_property_string (HalDevice *device, const char *key)
+{
+  const char *ret;
+  
+  ret = libhal_ps_get_string (device->priv->properties, key);
+  if (ret != NULL)
+    return ret;
+  
+  /* play it safe and don't make clients crash */
+  return "";
+}
+
+int
+hal_device_get_property_int (HalDevice *device, const char *key)
+{
+  return libhal_ps_get_int32 (device->priv->properties, key);
+}
+
+double
+hal_device_get_property_double (HalDevice *device, const char *key)
+{
+  return libhal_ps_get_double (device->priv->properties, key);
+}
+
+guint64
+hal_device_get_property_uint64 (HalDevice *device, const char *key)
+{
+  return libhal_ps_get_uint64 (device->priv->properties, key);
+}
+
+gboolean
+hal_device_get_property_bool (HalDevice *device, const char *key)
+{
+  return libhal_ps_get_bool (device->priv->properties, key);
+}
+
+char **
+hal_device_get_property_strlist (HalDevice *device, const char *key)
+{
+  static char * empty[1] = {NULL};
+  char **ret;
+  
+  ret = (char **) libhal_ps_get_strlist (device->priv->properties, key);
+  if (ret != NULL)
+    return (char **) ret;
+  
+  /* play it safe and don't make clients crash */
+  return empty;
+}
+
+gboolean
+hal_device_has_capability (HalDevice *device, const char *capability)
+{
+  int n;
+  char **caps;
+  gboolean ret;
+  
+  ret = FALSE;
+  caps = hal_device_get_property_strlist (device, "info.capabilities");
+  if (caps == NULL)
+    goto out;
+  
+  for (n = 0; caps[n] != NULL; n++)
+    {
+      if (g_ascii_strcasecmp (caps[n], capability) == 0)
+        {
+          ret = TRUE;
+          break;
+        }
+    }
+  
+ out:
+  return ret;
+}
+
+gboolean
+hal_device_has_interface (HalDevice *device, const char *interface)
+{
+  int n;
+  char **ifs;
+  gboolean ret;
+  
+  ret = FALSE;
+  ifs = hal_device_get_property_strlist (device, "info.interfaces");
+  if (ifs == NULL)
+    goto out;
+  
+  for (n = 0; ifs[n] != NULL; n++)
+    {
+      if (g_ascii_strcasecmp (ifs[n], interface) == 0)
+        {
+          ret = TRUE;
+          break;
+        }
+    }
+
+out:
+  return ret;
+}
+
+gboolean
+hal_device_has_property (HalDevice *device, const char *key)
+{
+  gboolean ret;
+  LibHalPropertySetIterator it;
+
+  ret = FALSE;
+  if (device->priv->properties == NULL)
+    goto out;
+  
+  libhal_psi_init (&it, device->priv->properties);
+  
+  while (libhal_psi_has_more (&it))
+    {
+      char *pkey = libhal_psi_get_key (&it);
+      
+      if (pkey != NULL && g_ascii_strcasecmp (pkey, key) == 0)
+        {
+          ret = TRUE;
+          break;
+        }
+      libhal_psi_next (&it);
+    }
+  
+ out:
+  return ret;
+}
+
+
+HalDevice *
+hal_device_new_from_udi (LibHalContext *hal_ctx, const char *udi)
+{
+  HalDevice *device;
+  
+  device = HAL_DEVICE (g_object_new (HAL_TYPE_DEVICE, NULL));
+  device->priv->udi = g_strdup (udi);
+  device->priv->hal_ctx = hal_ctx;
+  device->priv->properties = libhal_device_get_all_properties (hal_ctx, udi, NULL);
+  return device;
+}
+
+HalDevice *
+hal_device_new_from_udi_and_properties (LibHalContext *hal_ctx, 
+                                        char *udi, 
+                                        LibHalPropertySet *properties)
+{
+  HalDevice *device;
+  
+  device = HAL_DEVICE (g_object_new (HAL_TYPE_DEVICE, NULL));
+  device->priv->udi = g_strdup (udi);
+  device->priv->hal_ctx = hal_ctx;
+  device->priv->properties = properties;
+  return device;
+}
+
+void
+_hal_device_hal_property_changed (HalDevice *device, const char *key);
+
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail);
+
+void
+_hal_device_hal_property_changed (HalDevice *device, const char *key)
+{
+  LibHalPropertySet *new_props;
+  
+  new_props = libhal_device_get_all_properties (device->priv->hal_ctx, device->priv->udi, NULL);
+  if (new_props != NULL)
+    {
+      libhal_free_property_set (device->priv->properties);
+      device->priv->properties = new_props;
+      g_signal_emit (device, signals[HAL_PROPERTY_CHANGED], 0, key);
+    }
+}
+
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail)
+{
+  g_signal_emit (device, signals[HAL_CONDITION], 0, name, detail);
+}
+
+const char *
+hal_device_get_udi (HalDevice *device)
+{
+  return device->priv->udi;
+}
+
+LibHalPropertySet *
+hal_device_get_properties (HalDevice *device)
+{
+  return device->priv->properties;
+}
+
+gboolean
+hal_device_is_recently_plugged_in (HalDevice *device)
+{
+  GTimeVal now;
+  glong delta_msec;
+
+  g_get_current_time (&now);
+
+  delta_msec = (now.tv_sec - device->priv->time_added.tv_sec) * 1000  + 
+    (now.tv_usec - device->priv->time_added.tv_usec) / 1000;
+
+  return delta_msec < 2000;
+}

Added: trunk/monitor/gphoto2/hal-device.h
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-device.h	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,93 @@
+/* hal-device.h
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef HAL_DEVICE_H
+#define HAL_DEVICE_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <libhal.h>
+
+#define HAL_TYPE_DEVICE             (hal_device_get_type ())
+#define HAL_DEVICE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), HAL_TYPE_DEVICE, HalDevice))
+#define HAL_DEVICE_CLASS(obj)       (G_TYPE_CHECK_CLASS_CAST ((obj), HAL_DEVICE,  HalDeviceClass))
+#define HAL_IS_DEVICE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), HAL_TYPE_DEVICE))
+#define HAL_IS_DEVICE_CLASS(obj)    (G_TYPE_CHECK_CLASS_TYPE ((obj), HAL_TYPE_DEVICE))
+#define HAL_DEVICE_GET_CLASS        (G_TYPE_INSTANCE_GET_CLASS ((obj), HAL_TYPE_DEVICE, HalDeviceClass))
+
+
+typedef struct _HalDevice            HalDevice;
+typedef struct _HalDeviceClass       HalDeviceClass;
+
+struct _HalDevicePrivate;
+typedef struct _HalDevicePrivate     HalDevicePrivate;
+
+struct _HalDevice
+{
+  GObject parent;
+        
+  /* private */
+  HalDevicePrivate *priv;
+};
+
+struct _HalDeviceClass
+{
+  GObjectClass parent_class;
+  
+  /* signals */
+  void (*hal_property_changed) (HalDevice *device, const char *key);
+  void (*hal_condition) (HalDevice *device, const char *name, const char *detail);
+};
+
+
+GType               hal_device_get_type                    (void);
+
+HalDevice *         hal_device_new_from_udi                (LibHalContext     *hal_ctx, 
+                                                            const char        *udi);
+
+HalDevice *         hal_device_new_from_udi_and_properties (LibHalContext     *hal_ctx, 
+                                                            char              *udi, 
+                                                            LibHalPropertySet *properties);
+
+const char *        hal_device_get_udi                     (HalDevice         *device);
+LibHalPropertySet * hal_device_get_properties              (HalDevice         *device);
+const char *        hal_device_get_property_string         (HalDevice         *device,
+                                                            const char        *key);
+int                 hal_device_get_property_int            (HalDevice         *device,
+                                                            const char        *key);
+guint64             hal_device_get_property_uint64         (HalDevice         *device,
+                                                            const char        *key);
+double              hal_device_get_property_double         (HalDevice         *device,
+                                                            const char        *key);
+gboolean            hal_device_get_property_bool           (HalDevice         *device,
+                                                            const char        *key);
+char **             hal_device_get_property_strlist        (HalDevice         *device,
+                                                            const char        *key);
+
+gboolean            hal_device_has_property                (HalDevice         *device,
+                                                            const char        *key);
+gboolean            hal_device_has_capability              (HalDevice         *device,
+                                                            const char        *capability);
+gboolean            hal_device_has_interface               (HalDevice         *device,
+                                                            const char        *interface);
+
+gboolean            hal_device_is_recently_plugged_in      (HalDevice         *device);
+
+#endif /* HAL_DEVICE_H */

Added: trunk/monitor/gphoto2/hal-marshal.c
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-marshal.c	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,163 @@
+#include "hal-marshal.h"
+
+#include	<glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:OBJECT,STRING (hal-marshal.list:1) */
+void
+hal_marshal_VOID__OBJECT_STRING (GClosure     *closure,
+                                 GValue       *return_value G_GNUC_UNUSED,
+                                 guint         n_param_values,
+                                 const GValue *param_values,
+                                 gpointer      invocation_hint G_GNUC_UNUSED,
+                                 gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__OBJECT_STRING) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__OBJECT_STRING) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_object (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            data2);
+}
+
+/* VOID:OBJECT,STRING,STRING (hal-marshal.list:2) */
+void
+hal_marshal_VOID__OBJECT_STRING_STRING (GClosure     *closure,
+                                        GValue       *return_value G_GNUC_UNUSED,
+                                        guint         n_param_values,
+                                        const GValue *param_values,
+                                        gpointer      invocation_hint G_GNUC_UNUSED,
+                                        gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__OBJECT_STRING_STRING) (gpointer     data1,
+                                                           gpointer     arg_1,
+                                                           gpointer     arg_2,
+                                                           gpointer     arg_3,
+                                                           gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_STRING_STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__OBJECT_STRING_STRING) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_object (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            g_marshal_value_peek_string (param_values + 3),
+            data2);
+}
+
+/* VOID:STRING,STRING (hal-marshal.list:3) */
+void
+hal_marshal_VOID__STRING_STRING (GClosure     *closure,
+                                 GValue       *return_value G_GNUC_UNUSED,
+                                 guint         n_param_values,
+                                 const GValue *param_values,
+                                 gpointer      invocation_hint G_GNUC_UNUSED,
+                                 gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__STRING_STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_STRING) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            data2);
+}
+

Added: trunk/monitor/gphoto2/hal-marshal.h
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-marshal.h	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,36 @@
+
+#ifndef __hal_marshal_MARSHAL_H__
+#define __hal_marshal_MARSHAL_H__
+
+#include	<glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:OBJECT,STRING (hal-marshal.list:1) */
+extern void hal_marshal_VOID__OBJECT_STRING (GClosure     *closure,
+                                             GValue       *return_value,
+                                             guint         n_param_values,
+                                             const GValue *param_values,
+                                             gpointer      invocation_hint,
+                                             gpointer      marshal_data);
+
+/* VOID:OBJECT,STRING,STRING (hal-marshal.list:2) */
+extern void hal_marshal_VOID__OBJECT_STRING_STRING (GClosure     *closure,
+                                                    GValue       *return_value,
+                                                    guint         n_param_values,
+                                                    const GValue *param_values,
+                                                    gpointer      invocation_hint,
+                                                    gpointer      marshal_data);
+
+/* VOID:STRING,STRING (hal-marshal.list:3) */
+extern void hal_marshal_VOID__STRING_STRING (GClosure     *closure,
+                                             GValue       *return_value,
+                                             guint         n_param_values,
+                                             const GValue *param_values,
+                                             gpointer      invocation_hint,
+                                             gpointer      marshal_data);
+
+G_END_DECLS
+
+#endif /* __hal_marshal_MARSHAL_H__ */
+

Added: trunk/monitor/gphoto2/hal-marshal.list
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-marshal.list	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,3 @@
+VOID:OBJECT,STRING
+VOID:OBJECT,STRING,STRING
+VOID:STRING,STRING

Added: trunk/monitor/gphoto2/hal-pool.c
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-pool.c	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,458 @@
+/* hal-pool.c
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <gdbusutils.h>
+
+#include "hal-pool.h"
+#include "hal-marshal.h"
+
+enum {
+  DEVICE_ADDED,
+  DEVICE_REMOVED,
+  DEVICE_PROPERTY_CHANGED,
+  DEVICE_CONDITION,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _HalPoolPrivate
+{
+  char **cap_only;
+  
+  DBusConnection *dbus_connection;
+  LibHalContext *hal_ctx;
+  GHashTable *devices;
+};
+
+G_DEFINE_TYPE (HalPool, hal_pool, G_TYPE_OBJECT)
+
+static void
+hal_pool_finalize (HalPool *pool)
+{
+  g_strfreev (pool->priv->cap_only);
+
+  dbus_bus_remove_match (pool->priv->dbus_connection,
+                         "type='signal',"
+                         "interface='org.freedesktop.Hal.Device',"
+                         "sender='org.freedesktop.Hal'", NULL);
+  libhal_ctx_shutdown (pool->priv->hal_ctx, NULL);
+  dbus_connection_close (pool->priv->dbus_connection);
+  dbus_connection_unref (pool->priv->dbus_connection);
+  
+  if (G_OBJECT_CLASS (hal_pool_parent_class)->finalize)
+    (* G_OBJECT_CLASS (hal_pool_parent_class)->finalize) (G_OBJECT (pool));
+}
+
+static void
+hal_pool_class_init (HalPoolClass *klass)
+{
+  GObjectClass *obj_class = (GObjectClass *) klass;
+  
+  obj_class->finalize = (GObjectFinalizeFunc) hal_pool_finalize;
+
+  g_type_class_ref (HAL_TYPE_DEVICE);
+  
+  signals[DEVICE_ADDED] =
+    g_signal_new ("device_added",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (HalPoolClass, device_added),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1,
+                  HAL_TYPE_DEVICE);
+  
+  signals[DEVICE_REMOVED] =
+    g_signal_new ("device_removed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (HalPoolClass, device_removed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1,
+                  HAL_TYPE_DEVICE);
+  
+  signals[DEVICE_PROPERTY_CHANGED] =
+    g_signal_new ("device_property_changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (HalPoolClass, device_property_changed),
+                  NULL, NULL,
+                  hal_marshal_VOID__OBJECT_STRING,
+                  G_TYPE_NONE, 2,
+                  HAL_TYPE_DEVICE,
+                  G_TYPE_STRING);
+
+  signals[DEVICE_CONDITION] =
+    g_signal_new ("device_condition",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (HalPoolClass, device_condition),
+                  NULL, NULL,
+                  hal_marshal_VOID__OBJECT_STRING_STRING,
+                  G_TYPE_NONE, 3,
+                  HAL_TYPE_DEVICE,
+                  G_TYPE_STRING,
+                  G_TYPE_STRING);
+}
+
+static void
+hal_pool_init (HalPool *pool)
+{
+  pool->priv = g_new0 (HalPoolPrivate, 1);
+  pool->priv->hal_ctx = NULL;
+}
+
+static gboolean
+has_cap_only (HalPool *pool, HalDevice *device)
+{
+  const char *subsys;
+  unsigned int n;
+
+  for (n = 0; pool->priv->cap_only != NULL && pool->priv->cap_only[n] != NULL; n++)
+    {
+      if (hal_device_has_capability (device, pool->priv->cap_only[n]))
+        return TRUE;
+
+      subsys = hal_device_get_property_string (device, "info.subsystem");
+
+      if (subsys != NULL && strcmp (subsys, pool->priv->cap_only[n]) == 0)
+        return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static void
+hal_pool_add_device_by_udi (HalPool *pool, 
+                            const char *udi, 
+                            gboolean emit_signal)
+{
+  HalDevice *device;
+  
+  device = hal_device_new_from_udi (pool->priv->hal_ctx, udi);
+  if (device != NULL)
+    {
+      if (!has_cap_only (pool, device))
+        g_object_unref (device);
+      else 
+        {
+          g_hash_table_insert (pool->priv->devices, g_strdup (udi), device);
+          if (emit_signal)
+            g_signal_emit (pool, signals[DEVICE_ADDED], 0, device);
+        }
+    }
+}
+
+#ifdef HAVE_HAL_FAST_INIT
+static void
+hal_pool_add_device_by_udi_and_properties (HalPool *pool, 
+                                           char *udi, 
+                                           LibHalPropertySet *properties, 
+                                           gboolean emit_signal)
+{
+  HalDevice *device;
+  
+  device = hal_device_new_from_udi_and_properties (pool->priv->hal_ctx, udi, properties);
+  if (device != NULL)
+    {
+      if (!has_cap_only (pool, device))
+        g_object_unref (device);
+      else 
+        {
+          g_hash_table_insert (pool->priv->devices, g_strdup (udi), device);
+          if (emit_signal)
+            g_signal_emit (pool, signals[DEVICE_ADDED], 0, device);
+        }
+    }
+}
+#endif
+
+static void
+_hal_device_added (LibHalContext *hal_ctx, const char *udi)
+{
+  HalPool *pool;
+  
+  pool = HAL_POOL (libhal_ctx_get_user_data (hal_ctx));
+  hal_pool_add_device_by_udi (pool, udi, TRUE);
+}
+
+static void
+_hal_device_removed (LibHalContext *hal_ctx, const char *udi)
+{
+  HalPool *pool;
+  HalDevice *device;
+  
+  pool = HAL_POOL (libhal_ctx_get_user_data (hal_ctx));
+  if ((device = hal_pool_get_device_by_udi (pool, udi)) != NULL)
+    {
+      g_object_ref (device);
+      g_hash_table_remove (pool->priv->devices, udi);
+      g_signal_emit (pool, signals[DEVICE_REMOVED], 0, device);                
+      g_object_unref (device);
+    }
+}
+
+void
+_hal_device_hal_property_changed (HalDevice *device, const char *key);
+
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail);
+
+static void
+_hal_property_modified (LibHalContext *ctx,
+                        const char *udi,
+                        const char *key,
+                        dbus_bool_t is_removed,
+                        dbus_bool_t is_added)
+{
+  HalPool *pool;
+  HalDevice *device;
+  
+  pool = HAL_POOL (libhal_ctx_get_user_data (ctx));
+  
+  device = hal_pool_get_device_by_udi (pool, udi);
+  if (device != NULL)
+    {
+      _hal_device_hal_property_changed (device, key);
+      g_signal_emit (pool, signals[DEVICE_PROPERTY_CHANGED], 0, device, key);
+    }
+}
+
+static void
+_hal_condition (LibHalContext *ctx,
+                const char *udi,
+                const char *condition_name,
+                const char *condition_detail)
+{
+  HalPool *pool;
+  HalDevice *device;
+  
+  pool = HAL_POOL (libhal_ctx_get_user_data (ctx));
+  
+  device = hal_pool_get_device_by_udi (pool, udi);
+  if (device != NULL)
+    {
+      _hal_device_hal_condition (device, condition_name, condition_detail);
+      g_signal_emit (pool, signals[DEVICE_CONDITION], 0, device, condition_name, condition_detail);
+    }
+}
+
+LibHalContext *
+hal_pool_get_hal_ctx (HalPool *pool)
+{
+  return pool->priv->hal_ctx;
+}
+
+DBusConnection *
+hal_pool_get_dbus_connection (HalPool *pool)
+{
+  return pool->priv->dbus_connection;
+}
+
+HalPool *
+hal_pool_new (char **cap_only)
+{
+  int i;
+  char **devices;
+  int num_devices;
+  HalPool *pool;
+  LibHalContext *hal_ctx;
+  DBusError error;
+  DBusConnection *dbus_connection;
+#ifdef HAVE_HAL_FAST_INIT
+  LibHalPropertySet **properties;
+#endif
+  
+  pool = NULL;
+  
+  dbus_error_init (&error);
+  /* see discussion on gtk-devel-list (Subject: Re: gvfs hal volume monitoring backend) on 
+   * why this is private
+   */
+  dbus_connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error);
+  if (dbus_error_is_set (&error))
+    {
+      dbus_error_free (&error);
+      goto out;
+    }
+  
+  dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
+
+  hal_ctx = libhal_ctx_new ();
+  if (hal_ctx == NULL)
+    {
+      dbus_connection_close (dbus_connection);
+      dbus_connection_unref (dbus_connection);
+      goto out;
+    }
+
+  _g_dbus_connection_integrate_with_main (dbus_connection);
+  libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
+  
+  if (!libhal_ctx_init (hal_ctx, &error))
+    {
+      dbus_connection_close (dbus_connection);
+      dbus_connection_unref (dbus_connection);
+      dbus_error_free (&error);
+      goto out;
+    }
+
+  pool = HAL_POOL (g_object_new (HAL_TYPE_POOL, NULL));
+  pool->priv->dbus_connection = dbus_connection;
+  pool->priv->hal_ctx = hal_ctx;
+  pool->priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+  pool->priv->cap_only = g_strdupv (cap_only);
+  
+  /* Gah, unfortunately we have to watch all devices as HAL's PropertyModified signal
+   * doesn't include the capabilities...
+   */
+  dbus_bus_add_match (dbus_connection,
+                      "type='signal',"
+                      "interface='org.freedesktop.Hal.Device',"
+                      "sender='org.freedesktop.Hal'", NULL);
+  libhal_ctx_set_device_added (hal_ctx, _hal_device_added);
+  libhal_ctx_set_device_removed (hal_ctx, _hal_device_removed);
+  libhal_ctx_set_device_property_modified (hal_ctx, _hal_property_modified);
+  libhal_ctx_set_device_condition (hal_ctx, _hal_condition);
+  libhal_ctx_set_user_data (hal_ctx, pool);
+
+#ifdef HAVE_HAL_FAST_INIT
+  /* First try new O(1) algorithm to get all devices and properties in a single call..
+   *
+   * This method is only available in post hal 0.5.10.
+   */
+  if (libhal_get_all_devices_with_properties (pool->priv->hal_ctx, 
+                                              &num_devices, 
+                                              &devices, 
+                                              &properties, 
+                                              NULL))
+    {
+      for (i = 0; i < num_devices; i++)
+        hal_pool_add_device_by_udi_and_properties (pool, devices[i], properties[i], FALSE);
+      libhal_free_string_array (devices);
+      free (properties); /* hal_pool_add_device_by_udi_and_properties steals the given properties */
+      goto out;
+    }
+#endif
+
+  /* fallback to using O(n) algorithm; will work on any hal 0.5.x release */
+  devices = libhal_get_all_devices (pool->priv->hal_ctx, &num_devices, NULL);
+  if (devices != NULL)
+    {
+      for (i = 0; i < num_devices; i++)
+        {
+          char *device_udi;
+          device_udi = devices[i];
+          hal_pool_add_device_by_udi (pool, device_udi, FALSE);
+        }
+      libhal_free_string_array (devices);
+      goto out;
+    }
+  
+  /* FAIL! */
+  
+  g_object_unref (pool);
+  return NULL;
+  
+ out:
+  return pool;
+}
+
+HalDevice *
+hal_pool_get_device_by_udi (HalPool *pool, const char *udi)
+{
+  return g_hash_table_lookup (pool->priv->devices, udi);
+}
+
+HalDevice *
+hal_pool_get_device_by_capability_and_string (HalPool    *pool, 
+                                              const char *capability,
+                                              const char *key,
+                                              const char *value)
+{
+  GList *i;
+  GList *devices;
+  HalDevice *result;
+  
+  result = NULL;
+  devices = NULL;
+  
+  if (pool->priv->devices == NULL)
+    goto out;
+  
+  devices = g_hash_table_get_values (pool->priv->devices);
+  for (i = devices; i != NULL; i = i->next)
+    {
+      HalDevice *d = i->data;
+      const char *s;
+      
+      if (!hal_device_has_capability (d, capability))
+        continue;
+      
+      s = hal_device_get_property_string (d, key);
+      if (s == NULL)
+        continue;
+      
+      if (strcmp (s, value) == 0)
+        {
+          result = d;
+          goto out;
+        }
+    }
+  
+out:
+  if (devices != NULL)
+    g_list_free (devices);
+  return result;
+}
+
+GList *
+hal_pool_find_by_capability (HalPool *pool, const char *capability)
+{
+  GList *i;
+  GList *j;
+  GList *devices;
+  
+  devices = NULL;
+  
+  if (pool->priv->devices == NULL)
+    goto out;
+  
+  devices = g_hash_table_get_values (pool->priv->devices);
+  for (i = devices; i != NULL; i = j)
+    {
+      HalDevice *d = i->data;
+      
+      j = i->next;
+      
+      if (!hal_device_has_capability (d, capability))
+        devices = g_list_delete_link (devices, i);
+    }
+  
+ out:
+  return devices;
+}

Added: trunk/monitor/gphoto2/hal-pool.h
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-pool.h	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,74 @@
+/* hal-pool.h
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#if !defined(HAL_POOL_H)
+#define HAL_POOL_H
+
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+#include "hal-device.h"
+
+#define HAL_TYPE_POOL             (hal_pool_get_type ())
+#define HAL_POOL(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), HAL_TYPE_POOL, HalPool))
+#define HAL_POOL_CLASS(obj)       (G_TYPE_CHECK_CLASS_CAST ((obj), HAL_POOL,  HalPoolClass))
+#define HAL_IS_POOL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), HAL_TYPE_POOL))
+#define HAL_IS_POOL_CLASS(obj)    (G_TYPE_CHECK_CLASS_TYPE ((obj), HAL_TYPE_POOL))
+#define HAL_POOL_GET_CLASS        (G_TYPE_INSTANCE_GET_CLASS ((obj), HAL_TYPE_POOL, HalPoolClass))
+
+
+typedef struct _HalPool            HalPool;
+typedef struct _HalPoolClass       HalPoolClass;
+
+struct _HalPoolPrivate;
+typedef struct _HalPoolPrivate     HalPoolPrivate;
+
+struct _HalPool
+{
+  GObject parent;
+        
+  /* private */
+  HalPoolPrivate *priv;
+};
+
+struct _HalPoolClass
+{
+  GObjectClass parent_class;
+  
+  /* signals */
+  void (*device_added) (HalPool *pool, HalDevice *device);
+  void (*device_removed) (HalPool *pool, HalDevice *device);
+  void (*device_property_changed) (HalPool *pool, HalDevice *device, const char *key);
+  void (*device_condition) (HalPool *pool, HalDevice *device, const char *name, const char *detail);
+};
+
+GType            hal_pool_get_type                            (void);
+HalPool *        hal_pool_new                                 (char        **cap_only);
+LibHalContext *  hal_pool_get_hal_ctx                         (HalPool      *pool);
+DBusConnection * hal_pool_get_dbus_connection                 (HalPool      *pool);
+HalDevice *      hal_pool_get_device_by_udi                   (HalPool      *pool, 
+                                                               const char   *udi);
+HalDevice *      hal_pool_get_device_by_capability_and_string (HalPool      *pool, 
+                                                               const char   *capability,
+                                                               const char   *key,
+                                                               const char   *value);
+GList *          hal_pool_find_by_capability                  (HalPool      *pool, 
+                                                               const char   *capability);
+
+#endif /* HAL_POOL_H */

Added: trunk/monitor/gphoto2/hal-utils.c
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-utils.c	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,142 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ *         Christian Kellner <gicmo gnome org>
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "string.h"
+
+#include "hal-utils.h"
+
+static const struct {
+  const char *disc_type;
+  const char *icon_name;
+  char *ui_name;
+  char *ui_name_blank;
+} disc_data[] = {
+  {"cd_rom",        "media-optical-cd-rom", N_("CD-ROM Disc"), N_("Blank CD-ROM Disc")},
+  {"cd_r",          "media-optical-cd-r", N_("CD-R Disc"), N_("Blank CD-R Disc")},
+  {"cd_rw",         "media-optical-cd-rw", N_("CD-RW Disc"), N_("Blank CD-RW Disc")},
+  {"dvd_rom",       "media-optical-dvd-rom", N_("DVD-ROM Disc"), N_("Blank DVD-ROM Disc")},
+  {"dvd_ram",       "media-optical-dvd-ram", N_("DVD-RAM Disc"), N_("Blank DVD-RAM Disc")},
+  {"dvd_r",         "media-optical-dvd-r", N_("DVD-ROM Disc"), N_("Blank DVD-ROM Disc")},
+  {"dvd_rw",        "media-optical-dvd-rw", N_("DVD-RW Disc"), N_("Blank DVD-RW Disc")},
+  {"dvd_plus_r",    "media-optical-dvd-r-plus", N_("DVD+R Disc"), N_("Blank DVD+R Disc")},
+  {"dvd_plus_rw",   "media-optical-dvd-rw-plus",  N_("DVD+RW Disc"), N_("Blank DVD+RW Disc")},
+  {"dvd_plus_r_dl", "media-optical-dvd-dl-r-plus", N_("DVD+R DL Disc"), N_("Blank DVD+R DL Disc")},
+  {"bd_rom",        "media-optical-bd-rom", N_("Blu-Ray Disc"), N_("Blank Blu-Ray Disc")},
+  {"bd_r",          "media-optical-bd-r", N_("Blu-Ray R Disc"), N_("Blank Blu-Ray R Disc")},
+  {"bd_re",         "media-optical-bd-re", N_("Blu-Ray RW Disc"), N_("Blank Blu-Ray RW Disc")},
+  {"hddvd_rom",     "media-optical-hddvd-rom", N_("HD DVD Disc"), N_("Blank HD DVD Disc")},
+  {"hddvd_r",       "media-optical-hddvd-r", N_("HD DVD-R Disc"), N_("Blank HD DVD-R Disc")},
+  {"hddvd_rw",      "media-optical-hddvd-rw", N_("HD DVD-RW Disc"), N_("Blank HD DVD-RW Disc")},
+  {"mo",            "media-optical-mo", N_("MO Disc"), N_("Blank MO Disc")},
+  {NULL,            "media-optical", N_("Disc"), N_("Blank Disc")}
+};
+
+const char *
+get_disc_icon (const char *disc_type)
+{
+  int n;
+
+  for (n = 0; disc_data[n].disc_type != NULL; n++)
+    {
+      if (strcmp (disc_data[n].disc_type, disc_type) == 0)
+        break;
+    }
+
+  return disc_data[n].icon_name;
+}
+
+const char *
+get_disc_name (const char *disc_type, gboolean is_blank)
+{
+  int n;
+
+  for (n = 0; disc_data[n].disc_type != NULL; n++)
+    {
+      if (strcmp (disc_data[n].disc_type, disc_type) == 0)
+        break;
+    }
+
+  if (is_blank)
+    return dgettext (GETTEXT_PACKAGE, disc_data[n].ui_name_blank);
+  else
+    return dgettext (GETTEXT_PACKAGE, disc_data[n].ui_name);
+}
+
+/*
+ * Creates a GThemedIcon from icon_name and creates default
+ * fallbacks from fallbacks. Is smart in the case that icon_name
+ * and fallbacks are identically.
+ * Note: See the GThemedIcon documentation for more information
+ * on default fallbacks
+ */
+GIcon *
+get_themed_icon_with_fallbacks (const char *icon_name,
+                                const char *fallbacks)
+{
+  int i = 0, dashes = 0;
+  const char *p;
+  char *dashp;
+  char *last;
+  char **names;
+  GIcon *icon;
+
+  if (G_UNLIKELY (icon_name == NULL))
+    return NULL;
+
+  if (fallbacks == NULL)
+    return g_themed_icon_new (icon_name);
+
+  p = fallbacks;
+  while (*p)
+    {
+      if (*p == '-')
+        dashes++;
+      p++;
+    }
+
+  if (strcmp (icon_name, fallbacks))
+    {
+      names = g_new (char *, dashes + 3);
+      names[i++] = g_strdup (icon_name);
+    }
+  else
+    names = g_new (char *, dashes + 2);
+
+  names[i++] = last = g_strdup (fallbacks);
+
+  while ((dashp = strrchr (last, '-')) != NULL)
+    names[i++] = last = g_strndup (last, dashp - last);
+
+  names[i++] = NULL;
+  icon =  g_themed_icon_new_from_names (names, -1);
+  g_strfreev (names);
+
+  return icon;
+}
+

Added: trunk/monitor/gphoto2/hal-utils.h
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/hal-utils.h	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,40 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ *         Chrsitian Kellner <gicmo gnome org>
+ */
+
+#ifndef __HAL_UTILS_H__
+#define __HAL_UTILS_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+const char * get_disc_icon (const char *disc_type);
+const char * get_disc_name (const char *disc_type, gboolean is_blank);
+
+GIcon *      get_themed_icon_with_fallbacks (const char *icon_name,
+                                             const char *fallbacks);
+
+G_END_DECLS
+
+#endif /* __HAL_UTILS_H__ */

Added: trunk/monitor/gphoto2/org.gtk.Private.GPhoto2VolumeMonitor.service.in
==============================================================================
--- (empty file)
+++ trunk/monitor/gphoto2/org.gtk.Private.GPhoto2VolumeMonitor.service.in	Mon Jul 21 21:23:37 2008
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gtk.Private.GPhoto2VolumeMonitor
+Exec= libexecdir@/gvfs-gphoto2-volume-monitor

Modified: trunk/monitor/hal/ghalvolume.c
==============================================================================
--- trunk/monitor/hal/ghalvolume.c	(original)
+++ trunk/monitor/hal/ghalvolume.c	Mon Jul 21 21:23:37 2008
@@ -304,72 +304,6 @@
                           (GDestroyNotify) g_free);
 }
 
-#ifdef HAVE_GPHOTO2
-static void
-do_update_from_hal_for_camera (GHalVolume *v)
-{
-  const char *vendor;
-  const char *product;
-  const char *icon_from_hal;
-  const char *name_from_hal;
-  gboolean is_audio_player;
-
-  vendor = hal_device_get_property_string (v->drive_device, "usb_device.vendor");
-  product = hal_device_get_property_string (v->drive_device, "usb_device.product");
-  icon_from_hal = hal_device_get_property_string (v->device, "info.desktop.icon");
-  name_from_hal = hal_device_get_property_string (v->device, "info.desktop.name");
-
-  is_audio_player = hal_device_has_capability (v->device, "portable_audio_player");
-
-  v->name = NULL;
-  if (strlen (name_from_hal) > 0)
-    v->name = g_strdup (name_from_hal);
-  else if (vendor == NULL)
-    {
-      if (product != NULL)
-        v->name = g_strdup (product);
-    }
-  else
-    {
-      if (product != NULL)
-        v->name = g_strdup_printf ("%s %s", vendor, product);
-      else
-        {
-          if (is_audio_player)
-            {
-              /* Translators: %s is the device vendor */
-              v->name = g_strdup_printf (_("%s Audio Player"), vendor);
-            }
-          else
-            {
-              /* Translators: %s is the device vendor */
-              v->name = g_strdup_printf (_("%s Camera"), vendor);
-            }
-        }
-    }
-  if (v->name == NULL)
-    {
-      if (is_audio_player)
-        v->name = g_strdup (_("Audio Player"));
-      else
-        v->name = g_strdup (_("Camera"));
-    }
-
-  if (strlen (icon_from_hal) > 0)
-    v->icon = g_strdup (icon_from_hal);
-  else if (is_audio_player)
-    v->icon = g_strdup ("multimedia-player");
-  else
-    v->icon = g_strdup ("camera");
-  v->mount_path = NULL;
-
-  g_object_set_data_full (G_OBJECT (v), 
-                          "hal-storage-device-capabilities",
-                          dupv_and_uniqify (hal_device_get_property_strlist (v->device, "info.capabilities")),
-                          (GDestroyNotify) g_strfreev);
-}
-#endif
-
 static void
 update_from_hal (GHalVolume *mv, gboolean emit_changed)
 {
@@ -386,16 +320,7 @@
   g_free (mv->name);
   g_free (mv->icon);
   g_free (mv->mount_path);
-#ifdef HAVE_GPHOTO2
-  if (hal_device_has_capability (mv->device, "camera") || 
-      (hal_device_has_capability (mv->device, "portable_audio_player") &&
-       hal_device_get_property_bool (mv->device, "camera.libgphoto2.support")))
-    do_update_from_hal_for_camera (mv);
-  else
-    do_update_from_hal (mv);
-#else
   do_update_from_hal (mv);
-#endif
 
   if (emit_changed)
     {
@@ -481,32 +406,6 @@
       
       device_path = hal_device_get_property_string (device, "block.device");
     }
-#ifdef HAVE_GPHOTO2
-  else if (hal_device_has_capability (device, "camera") ||
-           (hal_device_has_capability (device, "portable_audio_player") &&
-            hal_device_get_property_bool (device, "camera.libgphoto2.support")))
-    {
-
-      /* 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;

Modified: trunk/monitor/hal/ghalvolumemonitor.c
==============================================================================
--- trunk/monitor/hal/ghalvolumemonitor.c	(original)
+++ trunk/monitor/hal/ghalvolumemonitor.c	Mon Jul 21 21:23:37 2008
@@ -57,7 +57,6 @@
 
   HalPool *pool;
 
-  GList *last_camera_devices;
   GList *last_optical_disc_devices;
   GList *last_drive_devices;
   GList *last_volume_devices;
@@ -72,8 +71,6 @@
   GList *disc_volumes;
   GList *disc_mounts;
 
-  /* Digital cameras (e.g. gphoto2) are kept here */
-  GList *camera_volumes;
 };
 
 static void mountpoints_changed      (GUnixMountMonitor  *mount_monitor,
@@ -99,9 +96,6 @@
                                       GList **removed_volumes,
                                       GList **added_mounts,
                                       GList **removed_mounts);
-static void update_cameras           (GHalVolumeMonitor *monitor,
-                                      GList **added_volumes,
-                                      GList **removed_volumes);
 
 
 G_DEFINE_TYPE (GHalVolumeMonitor, g_hal_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR)
@@ -116,7 +110,7 @@
 static HalPool *
 get_hal_pool (void)
 {
-  char *cap_only[] = {"block", "camera", "portable_audio_player", "usb_device", NULL};
+  char *cap_only[] = {"block", NULL};
 
   if (pool == NULL)
     pool = hal_pool_new (cap_only);
@@ -153,7 +147,6 @@
   g_object_unref (monitor->mount_monitor);
   g_object_unref (monitor->pool);
   
-  list_free (monitor->last_camera_devices);
   list_free (monitor->last_optical_disc_devices);
   list_free (monitor->last_drive_devices);
   list_free (monitor->last_volume_devices);
@@ -168,7 +161,6 @@
 
   list_free (monitor->disc_volumes);
   list_free (monitor->disc_mounts);
-  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);
@@ -208,8 +200,6 @@
   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);
 
@@ -512,19 +502,6 @@
         }
     }
 
-  /* gphoto2:// as foreign mounts */
-  for (l = the_volume_monitor->camera_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);
   
@@ -736,24 +713,6 @@
   return NULL;
 }
 
-#ifdef HAVE_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)
 {
@@ -1034,7 +993,6 @@
   update_discs (monitor,
                 &added_volumes, &removed_volumes,
                 &added_mounts, &removed_mounts);
-  update_cameras (monitor, &added_volumes, &removed_volumes);
   G_UNLOCK (hal_vm);
 
   if (emit_changes)
@@ -1438,122 +1396,3 @@
   list_free (monitor->last_optical_disc_devices);
   monitor->last_optical_disc_devices = new_optical_disc_devices;
 }
-
-static void
-update_cameras (GHalVolumeMonitor *monitor,
-                GList **added_volumes,
-                GList **removed_volumes)
-{
-#ifdef HAVE_GPHOTO2
-  GList *new_camera_devices;
-  GList *new_mpt_devices;
-  GList *removed, *added;
-  GList *l, *ll;
-  GHalVolume *volume;
-  const char *udi;
-
-  new_mpt_devices = hal_pool_find_by_capability (monitor->pool, "portable_audio_player");
-  for (l = new_mpt_devices; l != NULL; l = ll)
-    {
-      HalDevice *d = l->data;
-      ll = l->next;
-      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_mpt_devices = g_list_delete_link (new_mpt_devices, l);
-        }
-    }
-
-  new_camera_devices = hal_pool_find_by_capability (monitor->pool, "camera");
-  new_camera_devices = g_list_concat (new_camera_devices, new_mpt_devices);
-  for (l = new_camera_devices; l != NULL; l = ll)
-    {
-      HalDevice *d = l->data;
-      ll = l->next;
-      /*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);
-          *removed_volumes = g_list_prepend (*removed_volumes, 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;
-      gboolean found;
-
-      /* Look for the device in the added volumes, so as
-       * not to add devices that are both audio players, and cameras */
-      found = FALSE;
-      for (ll = *added_volumes; ll; ll = ll->next)
-        {
-	  if (g_hal_volume_has_udi (ll->data, hal_device_get_udi (d)) != FALSE)
-	    {
-	      found = TRUE;
-	      break;
-	    }
-	}
-
-      if (found)
-        continue;
-
-      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);
-          *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
-        }
-    }
-
-  g_list_free (added);
-  g_list_free (removed);
-  list_free (monitor->last_camera_devices);
-  monitor->last_camera_devices = new_camera_devices;
-#endif
-}

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Mon Jul 21 21:23:37 2008
@@ -65,6 +65,9 @@
 monitor/hal/ghalvolume.c
 monitor/hal/ghalvolumemonitor.c
 monitor/hal/hal-utils.c
+monitor/gphoto2/ggphoto2volume.c
+monitor/gphoto2/ggphoto2volumemonitor.c
+monitor/gphoto2/hal-utils.c
 programs/gvfs-cat.c
 programs/gvfs-copy.c
 programs/gvfs-info.c



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