From 953132a87aed73507042a6279b343523741a1800 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 24 Sep 2008 12:40:53 +0000 Subject: Tagged for release 1.0.1 svn path=/tags/GVFS_1_0_1/; revision=2025 --- gnome-2-24/monitor/proxy/Makefile.am | 67 + gnome-2-24/monitor/proxy/gproxydrive.c | 578 +++++++++ gnome-2-24/monitor/proxy/gproxydrive.h | 55 + gnome-2-24/monitor/proxy/gproxymount.c | 560 +++++++++ gnome-2-24/monitor/proxy/gproxymount.h | 56 + gnome-2-24/monitor/proxy/gproxyvolume.c | 689 ++++++++++ gnome-2-24/monitor/proxy/gproxyvolume.h | 58 + gnome-2-24/monitor/proxy/gproxyvolumemonitor.c | 1321 ++++++++++++++++++++ gnome-2-24/monitor/proxy/gproxyvolumemonitor.h | 77 ++ .../monitor/proxy/gvfsproxyvolumemonitordaemon.c | 1155 +++++++++++++++++ .../monitor/proxy/gvfsproxyvolumemonitordaemon.h | 35 + .../monitor/proxy/remote-volume-monitor-module.c | 64 + 12 files changed, 4715 insertions(+) create mode 100644 gnome-2-24/monitor/proxy/Makefile.am create mode 100644 gnome-2-24/monitor/proxy/gproxydrive.c create mode 100644 gnome-2-24/monitor/proxy/gproxydrive.h create mode 100644 gnome-2-24/monitor/proxy/gproxymount.c create mode 100644 gnome-2-24/monitor/proxy/gproxymount.h create mode 100644 gnome-2-24/monitor/proxy/gproxyvolume.c create mode 100644 gnome-2-24/monitor/proxy/gproxyvolume.h create mode 100644 gnome-2-24/monitor/proxy/gproxyvolumemonitor.c create mode 100644 gnome-2-24/monitor/proxy/gproxyvolumemonitor.h create mode 100644 gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.c create mode 100644 gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.h create mode 100644 gnome-2-24/monitor/proxy/remote-volume-monitor-module.c (limited to 'gnome-2-24/monitor/proxy') diff --git a/gnome-2-24/monitor/proxy/Makefile.am b/gnome-2-24/monitor/proxy/Makefile.am new file mode 100644 index 00000000..9f1c9743 --- /dev/null +++ b/gnome-2-24/monitor/proxy/Makefile.am @@ -0,0 +1,67 @@ + +NULL = + +remote_volume_monitorsdir = $(datadir)/gvfs/remote-volume-monitors + +module_flags = -export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)' + +giomodules_LTLIBRARIES = libgioremote-volume-monitor.la + +libgioremote_volume_monitor_la_SOURCES = \ + remote-volume-monitor-module.c \ + gproxydrive.c gproxydrive.h \ + gproxyvolume.c gproxyvolume.h \ + gproxymount.c gproxymount.h \ + gproxyvolumemonitor.c gproxyvolumemonitor.h \ + $(NULL) + +libgioremote_volume_monitor_la_CFLAGS = \ + -DG_LOG_DOMAIN=\"GVFS-RemoteVolumeMonitor\" \ + -I$(top_srcdir)/common \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) \ + -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\" \ + -DREMOTE_VOLUME_MONITORS_DIR=\"$(remote_volume_monitorsdir)\" \ + -DGVFS_LOCALEDIR=\""$(localedir)"\" \ + -DG_DISABLE_DEPRECATED \ + $(NULL) + +libgioremote_volume_monitor_la_LDFLAGS = \ + $(module_flags) \ + $(NULL) + +libgioremote_volume_monitor_la_LIBADD = \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) \ + $(top_builddir)/common/libgvfscommon.la \ + $(NULL) + +############################################################################ + +noinst_LTLIBRARIES = libgvfsproxyvolumemonitordaemon-noin.la + +libgvfsproxyvolumemonitordaemon_noin_la_SOURCES = \ + gvfsproxyvolumemonitordaemon.c \ + gvfsproxyvolumemonitordaemon.h + +libgvfsproxyvolumemonitordaemon_noin_la_CFLAGS = \ + -I$(top_srcdir)/common \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(GDU_CFLAGS) \ + -DG_LOG_DOMAIN=\"GVFS-RemoteVolumeMonitorDaemon\" \ + -DGVFS_LOCALEDIR=\""$(localedir)"\" \ + -DG_DISABLE_DEPRECATED \ + $(NULL) + +libgvfsproxyvolumemonitordaemon_noin_la_LIBADD = \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) \ + $(top_builddir)/common/libgvfscommon.la \ + $(NULL) + +clean-local: + rm -f *~ *.loT + +install-data-local: + mkdir -p $(DESTDIR)$(remote_volume_monitorsdir) diff --git a/gnome-2-24/monitor/proxy/gproxydrive.c b/gnome-2-24/monitor/proxy/gproxydrive.c new file mode 100644 index 00000000..b1e9533b --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxydrive.c @@ -0,0 +1,578 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* gvfs - extensions for gio + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "gproxyvolumemonitor.h" +#include "gproxydrive.h" +#include "gproxyvolume.h" + +/* Protects all fields of GProxyDrive that can change */ +G_LOCK_DEFINE_STATIC(proxy_drive); + +struct _GProxyDrive { + GObject parent; + + GProxyVolumeMonitor *volume_monitor; + + char *id; + char *name; + GIcon *icon; + char **volume_ids; + gboolean can_eject; + gboolean can_poll_for_media; + gboolean is_media_check_automatic; + gboolean has_media; + gboolean is_media_removable; + + GHashTable *identifiers; +}; + +static void g_proxy_drive_drive_iface_init (GDriveIface *iface); + +#define _G_IMPLEMENT_INTERFACE_DYNAMIC(TYPE_IFACE, iface_init) { \ + const GInterfaceInfo g_implement_interface_info = { \ + (GInterfaceInitFunc) iface_init, NULL, NULL \ + }; \ + g_type_module_add_interface (type_module, g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \ +} + +G_DEFINE_DYNAMIC_TYPE_EXTENDED (GProxyDrive, g_proxy_drive, G_TYPE_OBJECT, 0, + _G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_DRIVE, + g_proxy_drive_drive_iface_init)) + +static void +g_proxy_drive_finalize (GObject *object) +{ + GProxyDrive *drive; + + drive = G_PROXY_DRIVE (object); + + if (drive->volume_monitor != NULL) + g_object_unref (drive->volume_monitor); + g_free (drive->id); + g_free (drive->name); + if (drive->icon != NULL) + g_object_unref (drive->icon); + g_strfreev (drive->volume_ids); + if (drive->identifiers != NULL) + g_hash_table_unref (drive->identifiers); + + if (G_OBJECT_CLASS (g_proxy_drive_parent_class)->finalize) + (*G_OBJECT_CLASS (g_proxy_drive_parent_class)->finalize) (object); +} + +static void +g_proxy_drive_class_init (GProxyDriveClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_proxy_drive_finalize; +} + +static void +g_proxy_drive_class_finalize (GProxyDriveClass *klass) +{ +} + +static void +g_proxy_drive_init (GProxyDrive *proxy_drive) +{ +} + +GProxyDrive * +g_proxy_drive_new (GProxyVolumeMonitor *volume_monitor) +{ + GProxyDrive *drive; + drive = g_object_new (G_TYPE_PROXY_DRIVE, NULL); + drive->volume_monitor = g_object_ref (volume_monitor); + return drive; +} + +/* string id + * string name + * string gicon_data + * boolean can-eject + * boolean can-poll-for-media + * boolean has-media + * boolean is-media-removable + * array:string volume-ids + * dict:string->string identifiers + */ +#define DRIVE_STRUCT_TYPE "(sssbbbasa{ss})" + +void +g_proxy_drive_update (GProxyDrive *drive, + DBusMessageIter *iter) +{ + DBusMessageIter iter_struct; + DBusMessageIter iter_volume_ids_iter; + const char *id; + const char *name; + const char *gicon_data; + dbus_bool_t can_eject; + dbus_bool_t can_poll_for_media; + dbus_bool_t has_media; + dbus_bool_t is_media_removable; + GPtrArray *volume_ids; + GHashTable *identifiers; + + dbus_message_iter_recurse (iter, &iter_struct); + dbus_message_iter_get_basic (&iter_struct, &id); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &name); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &gicon_data); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &can_eject); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &can_poll_for_media); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &has_media); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &is_media_removable); + dbus_message_iter_next (&iter_struct); + + volume_ids = g_ptr_array_new (); + dbus_message_iter_recurse (&iter_struct, &iter_volume_ids_iter); + while (dbus_message_iter_get_arg_type (&iter_volume_ids_iter) != DBUS_TYPE_INVALID) + { + const char *volume_id; + dbus_message_iter_get_basic (&iter_volume_ids_iter, &volume_id); + dbus_message_iter_next (&iter_volume_ids_iter); + g_ptr_array_add (volume_ids, (gpointer) volume_id); + } + g_ptr_array_add (volume_ids, NULL); + dbus_message_iter_next (&iter_struct); + + identifiers = _get_identifiers (&iter_struct); + dbus_message_iter_next (&iter_struct); + + if (drive->id != NULL && strcmp (drive->id, id) != 0) + { + g_warning ("id mismatch during update of drive"); + goto out; + } + + if (strlen (name) == 0) + name = NULL; + + /* out with the old */ + g_free (drive->id); + g_free (drive->name); + if (drive->icon != NULL) + g_object_unref (drive->icon); + g_strfreev (drive->volume_ids); + if (drive->identifiers != NULL) + g_hash_table_unref (drive->identifiers); + + /* in with the new */ + drive->id = g_strdup (id); + drive->name = g_strdup (name); + drive->icon = _g_icon_new_from_serialized_data (gicon_data); + drive->can_eject = can_eject; + drive->can_poll_for_media = can_poll_for_media; + drive->has_media = has_media; + drive->is_media_removable = is_media_removable; + drive->identifiers = identifiers != NULL ? g_hash_table_ref (identifiers) : NULL; + drive->volume_ids = g_strdupv ((char **) volume_ids->pdata); + + out: + g_ptr_array_free (volume_ids, TRUE); + g_hash_table_unref (identifiers); +} + +static GIcon * +g_proxy_drive_get_icon (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + GIcon *icon; + + G_LOCK (proxy_drive); + icon = proxy_drive->icon != NULL ? g_object_ref (proxy_drive->icon) : NULL; + G_UNLOCK (proxy_drive); + + return icon; +} + +static char * +g_proxy_drive_get_name (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + char *name; + + G_LOCK (proxy_drive); + name = g_strdup (proxy_drive->name); + G_UNLOCK (proxy_drive); + + return name; +} + +static GList * +g_proxy_drive_get_volumes (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + GList *l; + + l = NULL; + + G_LOCK (proxy_drive); + if (proxy_drive->volume_monitor != NULL && proxy_drive->volume_ids != NULL) + { + int n; + + for (n = 0; proxy_drive->volume_ids[n] != NULL; n++) + { + GProxyVolume *volume; + volume = g_proxy_volume_monitor_get_volume_for_id (proxy_drive->volume_monitor, proxy_drive->volume_ids[n]); + if (volume != NULL) + l = g_list_append (l, volume); + } + } + G_UNLOCK (proxy_drive); + + return l; +} + +static gboolean +g_proxy_drive_has_volumes (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + gboolean res; + + G_LOCK (proxy_drive); + res = (proxy_drive->volume_ids != NULL && g_strv_length (proxy_drive->volume_ids) > 0); + G_UNLOCK (proxy_drive); + + return res; +} + +static gboolean +g_proxy_drive_is_media_removable (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + gboolean res; + + G_LOCK (proxy_drive); + res = proxy_drive->is_media_removable; + G_UNLOCK (proxy_drive); + + return res; +} + +static gboolean +g_proxy_drive_has_media (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + gboolean res; + + G_LOCK (proxy_drive); + res = proxy_drive->has_media; + G_UNLOCK (proxy_drive); + + return res; +} + +static gboolean +g_proxy_drive_is_media_check_automatic (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + gboolean res; + + G_LOCK (proxy_drive); + res = proxy_drive->is_media_check_automatic; + G_UNLOCK (proxy_drive); + + return res; +} + +static gboolean +g_proxy_drive_can_eject (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + gboolean res; + + G_LOCK (proxy_drive); + res = proxy_drive->can_eject; + G_UNLOCK (proxy_drive); + + return res; +} + +static gboolean +g_proxy_drive_can_poll_for_media (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + gboolean res; + + G_LOCK (proxy_drive); + res = proxy_drive->can_poll_for_media; + G_UNLOCK (proxy_drive); + + return res; +} + +static char * +g_proxy_drive_get_identifier (GDrive *drive, + const char *kind) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + char *res; + + G_LOCK (proxy_drive); + if (proxy_drive->identifiers != NULL) + res = g_strdup (g_hash_table_lookup (proxy_drive->identifiers, kind)); + else + res = NULL; + G_UNLOCK (proxy_drive); + + return res; +} + +static void +add_identifier_key (const char *key, const char *value, GPtrArray *res) +{ + g_ptr_array_add (res, g_strdup (key)); +} + +static char ** +g_proxy_drive_enumerate_identifiers (GDrive *drive) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + GPtrArray *res; + + res = g_ptr_array_new (); + + G_LOCK (proxy_drive); + if (proxy_drive->identifiers != NULL) + g_hash_table_foreach (proxy_drive->identifiers, (GHFunc) add_identifier_key, res); + G_UNLOCK (proxy_drive); + + /* Null-terminate */ + g_ptr_array_add (res, NULL); + + return (char **) g_ptr_array_free (res, FALSE); +} + +const char * +g_proxy_drive_get_id (GProxyDrive *drive) +{ + return drive->id; +} + +typedef struct { + GObject *object; + GAsyncReadyCallback callback; + gpointer user_data; + GCancellable *cancellable; +} DBusOp; + +static void +eject_cb (DBusMessage *reply, + GError *error, + DBusOp *data) +{ + GSimpleAsyncResult *simple; + if (error != NULL) + simple = g_simple_async_result_new_from_error (data->object, + data->callback, + data->user_data, + error); + else + simple = g_simple_async_result_new (data->object, + data->callback, + data->user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); + + g_object_unref (data->object); + g_free (data); +} + +static void +g_proxy_drive_eject (GDrive *drive, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + DBusConnection *connection; + const char *name; + DBusMessage *message; + DBusOp *data; + dbus_uint32_t _flags = flags; + + G_LOCK (proxy_drive); + + data = g_new0 (DBusOp, 1); + data->object = g_object_ref (drive); + data->callback = callback; + data->user_data = user_data; + data->cancellable = cancellable; + + connection = g_proxy_volume_monitor_get_dbus_connection (proxy_drive->volume_monitor); + name = g_proxy_volume_monitor_get_dbus_name (proxy_drive->volume_monitor); + + message = dbus_message_new_method_call (name, + "/", + "org.gtk.Private.RemoteVolumeMonitor", + "DriveEject"); + dbus_message_append_args (message, + DBUS_TYPE_STRING, + &(proxy_drive->id), + DBUS_TYPE_UINT32, + &_flags, + DBUS_TYPE_INVALID); + G_UNLOCK (proxy_drive); + + _g_dbus_connection_call_async (connection, + message, + -1, + (GAsyncDBusCallback) eject_cb, + data); + dbus_connection_unref (connection); + dbus_message_unref (message); +} + +static gboolean +g_proxy_drive_eject_finish (GDrive *drive, + GAsyncResult *result, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + return TRUE; +} + +static void +poll_for_media_cb (DBusMessage *reply, + GError *error, + DBusOp *data) +{ + GSimpleAsyncResult *simple; + if (error != NULL) + simple = g_simple_async_result_new_from_error (data->object, + data->callback, + data->user_data, + error); + else + simple = g_simple_async_result_new (data->object, + data->callback, + data->user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); + + g_object_unref (data->object); + g_free (data); +} + +static void +g_proxy_drive_poll_for_media (GDrive *drive, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GProxyDrive *proxy_drive = G_PROXY_DRIVE (drive); + DBusConnection *connection; + const char *name; + DBusMessage *message; + DBusOp *data; + + G_LOCK (proxy_drive); + + data = g_new0 (DBusOp, 1); + data->object = g_object_ref (drive); + data->callback = callback; + data->user_data = user_data; + data->cancellable = cancellable; + + connection = g_proxy_volume_monitor_get_dbus_connection (proxy_drive->volume_monitor); + name = g_proxy_volume_monitor_get_dbus_name (proxy_drive->volume_monitor); + + message = dbus_message_new_method_call (name, + "/", + "org.gtk.Private.RemoteVolumeMonitor", + "DrivePollForMedia"); + dbus_message_append_args (message, + DBUS_TYPE_STRING, + &(proxy_drive->id), + DBUS_TYPE_INVALID); + G_UNLOCK (proxy_drive); + + _g_dbus_connection_call_async (connection, + message, + -1, + (GAsyncDBusCallback) poll_for_media_cb, + data); + dbus_connection_unref (connection); + dbus_message_unref (message); +} + +static gboolean +g_proxy_drive_poll_for_media_finish (GDrive *drive, + GAsyncResult *result, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + return TRUE; +} + + +static void +g_proxy_drive_drive_iface_init (GDriveIface *iface) +{ + iface->get_name = g_proxy_drive_get_name; + iface->get_icon = g_proxy_drive_get_icon; + iface->has_volumes = g_proxy_drive_has_volumes; + iface->get_volumes = g_proxy_drive_get_volumes; + iface->is_media_removable = g_proxy_drive_is_media_removable; + iface->has_media = g_proxy_drive_has_media; + iface->is_media_check_automatic = g_proxy_drive_is_media_check_automatic; + iface->can_eject = g_proxy_drive_can_eject; + iface->can_poll_for_media = g_proxy_drive_can_poll_for_media; + iface->eject = g_proxy_drive_eject; + iface->eject_finish = g_proxy_drive_eject_finish; + iface->poll_for_media = g_proxy_drive_poll_for_media; + iface->poll_for_media_finish = g_proxy_drive_poll_for_media_finish; + iface->get_identifier = g_proxy_drive_get_identifier; + iface->enumerate_identifiers = g_proxy_drive_enumerate_identifiers; +} + +void +g_proxy_drive_register (GIOModule *module) +{ + g_proxy_drive_register_type (G_TYPE_MODULE (module)); +} diff --git a/gnome-2-24/monitor/proxy/gproxydrive.h b/gnome-2-24/monitor/proxy/gproxydrive.h new file mode 100644 index 00000000..7494286c --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxydrive.h @@ -0,0 +1,55 @@ +/* -*- 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 + */ + +#ifndef __G_PROXY_DRIVE_H__ +#define __G_PROXY_DRIVE_H__ + +#include +#include + +#include "gproxyvolumemonitor.h" + +G_BEGIN_DECLS + +#define G_TYPE_PROXY_DRIVE (g_proxy_drive_get_type ()) +#define G_PROXY_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_PROXY_DRIVE, GProxyDrive)) +#define G_PROXY_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_PROXY_DRIVE, GProxyDriveClass)) +#define G_IS_PROXY_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_PROXY_DRIVE)) +#define G_IS_PROXY_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_PROXY_DRIVE)) + +typedef struct _GProxyDriveClass GProxyDriveClass; + +struct _GProxyDriveClass { + GObjectClass parent_class; +}; + +GType g_proxy_drive_get_type (void) G_GNUC_CONST; +void g_proxy_drive_register (GIOModule *module); +GProxyDrive *g_proxy_drive_new (GProxyVolumeMonitor *volume_monitor); +void g_proxy_drive_update (GProxyDrive *drive, + DBusMessageIter *iter); +const char *g_proxy_drive_get_id (GProxyDrive *drive); + +G_END_DECLS + +#endif /* __G_PROXY_DRIVE_H__ */ diff --git a/gnome-2-24/monitor/proxy/gproxymount.c b/gnome-2-24/monitor/proxy/gproxymount.c new file mode 100644 index 00000000..123f5c43 --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxymount.c @@ -0,0 +1,560 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* gvfs - extensions for gio + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "gproxyvolumemonitor.h" +#include "gproxymount.h" +#include "gproxyvolume.h" + +/* Protects all fields of GProxyMount that can change */ +G_LOCK_DEFINE_STATIC(proxy_mount); + +struct _GProxyMount { + GObject parent; + + GProxyVolumeMonitor *volume_monitor; + + char *id; + char *name; + char *uuid; + char *volume_id; + gboolean can_unmount; + char **x_content_types; + GFile *root; + GIcon *icon; +}; + +static void g_proxy_mount_mount_iface_init (GMountIface *iface); + +#define _G_IMPLEMENT_INTERFACE_DYNAMIC(TYPE_IFACE, iface_init) { \ + const GInterfaceInfo g_implement_interface_info = { \ + (GInterfaceInitFunc) iface_init, NULL, NULL \ + }; \ + g_type_module_add_interface (type_module, g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \ +} +G_DEFINE_DYNAMIC_TYPE_EXTENDED (GProxyMount, g_proxy_mount, G_TYPE_OBJECT, 0, + _G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_MOUNT, + g_proxy_mount_mount_iface_init)) + +static void +g_proxy_mount_finalize (GObject *object) +{ + GProxyMount *mount; + + mount = G_PROXY_MOUNT (object); + + g_free (mount->id); + g_free (mount->name); + g_free (mount->uuid); + g_free (mount->volume_id); + g_strfreev (mount->x_content_types); + if (mount->icon != NULL) + g_object_unref (mount->icon); + if (mount->root != NULL) + g_object_unref (mount->root); + + if (mount->volume_monitor != NULL) + g_object_unref (mount->volume_monitor); + + if (G_OBJECT_CLASS (g_proxy_mount_parent_class)->finalize) + (*G_OBJECT_CLASS (g_proxy_mount_parent_class)->finalize) (object); +} + +static void +g_proxy_mount_class_init (GProxyMountClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_proxy_mount_finalize; +} + +static void +g_proxy_mount_class_finalize (GProxyMountClass *klass) +{ +} + +static void +g_proxy_mount_init (GProxyMount *proxy_mount) +{ +} + +GProxyMount * +g_proxy_mount_new (GProxyVolumeMonitor *volume_monitor) +{ + GProxyMount *mount; + mount = g_object_new (G_TYPE_PROXY_MOUNT, NULL); + mount->volume_monitor = g_object_ref (volume_monitor); + return mount; +} + +gboolean +g_proxy_mount_has_mount_path (GProxyMount *mount, const char *mount_path) +{ + char *path; + gboolean result; + result = FALSE; + path = g_file_get_path (mount->root); + if (path != NULL) + { + if (strcmp (path, mount_path) == 0) + result = TRUE; + g_free (path); + } + return result; +} + +/* string id + * string name + * string gicon_data + * string uuid + * string root_uri + * boolean can-unmount + * string volume-id + * array:string x-content-types + */ + +void +g_proxy_mount_update (GProxyMount *mount, + DBusMessageIter *iter) +{ + DBusMessageIter iter_struct; + DBusMessageIter iter_x_content_types; + const char *id; + const char *name; + const char *gicon_data; + const char *uuid; + const char *root_uri; + dbus_bool_t can_unmount; + const char *volume_id; + GPtrArray *x_content_types; + + dbus_message_iter_recurse (iter, &iter_struct); + dbus_message_iter_get_basic (&iter_struct, &id); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &name); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &gicon_data); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &uuid); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &root_uri); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &can_unmount); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &volume_id); + dbus_message_iter_next (&iter_struct); + + x_content_types = g_ptr_array_new (); + dbus_message_iter_recurse (&iter_struct, &iter_x_content_types); + while (dbus_message_iter_get_arg_type (&iter_x_content_types) != DBUS_TYPE_INVALID) + { + const char *x_content_type; + dbus_message_iter_get_basic (&iter_x_content_types, &x_content_type); + dbus_message_iter_next (&iter_x_content_types); + g_ptr_array_add (x_content_types, (gpointer) x_content_type); + } + g_ptr_array_add (x_content_types, NULL); + dbus_message_iter_next (&iter_struct); + + if (mount->id != NULL && strcmp (mount->id, id) != 0) + { + g_warning ("id mismatch during update of mount"); + goto out; + } + + if (strlen (name) == 0) + name = NULL; + if (strlen (uuid) == 0) + uuid = NULL; + + /* out with the old */ + g_free (mount->id); + g_free (mount->name); + g_free (mount->uuid); + g_free (mount->volume_id); + if (mount->icon != NULL) + g_object_unref (mount->icon); + g_strfreev (mount->x_content_types); + if (mount->root != NULL) + g_object_unref (mount->root); + + /* in with the new */ + mount->id = g_strdup (id); + mount->name = g_strdup (name); + mount->icon = _g_icon_new_from_serialized_data (gicon_data); + mount->uuid = g_strdup (uuid); + mount->root = g_file_new_for_uri (root_uri); + mount->can_unmount = can_unmount; + mount->volume_id = g_strdup (volume_id); + mount->x_content_types = g_strdupv ((char **) x_content_types->pdata); + + out: + g_ptr_array_free (x_content_types, TRUE); +} + +const char * +g_proxy_mount_get_id (GProxyMount *mount) +{ + return mount->id; +} + +static GFile * +g_proxy_mount_get_root (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GFile *root; + + G_LOCK (proxy_mount); + root = proxy_mount->root != NULL ? g_object_ref (proxy_mount->root) : NULL; + G_UNLOCK (proxy_mount); + return root; +} + +static GIcon * +g_proxy_mount_get_icon (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GIcon *icon; + + G_LOCK (proxy_mount); + icon = proxy_mount->icon != NULL ? g_object_ref (proxy_mount->icon) : NULL; + G_UNLOCK (proxy_mount); + return icon; +} + +static char * +g_proxy_mount_get_uuid (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + char *uuid; + + G_LOCK (proxy_mount); + uuid = g_strdup (proxy_mount->uuid); + G_UNLOCK (proxy_mount); + return uuid; +} + +static char * +g_proxy_mount_get_name (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + char *name; + + G_LOCK (proxy_mount); + name = g_strdup (proxy_mount->name); + G_UNLOCK (proxy_mount); + + return name; +} + +static GDrive * +g_proxy_mount_get_drive (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GProxyVolume *volume; + GDrive *drive; + + G_LOCK (proxy_mount); + volume = NULL; + if (proxy_mount->volume_id != NULL && strlen (proxy_mount->volume_id) > 0) + volume = g_proxy_volume_monitor_get_volume_for_id (proxy_mount->volume_monitor, + proxy_mount->volume_id); + G_UNLOCK (proxy_mount); + + drive = NULL; + if (volume != NULL) + { + drive = g_volume_get_drive (G_VOLUME (volume)); + g_object_unref (volume); + } + + return drive; +} + +static GVolume * +g_proxy_mount_get_volume (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + GProxyVolume *volume; + + G_LOCK (proxy_mount); + volume = NULL; + if (proxy_mount->volume_id != NULL && strlen (proxy_mount->volume_id) > 0) + volume = g_proxy_volume_monitor_get_volume_for_id (proxy_mount->volume_monitor, + proxy_mount->volume_id); + G_UNLOCK (proxy_mount); + + return volume != NULL ? G_VOLUME (volume) : NULL; +} + +static gboolean +g_proxy_mount_can_unmount (GMount *mount) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + gboolean res; + + G_LOCK (proxy_mount); + res = proxy_mount->can_unmount; + G_UNLOCK (proxy_mount); + + return res; +} + +static gboolean +g_proxy_mount_can_eject (GMount *mount) +{ + GDrive *drive; + gboolean can_eject; + + can_eject = FALSE; + drive = g_proxy_mount_get_drive (mount); + if (drive != NULL) + { + can_eject = g_drive_can_eject (drive); + g_object_unref (drive); + } + + return can_eject; +} + +typedef struct { + GObject *object; + GAsyncReadyCallback callback; + gpointer user_data; +} EjectWrapperOp; + +static void +eject_wrapper_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EjectWrapperOp *data = user_data; + data->callback (data->object, res, data->user_data); + g_object_unref (data->object); + g_free (data); +} + +static void +g_proxy_mount_eject (GMount *mount, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GDrive *drive; + + drive = g_proxy_mount_get_drive (mount); + + if (drive != NULL) + { + EjectWrapperOp *data; + data = g_new0 (EjectWrapperOp, 1); + data->object = g_object_ref (mount); + data->callback = callback; + data->user_data = user_data; + g_drive_eject (drive, flags, cancellable, eject_wrapper_callback, data); + g_object_unref (drive); + } +} + +static gboolean +g_proxy_mount_eject_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + GDrive *drive; + gboolean res; + + res = TRUE; + + drive = g_proxy_mount_get_drive (mount); + + if (drive != NULL) + { + res = g_drive_eject_finish (drive, result, error); + g_object_unref (drive); + } + return res; +} + +typedef struct { + GObject *object; + GAsyncReadyCallback callback; + gpointer user_data; + GCancellable *cancellable; +} DBusOp; + +static void +unmount_cb (DBusMessage *reply, + GError *error, + DBusOp *data) +{ + GSimpleAsyncResult *simple; + if (error != NULL) + simple = g_simple_async_result_new_from_error (data->object, + data->callback, + data->user_data, + error); + else + simple = g_simple_async_result_new (data->object, + data->callback, + data->user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); + + g_object_unref (data->object); + g_free (data); +} + +static void +g_proxy_mount_unmount (GMount *mount, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + DBusConnection *connection; + const char *name; + DBusMessage *message; + DBusOp *data; + dbus_uint32_t _flags = flags; + + G_LOCK (proxy_mount); + + data = g_new0 (DBusOp, 1); + data->object = g_object_ref (mount); + data->callback = callback; + data->user_data = user_data; + data->cancellable = cancellable; + + connection = g_proxy_volume_monitor_get_dbus_connection (proxy_mount->volume_monitor); + name = g_proxy_volume_monitor_get_dbus_name (proxy_mount->volume_monitor); + + message = dbus_message_new_method_call (name, + "/", + "org.gtk.Private.RemoteVolumeMonitor", + "MountUnmount"); + dbus_message_append_args (message, + DBUS_TYPE_STRING, + &(proxy_mount->id), + DBUS_TYPE_UINT32, + &_flags, + DBUS_TYPE_INVALID); + G_UNLOCK (proxy_mount); + + _g_dbus_connection_call_async (connection, + message, + -1, + (GAsyncDBusCallback) unmount_cb, + data); + + dbus_message_unref (message); + dbus_connection_unref (connection); +} + +static gboolean +g_proxy_mount_unmount_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + return TRUE; +} + +static void +g_proxy_mount_guess_content_type (GMount *mount, + gboolean force_rescan, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + /* TODO: handle force_rescan */ + simple = g_simple_async_result_new (G_OBJECT (mount), + callback, + user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static char ** +g_proxy_mount_guess_content_type_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + return g_strdupv (proxy_mount->x_content_types); +} + +static char ** +g_proxy_mount_guess_content_type_sync (GMount *mount, + gboolean force_rescan, + GCancellable *cancellable, + GError **error) +{ + GProxyMount *proxy_mount = G_PROXY_MOUNT (mount); + /* TODO: handle force_rescan */ + return g_strdupv (proxy_mount->x_content_types); +} + +static void +g_proxy_mount_mount_iface_init (GMountIface *iface) +{ + iface->get_root = g_proxy_mount_get_root; + iface->get_name = g_proxy_mount_get_name; + iface->get_icon = g_proxy_mount_get_icon; + iface->get_uuid = g_proxy_mount_get_uuid; + iface->get_drive = g_proxy_mount_get_drive; + iface->get_volume = g_proxy_mount_get_volume; + iface->can_unmount = g_proxy_mount_can_unmount; + iface->can_eject = g_proxy_mount_can_eject; + iface->unmount = g_proxy_mount_unmount; + iface->unmount_finish = g_proxy_mount_unmount_finish; + iface->eject = g_proxy_mount_eject; + iface->eject_finish = g_proxy_mount_eject_finish; + iface->guess_content_type = g_proxy_mount_guess_content_type; + iface->guess_content_type_finish = g_proxy_mount_guess_content_type_finish; + iface->guess_content_type_sync = g_proxy_mount_guess_content_type_sync; +} + +void +g_proxy_mount_register (GIOModule *module) +{ + g_proxy_mount_register_type (G_TYPE_MODULE (module)); +} diff --git a/gnome-2-24/monitor/proxy/gproxymount.h b/gnome-2-24/monitor/proxy/gproxymount.h new file mode 100644 index 00000000..c6356518 --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxymount.h @@ -0,0 +1,56 @@ +/* -*- 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 + */ + +#ifndef __G_PROXY_MOUNT_H__ +#define __G_PROXY_MOUNT_H__ + +#include +#include + +#include "gproxyvolumemonitor.h" + +G_BEGIN_DECLS + +#define G_TYPE_PROXY_MOUNT (g_proxy_mount_get_type ()) +#define G_PROXY_MOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_PROXY_MOUNT, GProxyMount)) +#define G_PROXY_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_PROXY_MOUNT, GProxyMountClass)) +#define G_IS_PROXY_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_PROXY_MOUNT)) +#define G_IS_PROXY_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_PROXY_MOUNT)) + +typedef struct _GProxyMountClass GProxyMountClass; + +struct _GProxyMountClass { + GObjectClass parent_class; +}; + +GType g_proxy_mount_get_type (void) G_GNUC_CONST; +void g_proxy_mount_register (GIOModule *module); +GProxyMount *g_proxy_mount_new (GProxyVolumeMonitor *volume_monitor); +void g_proxy_mount_update (GProxyMount *mount, + DBusMessageIter *iter); +const char *g_proxy_mount_get_id (GProxyMount *mount); +gboolean g_proxy_mount_has_mount_path (GProxyMount *mount, const char *mount_path); + +G_END_DECLS + +#endif /* __G_PROXY_MOUNT_H__ */ diff --git a/gnome-2-24/monitor/proxy/gproxyvolume.c b/gnome-2-24/monitor/proxy/gproxyvolume.c new file mode 100644 index 00000000..23730b2f --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxyvolume.c @@ -0,0 +1,689 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* gvfs - extensions for gio + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "gproxydrive.h" +#include "gproxyvolume.h" +#include "gproxymount.h" + +/* Protects all fields of GProxyVolume that can change */ +G_LOCK_DEFINE_STATIC(proxy_volume); + +struct _GProxyVolume { + GObject parent; + + GProxyVolumeMonitor *volume_monitor; + + char *id; + char *name; + char *uuid; + char *activation_uri; + GIcon *icon; + char *drive_id; + char *mount_id; + GHashTable *identifiers; + + GMount *foreign_mount; + + gboolean can_mount; + gboolean should_automount; +}; + +static void g_proxy_volume_volume_iface_init (GVolumeIface *iface); + +#define _G_IMPLEMENT_INTERFACE_DYNAMIC(TYPE_IFACE, iface_init) { \ + const GInterfaceInfo g_implement_interface_info = { \ + (GInterfaceInitFunc) iface_init, NULL, NULL \ + }; \ + g_type_module_add_interface (type_module, g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \ +} + +G_DEFINE_DYNAMIC_TYPE_EXTENDED (GProxyVolume, g_proxy_volume, G_TYPE_OBJECT, 0, + _G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_VOLUME, + g_proxy_volume_volume_iface_init)) + +static void +g_proxy_volume_finalize (GObject *object) +{ + GProxyVolume *volume; + + volume = G_PROXY_VOLUME (object); + + g_free (volume->id); + g_free (volume->name); + g_free (volume->uuid); + g_free (volume->activation_uri); + if (volume->icon != NULL) + g_object_unref (volume->icon); + g_free (volume->drive_id); + g_free (volume->mount_id); + if (volume->identifiers != NULL) + g_hash_table_unref (volume->identifiers); + + if (volume->foreign_mount != NULL) + g_object_unref (volume->foreign_mount); + + if (volume->volume_monitor != NULL) + g_object_unref (volume->volume_monitor); + + if (G_OBJECT_CLASS (g_proxy_volume_parent_class)->finalize) + (*G_OBJECT_CLASS (g_proxy_volume_parent_class)->finalize) (object); +} + +static void +g_proxy_volume_class_init (GProxyVolumeClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_proxy_volume_finalize; +} + +static void +g_proxy_volume_class_finalize (GProxyVolumeClass *klass) +{ +} + +static void +g_proxy_volume_init (GProxyVolume *proxy_volume) +{ +} + +GProxyVolume * +g_proxy_volume_new (GProxyVolumeMonitor *volume_monitor) +{ + GProxyVolume *volume; + volume = g_object_new (G_TYPE_PROXY_VOLUME, NULL); + volume->volume_monitor = g_object_ref (volume_monitor); + return volume; +} + +static gboolean +changed_in_idle (gpointer data) +{ + GProxyVolume *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 void +foreign_mount_unmounted (GMount *mount, gpointer user_data) +{ + GProxyVolume *volume = G_PROXY_VOLUME (user_data); + gboolean check; + + G_LOCK (proxy_volume); + check = (volume->foreign_mount == mount); + G_UNLOCK (proxy_volume); + if (check) + g_proxy_volume_adopt_foreign_mount (volume, NULL); +} + +void +g_proxy_volume_adopt_foreign_mount (GProxyVolume *volume, + GMount *foreign_mount) +{ + G_LOCK (proxy_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 (proxy_volume); +} + +/* string id + * string name + * string gicon_data + * string uuid + * string activation_uri + * boolean can-mount + * boolean should-automount + * string drive-id + * string mount-id + * dict:string->string identifiers + */ + +void g_proxy_volume_update (GProxyVolume *volume, + DBusMessageIter *iter) +{ + DBusMessageIter iter_struct; + const char *id; + const char *name; + const char *gicon_data; + const char *uuid; + const char *activation_uri; + const char *drive_id; + const char *mount_id; + dbus_bool_t can_mount; + dbus_bool_t should_automount; + GHashTable *identifiers; + + dbus_message_iter_recurse (iter, &iter_struct); + dbus_message_iter_get_basic (&iter_struct, &id); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &name); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &gicon_data); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &uuid); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &activation_uri); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &can_mount); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &should_automount); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &drive_id); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &mount_id); + dbus_message_iter_next (&iter_struct); + + identifiers = _get_identifiers (&iter_struct); + dbus_message_iter_next (&iter_struct); + + if (volume->id != NULL && strcmp (volume->id, id) != 0) + { + g_warning ("id mismatch during update of volume"); + goto out; + } + + if (strlen (name) == 0) + name = NULL; + if (strlen (uuid) == 0) + uuid = NULL; + if (strlen (activation_uri) == 0) + activation_uri = NULL; + + /* out with the old */ + g_free (volume->id); + g_free (volume->name); + g_free (volume->uuid); + g_free (volume->activation_uri); + if (volume->icon != NULL) + g_object_unref (volume->icon); + g_free (volume->drive_id); + g_free (volume->mount_id); + if (volume->identifiers != NULL) + g_hash_table_unref (volume->identifiers); + + /* in with the new */ + volume->id = g_strdup (id); + volume->name = g_strdup (name); + volume->uuid = g_strdup (uuid); + volume->activation_uri = g_strdup (activation_uri); + volume->icon = _g_icon_new_from_serialized_data (gicon_data); + volume->drive_id = g_strdup (drive_id); + volume->mount_id = g_strdup (mount_id); + volume->can_mount = can_mount; + volume->should_automount = should_automount; + volume->identifiers = identifiers != NULL ? g_hash_table_ref (identifiers) : NULL; + + out: + g_hash_table_unref (identifiers); +} + +const char * +g_proxy_volume_get_id (GProxyVolume *volume) +{ + return volume->id; +} + +static GIcon * +g_proxy_volume_get_icon (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + GIcon *icon; + + G_LOCK (proxy_volume); + icon = proxy_volume->icon != NULL ? g_object_ref (proxy_volume->icon) : NULL; + G_UNLOCK (proxy_volume); + return icon; +} + +static char * +g_proxy_volume_get_name (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + char *name; + + G_LOCK (proxy_volume); + name = g_strdup (proxy_volume->name); + G_UNLOCK (proxy_volume); + return name; +} + +static char * +g_proxy_volume_get_uuid (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + char *uuid; + + G_LOCK (proxy_volume); + uuid = g_strdup (proxy_volume->uuid); + G_UNLOCK (proxy_volume); + return uuid; +} + +static gboolean +g_proxy_volume_can_mount (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + gboolean res; + + G_LOCK (proxy_volume); + res = proxy_volume->can_mount; + G_UNLOCK (proxy_volume); + return res; +} + +static gboolean +g_proxy_volume_can_eject (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + GProxyDrive *drive; + gboolean res; + + G_LOCK (proxy_volume); + res = FALSE; + if (proxy_volume->drive_id != NULL && strlen (proxy_volume->drive_id) > 0) + { + drive = g_proxy_volume_monitor_get_drive_for_id (proxy_volume->volume_monitor, + proxy_volume->drive_id); + if (drive != NULL) + { + res = g_drive_can_eject (G_DRIVE (drive)); + g_object_unref (drive); + } + } + G_UNLOCK (proxy_volume); + + return res; +} + +static gboolean +g_proxy_volume_should_automount (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + gboolean res; + + G_LOCK (proxy_volume); + res = proxy_volume->should_automount; + G_UNLOCK (proxy_volume); + + return res; +} + +static GDrive * +g_proxy_volume_get_drive (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + GProxyDrive *drive; + + G_LOCK (proxy_volume); + drive = NULL; + if (proxy_volume->drive_id != NULL && strlen (proxy_volume->drive_id) > 0) + drive = g_proxy_volume_monitor_get_drive_for_id (proxy_volume->volume_monitor, + proxy_volume->drive_id); + G_UNLOCK (proxy_volume); + + return drive != NULL ? G_DRIVE (drive) : NULL; +} + +static GMount * +g_proxy_volume_get_mount (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + GMount *mount; + + G_LOCK (proxy_volume); + if (proxy_volume->foreign_mount != NULL) + { + mount = g_object_ref (proxy_volume->foreign_mount); + } + else + { + mount = NULL; + if (proxy_volume->mount_id != NULL && strlen (proxy_volume->mount_id) > 0) + { + GProxyMount *proxy_mount; + proxy_mount = g_proxy_volume_monitor_get_mount_for_id (proxy_volume->volume_monitor, + proxy_volume->mount_id); + if (proxy_mount != NULL) + mount = G_MOUNT (proxy_mount); + } + } + G_UNLOCK (proxy_volume); + + return mount; +} + +typedef struct { + GObject *object; + GAsyncReadyCallback callback; + gpointer user_data; +} EjectWrapperOp; + +static void +eject_wrapper_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EjectWrapperOp *data = user_data; + data->callback (data->object, res, data->user_data); + g_object_unref (data->object); + g_free (data); +} + +static void +g_proxy_volume_eject (GVolume *volume, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + GProxyDrive *drive; + + drive = NULL; + G_LOCK (proxy_volume); + if (proxy_volume->drive_id != NULL && strlen (proxy_volume->drive_id) > 0) + { + drive = g_proxy_volume_monitor_get_drive_for_id (proxy_volume->volume_monitor, + proxy_volume->drive_id); + } + G_UNLOCK (proxy_volume); + + if (drive != NULL) + { + EjectWrapperOp *data; + data = g_new0 (EjectWrapperOp, 1); + data->object = g_object_ref (volume); + data->callback = callback; + data->user_data = user_data; + g_drive_eject (G_DRIVE (drive), flags, cancellable, eject_wrapper_callback, data); + g_object_unref (drive); + } +} + +static gboolean +g_proxy_volume_eject_finish (GVolume *volume, + GAsyncResult *result, + GError **error) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + GProxyDrive *drive; + gboolean res; + + G_LOCK (proxy_volume); + res = TRUE; + drive = NULL; + if (proxy_volume->drive_id != NULL && strlen (proxy_volume->drive_id) > 0) + drive = g_proxy_volume_monitor_get_drive_for_id (proxy_volume->volume_monitor, + proxy_volume->drive_id); + G_UNLOCK (proxy_volume); + + if (drive != NULL) + { + res = g_drive_eject_finish (G_DRIVE (drive), result, error); + g_object_unref (drive); + } + + return res; +} + +static char * +g_proxy_volume_get_identifier (GVolume *volume, + const char *kind) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + char *res; + + G_LOCK (proxy_volume); + if (proxy_volume->identifiers != NULL) + res = g_strdup (g_hash_table_lookup (proxy_volume->identifiers, kind)); + else + res = NULL; + G_UNLOCK (proxy_volume); + + return res; +} + +static void +add_identifier_key (const char *key, const char *value, GPtrArray *res) +{ + g_ptr_array_add (res, g_strdup (key)); +} + +static char ** +g_proxy_volume_enumerate_identifiers (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + GPtrArray *res; + + res = g_ptr_array_new (); + + G_LOCK (proxy_volume); + if (proxy_volume->identifiers != NULL) + g_hash_table_foreach (proxy_volume->identifiers, (GHFunc) add_identifier_key, res); + G_UNLOCK (proxy_volume); + + /* Null-terminate */ + g_ptr_array_add (res, NULL); + + return (char **) g_ptr_array_free (res, FALSE); +} + +typedef struct { + GObject *object; + GAsyncReadyCallback callback; + gpointer user_data; + GCancellable *cancellable; +} DBusOp; + +static void +mount_cb (DBusMessage *reply, + GError *error, + DBusOp *data) +{ + GSimpleAsyncResult *simple; + if (error != NULL) + simple = g_simple_async_result_new_from_error (data->object, + data->callback, + data->user_data, + error); + else + simple = g_simple_async_result_new (data->object, + data->callback, + data->user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); + + g_object_unref (data->object); + g_free (data); +} + +typedef struct +{ + GProxyVolume *enclosing_volume; + GAsyncReadyCallback callback; + gpointer user_data; +} ForeignMountOp; + +static void +mount_foreign_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + ForeignMountOp *data = user_data; + data->callback (G_OBJECT (data->enclosing_volume), res, data->user_data); + g_object_unref (data->enclosing_volume); + g_free (data); +} + +static void +g_proxy_volume_mount (GVolume *volume, + GMountMountFlags flags, + GMountOperation *mount_operation, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + + G_LOCK (proxy_volume); + if (proxy_volume->activation_uri != NULL) + { + ForeignMountOp *data; + GFile *root; + + data = g_new0 (ForeignMountOp, 1); + data->enclosing_volume = g_object_ref (volume); + data->callback = callback; + data->user_data = user_data; + + root = g_file_new_for_uri (proxy_volume->activation_uri); + + G_UNLOCK (proxy_volume); + + g_file_mount_enclosing_volume (root, + flags, + mount_operation, + cancellable, + mount_foreign_callback, + data); + + g_object_unref (root); + } + else + { + DBusOp *data; + DBusConnection *connection; + const char *name; + DBusMessage *message; + dbus_uint32_t _flags = flags; + dbus_bool_t use_mount_operation = mount_operation != NULL; + + /* TODO: support mount_operation */ + + data = g_new0 (DBusOp, 1); + data->object = g_object_ref (volume); + data->callback = callback; + data->user_data = user_data; + data->cancellable = cancellable; + + connection = g_proxy_volume_monitor_get_dbus_connection (proxy_volume->volume_monitor); + name = g_proxy_volume_monitor_get_dbus_name (proxy_volume->volume_monitor); + + message = dbus_message_new_method_call (name, + "/", + "org.gtk.Private.RemoteVolumeMonitor", + "VolumeMount"); + dbus_message_append_args (message, + DBUS_TYPE_STRING, + &(proxy_volume->id), + DBUS_TYPE_UINT32, + &_flags, + DBUS_TYPE_BOOLEAN, + &use_mount_operation, + DBUS_TYPE_INVALID); + G_UNLOCK (proxy_volume); + + _g_dbus_connection_call_async (connection, + message, + -1, + (GAsyncDBusCallback) mount_cb, + data); + dbus_message_unref (message); + dbus_connection_unref (connection); + } +} + +static gboolean +g_proxy_volume_mount_finish (GVolume *volume, + GAsyncResult *result, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + return TRUE; +} + +static GFile * +g_proxy_volume_get_activation_root (GVolume *volume) +{ + GProxyVolume *proxy_volume = G_PROXY_VOLUME (volume); + if (proxy_volume->activation_uri == NULL) + return NULL; + else + return g_file_new_for_uri (proxy_volume->activation_uri); +} + +static void +g_proxy_volume_volume_iface_init (GVolumeIface *iface) +{ + iface->get_name = g_proxy_volume_get_name; + iface->get_icon = g_proxy_volume_get_icon; + iface->get_uuid = g_proxy_volume_get_uuid; + iface->get_drive = g_proxy_volume_get_drive; + iface->get_mount = g_proxy_volume_get_mount; + iface->can_mount = g_proxy_volume_can_mount; + iface->can_eject = g_proxy_volume_can_eject; + iface->should_automount = g_proxy_volume_should_automount; + iface->mount_fn = g_proxy_volume_mount; + iface->mount_finish = g_proxy_volume_mount_finish; + iface->eject = g_proxy_volume_eject; + iface->eject_finish = g_proxy_volume_eject_finish; + iface->get_identifier = g_proxy_volume_get_identifier; + iface->enumerate_identifiers = g_proxy_volume_enumerate_identifiers; + iface->get_activation_root = g_proxy_volume_get_activation_root; +} + +void +g_proxy_volume_register (GIOModule *module) +{ + g_proxy_volume_register_type (G_TYPE_MODULE (module)); +} diff --git a/gnome-2-24/monitor/proxy/gproxyvolume.h b/gnome-2-24/monitor/proxy/gproxyvolume.h new file mode 100644 index 00000000..5626092f --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxyvolume.h @@ -0,0 +1,58 @@ +/* -*- 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 + */ + +#ifndef __G_PROXY_VOLUME_H__ +#define __G_PROXY_VOLUME_H__ + +#include +#include + +#include "gproxyvolumemonitor.h" + +G_BEGIN_DECLS + +#define G_TYPE_PROXY_VOLUME (g_proxy_volume_get_type ()) +#define G_PROXY_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_PROXY_VOLUME, GProxyVolume)) +#define G_PROXY_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_PROXY_VOLUME, GProxyVolumeClass)) +#define G_IS_PROXY_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_PROXY_VOLUME)) +#define G_IS_PROXY_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_PROXY_VOLUME)) + +typedef struct _GProxyVolumeClass GProxyVolumeClass; + +struct _GProxyVolumeClass { + GObjectClass parent_class; +}; + +GType g_proxy_volume_get_type (void) G_GNUC_CONST; +GProxyVolume *g_proxy_volume_new (GProxyVolumeMonitor *volume_monitor); +void g_proxy_volume_update (GProxyVolume *volume, + DBusMessageIter *iter); +const char *g_proxy_volume_get_id (GProxyVolume *volume); +void g_proxy_volume_adopt_foreign_mount (GProxyVolume *volume, + GMount *foreign_mount); +void g_proxy_volume_register (GIOModule *module); + + +G_END_DECLS + +#endif /* __G_PROXY_VOLUME_H__ */ diff --git a/gnome-2-24/monitor/proxy/gproxyvolumemonitor.c b/gnome-2-24/monitor/proxy/gproxyvolumemonitor.c new file mode 100644 index 00000000..e71fcde0 --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxyvolumemonitor.c @@ -0,0 +1,1321 @@ +/* -*- 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 + */ + +/* + * TODO: since we already call IsSupported() at module load time (in + * order to register the appropriate types) we really just should + * construct all the volume monitors. This is a good idea because + * + * - instead of calling IsSupported() we just call List() + * - e.g. exactly the same IPC overhead + * - neglible memory + cpu overhead + * - will need to construct them at some point + * - we can actually implement get_mount_for_mount_path() + * correctly even when no volume monitor is constructed + * + * - implement support for GMountOperation + * - not implemented in the HAL volume monitor and that's all + * that is using it right now. Will implement at some point + * when it's needed or someone has spare cycles. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "gproxyvolumemonitor.h" +#include "gproxymount.h" +#include "gproxyvolume.h" +#include "gproxydrive.h" + +G_LOCK_DEFINE_STATIC(proxy_vm); + +static DBusConnection *the_session_bus = NULL; +static gboolean the_session_bus_is_integrated = FALSE; +static GHashTable *the_volume_monitors = NULL; + +struct _GProxyVolumeMonitor { + GNativeVolumeMonitor parent; + DBusConnection *session_bus; + + GHashTable *drives; + GHashTable *volumes; + GHashTable *mounts; +}; + +G_DEFINE_DYNAMIC_TYPE_EXTENDED (GProxyVolumeMonitor, + g_proxy_volume_monitor, + G_TYPE_NATIVE_VOLUME_MONITOR, + G_TYPE_FLAG_ABSTRACT, + {}) + +static void seed_monitor (GProxyVolumeMonitor *monitor); + +static DBusHandlerResult filter_function (DBusConnection *connection, DBusMessage *message, void *user_data); + +static void signal_emit_in_idle (gpointer object, const char *signal_name, gpointer other_object); + +static gboolean is_supported (GProxyVolumeMonitorClass *klass); + +/* The is_supported API is kinda lame and doesn't pass in the class, + so we work around this with this hack */ +typedef gboolean (*is_supported_func) (void); + +static GProxyVolumeMonitorClass *is_supported_classes[10] = { NULL }; +static gboolean is_supported_0 (void) { return is_supported (is_supported_classes[0]); }; +static gboolean is_supported_1 (void) { return is_supported (is_supported_classes[1]); }; +static gboolean is_supported_2 (void) { return is_supported (is_supported_classes[2]); }; +static gboolean is_supported_3 (void) { return is_supported (is_supported_classes[3]); }; +static gboolean is_supported_4 (void) { return is_supported (is_supported_classes[4]); }; +static gboolean is_supported_5 (void) { return is_supported (is_supported_classes[5]); }; +static gboolean is_supported_6 (void) { return is_supported (is_supported_classes[6]); }; +static gboolean is_supported_7 (void) { return is_supported (is_supported_classes[7]); }; +static gboolean is_supported_8 (void) { return is_supported (is_supported_classes[8]); }; +static gboolean is_supported_9 (void) { return is_supported (is_supported_classes[9]); }; +static is_supported_func is_supported_funcs[] = { + is_supported_0, is_supported_1, is_supported_2, is_supported_3, + is_supported_4, is_supported_5, is_supported_6, is_supported_7, + is_supported_8, is_supported_9, + NULL +}; + +static char * +get_match_rule (GProxyVolumeMonitor *monitor) +{ + return g_strdup_printf ("type='signal'," + "interface='org.gtk.Private.RemoteVolumeMonitor'," + "sender='%s'", + g_proxy_volume_monitor_get_dbus_name (monitor)); +} + +static void +g_proxy_volume_monitor_finalize (GObject *object) +{ + GProxyVolumeMonitor *monitor; + DBusError dbus_error; + char *match_rule; + GObjectClass *parent_class; + + /* since GProxyVolumeMonitor is a non-instantiatable type we're dealing with a + * sub-type here. So we need to look at the grandparent sub-type to get the + * parent class for GProxyVolumeMonitor */ + parent_class = G_OBJECT_CLASS (g_type_class_peek_parent ( + g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)))); + + monitor = G_PROXY_VOLUME_MONITOR (object); + + g_hash_table_unref (monitor->drives); + g_hash_table_unref (monitor->volumes); + g_hash_table_unref (monitor->mounts); + + dbus_connection_remove_filter (monitor->session_bus, filter_function, monitor); + match_rule = get_match_rule (monitor); + dbus_error_init (&dbus_error); + dbus_bus_remove_match (monitor->session_bus, + match_rule, + &dbus_error); + if (dbus_error_is_set (&dbus_error)) { + /* not really a whole lot to do on failure than whine since + * GObject finalization can't fail... + */ + g_warning ("cannot remove match rule '%s': %s: %s", match_rule, dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + } + g_free (match_rule); + dbus_connection_unref (monitor->session_bus); + + if (parent_class->finalize) + parent_class->finalize (object); +} + +static GList * +get_mounts (GVolumeMonitor *volume_monitor) +{ + GProxyVolumeMonitor *monitor; + GList *l; + GHashTableIter hash_iter; + GProxyMount *mount; + + monitor = G_PROXY_VOLUME_MONITOR (volume_monitor); + l = NULL; + + G_LOCK (proxy_vm); + + g_hash_table_iter_init (&hash_iter, monitor->mounts); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &mount)) + l = g_list_append (l, g_object_ref (mount)); + + G_UNLOCK (proxy_vm); + + return l; +} + +static GList * +get_volumes (GVolumeMonitor *volume_monitor) +{ + GProxyVolumeMonitor *monitor; + GList *l; + GHashTableIter hash_iter; + GProxyVolume *volume; + + monitor = G_PROXY_VOLUME_MONITOR (volume_monitor); + l = NULL; + + G_LOCK (proxy_vm); + + g_hash_table_iter_init (&hash_iter, monitor->volumes); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &volume)) + l = g_list_append (l, g_object_ref (volume)); + + G_UNLOCK (proxy_vm); + + return l; +} + +static GList * +get_connected_drives (GVolumeMonitor *volume_monitor) +{ + GProxyVolumeMonitor *monitor; + GList *l; + GHashTableIter hash_iter; + GProxyDrive *drive; + + monitor = G_PROXY_VOLUME_MONITOR (volume_monitor); + l = NULL; + + G_LOCK (proxy_vm); + + g_hash_table_iter_init (&hash_iter, monitor->drives); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &drive)) + l = g_list_append (l, g_object_ref (drive)); + + G_UNLOCK (proxy_vm); + + return l; +} + +static GVolume * +get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) +{ + GProxyVolumeMonitor *monitor; + GHashTableIter hash_iter; + GVolume *found_volume; + GVolume *volume; + + monitor = G_PROXY_VOLUME_MONITOR (volume_monitor); + + G_LOCK (proxy_vm); + + found_volume = NULL; + g_hash_table_iter_init (&hash_iter, monitor->volumes); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &volume) && + found_volume != NULL) + { + char *_uuid; + _uuid = g_volume_get_uuid (volume); + if (_uuid != NULL) + { + if (strcmp (uuid, _uuid) == 0) + found_volume = g_object_ref (volume); + g_free (_uuid); + } + } + + G_UNLOCK (proxy_vm); + + return found_volume; +} + +static GMount * +get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) +{ + GProxyVolumeMonitor *monitor; + GHashTableIter hash_iter; + GMount *found_mount; + GMount *mount; + + monitor = G_PROXY_VOLUME_MONITOR (volume_monitor); + + G_LOCK (proxy_vm); + + found_mount = NULL; + g_hash_table_iter_init (&hash_iter, monitor->mounts); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &mount) && + found_mount != NULL) + { + char *_uuid; + _uuid = g_mount_get_uuid (mount); + if (_uuid != NULL) + { + if (strcmp (uuid, _uuid) == 0) + found_mount = g_object_ref (mount); + g_free (_uuid); + } + } + + G_UNLOCK (proxy_vm); + + return found_mount; +} + +static GMount * +get_mount_for_mount_path (const char *mount_path, + GCancellable *cancellable) +{ + GMount *mount; + GProxyVolumeMonitor *volume_monitor; + GProxyVolumeMonitorClass *klass; + GHashTableIter vm_hash_iter; + GHashTableIter vol_hash_iter; + GProxyMount *candidate_mount; + + /* This static method on GNativeVolumeMonitor is a *complete* pain + * in the ass to deal with; we need to rework gio so it's deprecated + * and thus never will get called. + * + * TODO: we don't handle the case when there's no volume monitor ever + * constructed. See TODO at the top of this file on how to handle that. + */ + + mount = NULL; + G_LOCK (proxy_vm); + + /* First find the native volume monitor if one exists */ + g_hash_table_iter_init (&vm_hash_iter, the_volume_monitors); + while (g_hash_table_iter_next (&vm_hash_iter, NULL, (gpointer) &volume_monitor)) { + klass = G_PROXY_VOLUME_MONITOR_CLASS (G_OBJECT_GET_CLASS (volume_monitor)); + + if (klass->is_native) { + /* The see if we've got a mount */ + g_hash_table_iter_init (&vol_hash_iter, volume_monitor->mounts); + while (g_hash_table_iter_next (&vol_hash_iter, NULL, (gpointer) &candidate_mount)) { + if (g_proxy_mount_has_mount_path (candidate_mount, mount_path)) + { + mount = g_object_ref (candidate_mount); + goto out; + } + } + goto out; + } + } + + out: + G_UNLOCK (proxy_vm); + return mount; +} + +static void +volume_monitor_went_away (gpointer data, + GObject *where_the_object_was) +{ + GType type = (GType) data; + G_LOCK (proxy_vm); + g_hash_table_remove (the_volume_monitors, (gpointer) type); + G_UNLOCK (proxy_vm); +} + +static GObject * +g_proxy_volume_monitor_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + GProxyVolumeMonitor *monitor; + GProxyVolumeMonitorClass *klass; + GObjectClass *parent_class; + DBusError dbus_error; + char *match_rule; + + G_LOCK (proxy_vm); + + klass = G_PROXY_VOLUME_MONITOR_CLASS (g_type_class_peek (type)); + object = g_hash_table_lookup (the_volume_monitors, (gpointer) type); + if (object != NULL) + { + g_object_ref (object); + goto out; + } + + /* Invoke parent constructor. */ + klass = G_PROXY_VOLUME_MONITOR_CLASS (g_type_class_peek (G_TYPE_PROXY_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_PROXY_VOLUME_MONITOR (object); + + dbus_error_init (&dbus_error); + monitor->session_bus = dbus_connection_ref (the_session_bus); + monitor->drives = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + monitor->volumes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + monitor->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + dbus_connection_add_filter (monitor->session_bus, filter_function, monitor, NULL); + match_rule = get_match_rule (monitor); + dbus_bus_add_match (monitor->session_bus, + match_rule, + &dbus_error); + if (dbus_error_is_set (&dbus_error)) { + /* not really a whole lot to do on failure than whine since + * GObject construction can't fail... + */ + g_warning ("cannot add match rule '%s': %s: %s", match_rule, dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + } + g_free (match_rule); + + seed_monitor (monitor); + + g_hash_table_insert (the_volume_monitors, (gpointer) type, object); + g_object_weak_ref (G_OBJECT (object), volume_monitor_went_away, (gpointer) type); + + out: + G_UNLOCK (proxy_vm); + return object; +} + +typedef struct { + const char *signal_name; + GObject *object; + GObject *other_object; +} SignalEmitIdleData; + +static gboolean +signal_emit_in_idle_do (SignalEmitIdleData *data) +{ + if (data->other_object != NULL) + { + g_signal_emit_by_name (data->object, data->signal_name, data->other_object); + g_object_unref (data->other_object); + } + else + { + g_signal_emit_by_name (data->object, data->signal_name); + } + g_object_unref (data->object); + g_free (data); + + return FALSE; +} + +static void +signal_emit_in_idle (gpointer object, const char *signal_name, gpointer other_object) +{ + SignalEmitIdleData *data; + + data = g_new0 (SignalEmitIdleData, 1); + data->signal_name = signal_name; + data->object = g_object_ref (G_OBJECT (object)); + data->other_object = other_object != NULL ? g_object_ref (G_OBJECT (other_object)) : NULL; + g_idle_add ((GSourceFunc) signal_emit_in_idle_do, data); +} + + + +static DBusHandlerResult +filter_function (DBusConnection *connection, DBusMessage *message, void *user_data) +{ + GProxyVolumeMonitor *monitor = G_PROXY_VOLUME_MONITOR (user_data); + DBusMessageIter iter; + const char *id; + const char *the_dbus_name; + const char *member; + GProxyDrive *drive; + GProxyVolume *volume; + GProxyMount *mount; + GProxyVolumeMonitorClass *klass; + + G_LOCK (proxy_vm); + + klass = G_PROXY_VOLUME_MONITOR_CLASS (G_OBJECT_GET_CLASS (monitor)); + + member = dbus_message_get_member (message); + + if (dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "DriveChanged") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "DriveConnected") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "DriveDisconnected") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "DriveEjectButton")) { + + dbus_message_iter_init (message, &iter); + dbus_message_iter_get_basic (&iter, &the_dbus_name); + dbus_message_iter_next (&iter); + dbus_message_iter_get_basic (&iter, &id); + dbus_message_iter_next (&iter); + + if (strcmp (the_dbus_name, klass->dbus_name) != 0) + goto not_for_us; + + if (strcmp (member, "DriveChanged") == 0) + { + drive = g_hash_table_lookup (monitor->drives, id); + if (drive != NULL) + { + g_proxy_drive_update (drive, &iter); + signal_emit_in_idle (drive, "changed", NULL); + signal_emit_in_idle (monitor, "drive-changed", drive); + } + } + else if (strcmp (member, "DriveConnected") == 0) + { + drive = g_hash_table_lookup (monitor->drives, id); + if (drive == NULL) + { + drive = g_proxy_drive_new (monitor); + g_proxy_drive_update (drive, &iter); + g_hash_table_insert (monitor->drives, g_strdup (g_proxy_drive_get_id (drive)), drive); + signal_emit_in_idle (monitor, "drive-connected", drive); + } + } + else if (strcmp (member, "DriveDisconnected") == 0) + { + drive = g_hash_table_lookup (monitor->drives, id); + if (drive != NULL) + { + g_object_ref (drive); + g_hash_table_remove (monitor->drives, id); + signal_emit_in_idle (drive, "disconnected", NULL); + signal_emit_in_idle (monitor, "drive-disconnected", drive); + g_object_unref (drive); + } + } + else if (strcmp (member, "DriveEjectButton") == 0) + { + drive = g_hash_table_lookup (monitor->drives, id); + if (drive != NULL) + { + signal_emit_in_idle (drive, "eject-button", NULL); + signal_emit_in_idle (monitor, "drive-eject-button", drive); + } + } + + } else if (dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "VolumeChanged") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "VolumeAdded") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "VolumeRemoved")) { + + dbus_message_iter_init (message, &iter); + dbus_message_iter_get_basic (&iter, &the_dbus_name); + dbus_message_iter_next (&iter); + dbus_message_iter_get_basic (&iter, &id); + dbus_message_iter_next (&iter); + + if (strcmp (the_dbus_name, klass->dbus_name) != 0) + goto not_for_us; + + if (strcmp (member, "VolumeChanged") == 0) + { + volume = g_hash_table_lookup (monitor->volumes, id); + if (volume != NULL) + { + g_proxy_volume_update (volume, &iter); + signal_emit_in_idle (volume, "changed", NULL); + signal_emit_in_idle (monitor, "volume-changed", volume); + } + } + else if (strcmp (member, "VolumeAdded") == 0) + { + volume = g_hash_table_lookup (monitor->volumes, id); + if (volume == NULL) + { + volume = g_proxy_volume_new (monitor); + g_proxy_volume_update (volume, &iter); + g_hash_table_insert (monitor->volumes, g_strdup (g_proxy_volume_get_id (volume)), volume); + signal_emit_in_idle (monitor, "volume-added", volume); + } + } + else if (strcmp (member, "VolumeRemoved") == 0) + { + volume = g_hash_table_lookup (monitor->volumes, id); + if (volume != NULL) + { + g_object_ref (volume); + g_hash_table_remove (monitor->volumes, id); + signal_emit_in_idle (volume, "removed", NULL); + signal_emit_in_idle (monitor, "volume-removed", volume); + g_object_unref (volume); + } + } + + } else if (dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "MountChanged") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "MountAdded") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "MountPreUnmount") || + dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "MountRemoved")) { + + dbus_message_iter_init (message, &iter); + dbus_message_iter_get_basic (&iter, &the_dbus_name); + dbus_message_iter_next (&iter); + dbus_message_iter_get_basic (&iter, &id); + dbus_message_iter_next (&iter); + + if (strcmp (the_dbus_name, klass->dbus_name) != 0) + goto not_for_us; + + if (strcmp (member, "MountChanged") == 0) + { + mount = g_hash_table_lookup (monitor->mounts, id); + if (mount != NULL) + { + g_proxy_mount_update (mount, &iter); + signal_emit_in_idle (mount, "changed", NULL); + signal_emit_in_idle (monitor, "mount-changed", mount); + } + } + else if (strcmp (member, "MountAdded") == 0) + { + mount = g_hash_table_lookup (monitor->mounts, id); + if (mount == NULL) + { + mount = g_proxy_mount_new (monitor); + g_proxy_mount_update (mount, &iter); + g_hash_table_insert (monitor->mounts, g_strdup (g_proxy_mount_get_id (mount)), mount); + signal_emit_in_idle (monitor, "mount-added", mount); + } + } + else if (strcmp (member, "MountPreUnmount") == 0) + { + mount = g_hash_table_lookup (monitor->mounts, id); + if (mount != NULL) + { + signal_emit_in_idle (mount, "pre-unmount", NULL); + signal_emit_in_idle (monitor, "mount-pre-unmount", mount); + } + } + else if (strcmp (member, "MountRemoved") == 0) + { + mount = g_hash_table_lookup (monitor->mounts, id); + if (mount != NULL) + { + g_object_ref (mount); + g_hash_table_remove (monitor->mounts, id); + signal_emit_in_idle (mount, "unmounted", NULL); + signal_emit_in_idle (monitor, "mount-removed", mount); + g_object_unref (mount); + } + } + + } + + not_for_us: + G_UNLOCK (proxy_vm); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +g_proxy_volume_monitor_init (GProxyVolumeMonitor *monitor) +{ + g_proxy_volume_monitor_setup_session_bus_connection (TRUE); +} + +static void +g_proxy_volume_monitor_class_finalize (GProxyVolumeMonitorClass *klass) +{ + g_free (klass->dbus_name); +} + +typedef struct { + char *dbus_name; + gboolean is_native; + int is_supported_nr; +} ProxyClassData; + +static ProxyClassData * +proxy_class_data_new (const char *dbus_name, gboolean is_native) +{ + ProxyClassData *data; + static int is_supported_nr = 0; + + data = g_new0 (ProxyClassData, 1); + data->dbus_name = g_strdup (dbus_name); + data->is_native = is_native; + data->is_supported_nr = is_supported_nr++; + + g_assert (is_supported_funcs[data->is_supported_nr] != NULL); + + return data; +} + +static void +g_proxy_volume_monitor_class_intern_init_pre (GProxyVolumeMonitorClass *klass, gconstpointer class_data) +{ + ProxyClassData *data = (ProxyClassData *) class_data; + klass->dbus_name = g_strdup (data->dbus_name); + klass->is_native = data->is_native; + klass->is_supported_nr = data->is_supported_nr; + g_proxy_volume_monitor_class_intern_init (klass); +} + +static gboolean +is_remote_monitor_supported (const char *dbus_name) +{ + DBusMessage *message; + DBusMessage *reply; + DBusError dbus_error; + dbus_bool_t is_supported; + + message = NULL; + reply = NULL; + is_supported = FALSE; + + message = dbus_message_new_method_call (dbus_name, + "/", + "org.gtk.Private.RemoteVolumeMonitor", + "IsSupported"); + if (message == NULL) + { + g_warning ("Cannot allocate memory for DBusMessage"); + goto fail; + } + dbus_error_init (&dbus_error); + reply = dbus_connection_send_with_reply_and_block (the_session_bus, + message, + -1, + &dbus_error); + if (dbus_error_is_set (&dbus_error)) + { + g_warning ("invoking IsSupported() failed for remote volume monitor with dbus name %s: %s: %s", + dbus_name, + dbus_error.name, + dbus_error.message); + dbus_error_free (&dbus_error); + goto fail; + } + + if (!dbus_message_get_args (reply, &dbus_error, + DBUS_TYPE_BOOLEAN, &is_supported, + DBUS_TYPE_INVALID)) + { + g_warning ("Error parsing args in reply for IsSupported(): %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto fail; + } + + if (!is_supported) + g_warning ("remote volume monitor with dbus name %s is not supported", dbus_name); + + fail: + if (message != NULL) + dbus_message_unref (message); + if (reply != NULL) + dbus_message_unref (reply); + return is_supported; +} + +static gboolean +is_supported (GProxyVolumeMonitorClass *klass) +{ + gboolean res; + + G_LOCK (proxy_vm); + res = g_proxy_volume_monitor_setup_session_bus_connection (FALSE); + G_UNLOCK (proxy_vm); + + if (res) + res = is_remote_monitor_supported (klass->dbus_name); + + return res; +} + +static GVolume * +adopt_orphan_mount (GMount *mount, GVolumeMonitor *monitor) +{ + GProxyVolumeMonitor *proxy_monitor = G_PROXY_VOLUME_MONITOR (monitor); + GFile *mount_root; + GProxyVolume *proxy_volume; + GVolume *ret; + GHashTableIter hash_iter; + + ret = NULL; + + G_LOCK (proxy_vm); + + mount_root = g_mount_get_root (mount); + + /* TODO: consider what happens if two volumes wants to adopt the same mount? + * + * e.g. imagine two GVolume objects with activation_roots + * + * ssh://server/dir1 + * ssh://server/dir2 + */ + + g_hash_table_iter_init (&hash_iter, proxy_monitor->volumes); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &proxy_volume)) + { + GFile *activation_root; + + activation_root = g_volume_get_activation_root (G_VOLUME (proxy_volume)); + if (activation_root != NULL) + { + if (g_file_has_prefix (activation_root, mount_root) || + g_file_equal (activation_root, mount_root)) + { + g_proxy_volume_adopt_foreign_mount (proxy_volume, mount); + ret = g_object_ref (proxy_volume); + g_object_unref (activation_root); + goto found; + } + g_object_unref (activation_root); + } + } + + found: + g_object_unref (mount_root); + + G_UNLOCK (proxy_vm); + return ret; +} + +static void +g_proxy_volume_monitor_class_init (GProxyVolumeMonitorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass); + GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass); + int i; + + gobject_class->constructor = g_proxy_volume_monitor_constructor; + gobject_class->finalize = g_proxy_volume_monitor_finalize; + + 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; + + i = klass->is_supported_nr; + is_supported_classes[i] = klass; + monitor_class->is_supported = is_supported_funcs[i]; + + native_class->get_mount_for_mount_path = get_mount_for_mount_path; +} + +/* Must be called with no locks held */ +static void +seed_monitor (GProxyVolumeMonitor *monitor) +{ + DBusMessage *message; + DBusMessage *reply; + DBusError dbus_error; + DBusMessageIter iter_reply; + DBusMessageIter iter_array; + + message = dbus_message_new_method_call (g_proxy_volume_monitor_get_dbus_name (monitor), + "/", + "org.gtk.Private.RemoteVolumeMonitor", + "List"); + if (message == NULL) + { + g_warning ("Cannot allocate memory for DBusMessage"); + goto fail; + } + dbus_error_init (&dbus_error); + reply = dbus_connection_send_with_reply_and_block (monitor->session_bus, + message, + -1, + &dbus_error); + dbus_message_unref (message); + if (dbus_error_is_set (&dbus_error)) + { + g_warning ("invoking List() failed for type %s: %s: %s", + G_OBJECT_TYPE_NAME (monitor), + dbus_error.name, + dbus_error.message); + dbus_error_free (&dbus_error); + goto fail; + } + + dbus_message_iter_init (reply, &iter_reply); + + /* TODO: verify signature */ + + /* drives */ + dbus_message_iter_recurse (&iter_reply, &iter_array); + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + GProxyDrive *drive; + const char *id; + drive = g_proxy_drive_new (monitor); + g_proxy_drive_update (drive, &iter_array); + id = g_proxy_drive_get_id (drive); + g_hash_table_insert (monitor->drives, g_strdup (id), drive); + dbus_message_iter_next (&iter_array); + } + dbus_message_iter_next (&iter_reply); + + /* volumes */ + dbus_message_iter_recurse (&iter_reply, &iter_array); + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + GProxyVolume *volume; + const char *id; + volume = g_proxy_volume_new (monitor); + g_proxy_volume_update (volume, &iter_array); + id = g_proxy_volume_get_id (volume); + g_hash_table_insert (monitor->volumes, g_strdup (id), volume); + dbus_message_iter_next (&iter_array); + } + dbus_message_iter_next (&iter_reply); + + /* mounts */ + dbus_message_iter_recurse (&iter_reply, &iter_array); + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + GProxyMount *mount; + const char *id; + mount = g_proxy_mount_new (monitor); + g_proxy_mount_update (mount, &iter_array); + id = g_proxy_mount_get_id (mount); + g_hash_table_insert (monitor->mounts, g_strdup (id), mount); + dbus_message_iter_next (&iter_array); + } + dbus_message_iter_next (&iter_reply); + + dbus_message_unref (reply); + + fail: + ; +} + +GProxyDrive * +g_proxy_volume_monitor_get_drive_for_id (GProxyVolumeMonitor *volume_monitor, + const char *id) +{ + GProxyDrive *drive; + + G_LOCK (proxy_vm); + drive = g_hash_table_lookup (volume_monitor->drives, id); + if (drive != NULL) + g_object_ref (drive); + G_UNLOCK (proxy_vm); + + return drive; +} + +GProxyVolume * +g_proxy_volume_monitor_get_volume_for_id (GProxyVolumeMonitor *volume_monitor, + const char *id) +{ + GProxyVolume *volume; + + G_LOCK (proxy_vm); + volume = g_hash_table_lookup (volume_monitor->volumes, id); + if (volume != NULL) + g_object_ref (volume); + G_UNLOCK (proxy_vm); + + return volume; +} + +GProxyMount * +g_proxy_volume_monitor_get_mount_for_id (GProxyVolumeMonitor *volume_monitor, + const char *id) +{ + GProxyMount *mount; + + G_LOCK (proxy_vm); + mount = g_hash_table_lookup (volume_monitor->mounts, id); + if (mount != NULL) + g_object_ref (mount); + G_UNLOCK (proxy_vm); + + return mount; +} + + +GHashTable * +_get_identifiers (DBusMessageIter *iter) +{ + GHashTable *hash_table; + DBusMessageIter iter_array; + + hash_table = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + dbus_message_iter_recurse (iter, &iter_array); + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + DBusMessageIter iter_dict_entry; + const char *key; + const char *value; + + dbus_message_iter_recurse (&iter_array, &iter_dict_entry); + dbus_message_iter_get_basic (&iter_dict_entry, &key); + dbus_message_iter_next (&iter_dict_entry); + dbus_message_iter_get_basic (&iter_dict_entry, &value); + + g_hash_table_insert (hash_table, g_strdup (key), g_strdup (value)); + + dbus_message_iter_next (&iter_array); + } + + return hash_table; +} + +static GIcon * +_g_icon_new_from_tokens (char **tokens, int num_tokens) +{ + GIcon *icon; + + icon = NULL; + if (strcmp (tokens[0], "GFileIcon") == 0) + { + GFile *file; + char *unescaped_uri; + + if (num_tokens != 2) + goto out; + + unescaped_uri = g_uri_unescape_string (tokens[1], NULL); + file = g_file_new_for_uri (unescaped_uri); + icon = g_file_icon_new (file); + g_object_unref (file); + g_free (unescaped_uri); + } + else if (strcmp (tokens[0], "GThemedIcon") == 0) + { + int n; + + for (n = 1; n < num_tokens; n++) + { + char *unescaped_name; + + unescaped_name = g_uri_unescape_string (tokens[n], NULL); + if (icon == NULL) + icon = g_themed_icon_new (unescaped_name); + else + g_themed_icon_append_name (G_THEMED_ICON (icon), unescaped_name); + g_free (unescaped_name); + } + } + else if (strcmp (tokens[0], "GEmblemedIcon") == 0) + { + int n, m, i; + GIcon *base, *e_icon; + GEmblem *emblem; + GList *emblems, *e; + GEmblemOrigin origin; + char **t = tokens; + + t++; + n = atoi (*t); + t++; + if (t - tokens >= num_tokens) + goto out; + base = _g_icon_new_from_tokens (t, n); + if (base == NULL) + goto out; + + t = t + n; + m = atoi (*t); + t++; + emblems = NULL; + for (i = 0; i < m; i++) + { + origin = atoi (*t); + t++; + n = atoi (*t); + t++; + if (t - tokens >= num_tokens) + goto cleanup; + e_icon = _g_icon_new_from_tokens (t, n); + t += n; + if (e_icon == NULL) + goto cleanup; + emblem = g_emblem_new_with_origin (e_icon, origin); + emblems = g_list_append (emblems, emblem); + } + icon = g_emblemed_icon_new (base, (GEmblem*)emblems->data); + for (e = emblems->next; e; e = e->next) + g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (icon), (GEmblem*)e->data); + + cleanup: + g_object_unref (base); + g_list_foreach (emblems, (GFunc)g_object_unref, NULL); + g_list_free (emblems); + } + + out: + return icon; +} + +GIcon * +_g_icon_new_from_serialized_data (const char *gicon_data) +{ + char **tokens; + GIcon *icon; + gint num_tokens; + + g_return_val_if_fail (gicon_data != NULL, NULL); + + icon = NULL; + + tokens = g_strsplit (gicon_data, " ", 0); + + if (g_strv_length (tokens) >= 3) + { + num_tokens = atoi (tokens[0]); + icon = _g_icon_new_from_tokens (tokens + 1, num_tokens); + } + + if (icon == NULL) + g_warning ("malformed GIcon data \"%s\"", gicon_data); + + g_strfreev (tokens); + return icon; +} + +DBusConnection * +g_proxy_volume_monitor_get_dbus_connection (GProxyVolumeMonitor *volume_monitor) +{ + return dbus_connection_ref (volume_monitor->session_bus); +} + +const char * +g_proxy_volume_monitor_get_dbus_name (GProxyVolumeMonitor *volume_monitor) +{ + GProxyVolumeMonitorClass *klass = G_PROXY_VOLUME_MONITOR_CLASS (G_OBJECT_GET_CLASS (volume_monitor)); + return klass->dbus_name; +} + +static void +register_volume_monitor (GTypeModule *type_module, + const char *type_name, + const char *dbus_name, + gboolean is_native, + int priority) +{ + GType type; + const GTypeInfo type_info = { + sizeof (GProxyVolumeMonitorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) g_proxy_volume_monitor_class_intern_init_pre, + (GClassFinalizeFunc) g_proxy_volume_monitor_class_finalize, + (gconstpointer) proxy_class_data_new (dbus_name, is_native), /* class_data (leaked!) */ + sizeof (GProxyVolumeMonitor), + 0, /* n_preallocs */ + (GInstanceInitFunc) g_proxy_volume_monitor_init, + NULL /* value_table */ + }; + + type = g_type_module_register_type (type_module, + G_TYPE_PROXY_VOLUME_MONITOR, + type_name, + &type_info, + 0 /* type_flags */); + + g_io_extension_point_implement (is_native ? G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME : + G_VOLUME_MONITOR_EXTENSION_POINT_NAME, + type, + type_name, + priority); +} + +/* Call with proxy_vm lock held */ +gboolean +g_proxy_volume_monitor_setup_session_bus_connection (gboolean need_integration) +{ + gboolean ret; + DBusError dbus_error; + + ret = FALSE; + + if (the_session_bus != NULL) + goto has_bus_already; + + /* This is so that system daemons can use gio + * without spawning private dbus instances. + * See bug 526454. + */ + if (g_getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL) + goto out; + + dbus_error_init (&dbus_error); + the_session_bus = dbus_bus_get_private (DBUS_BUS_SESSION, &dbus_error); + if (dbus_error_is_set (&dbus_error)) + { + g_warning ("cannot connect to the session bus: %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + the_volume_monitors = g_hash_table_new (g_direct_hash, g_direct_equal); + + has_bus_already: + + if (need_integration && !the_session_bus_is_integrated) + { + _g_dbus_connection_integrate_with_main (the_session_bus); + the_session_bus_is_integrated = TRUE; + } + + ret = TRUE; + + out: + return ret; +} + +void +g_proxy_volume_monitor_teardown_session_bus_connection (void) +{ + G_LOCK (proxy_vm); + if (the_session_bus != NULL) + { + if (the_session_bus_is_integrated) + _g_dbus_connection_remove_from_main (the_session_bus); + the_session_bus_is_integrated = FALSE; + dbus_connection_close (the_session_bus); + the_session_bus = NULL; + + g_hash_table_unref (the_volume_monitors); + the_volume_monitors = NULL; + } + G_UNLOCK (proxy_vm); +} + +void +g_proxy_volume_monitor_register (GIOModule *module) +{ + GDir *dir; + GError *error; + + /* first register the abstract base type... */ + g_proxy_volume_monitor_register_type (G_TYPE_MODULE (module)); + + /* ... then register instantiable types for each remote volume + * monitor - each remote volume monitor is defined in a key-value + * file in $(datadir)/gvfs/remote-volume-monitors that must have + * the suffix .monitor. Each file specifies + * + * - the name of the volume monitor + * - the name of the D-Bus service + * - whether the volume monitor is native + * - and if so the priority + */ + + error = NULL; + dir = g_dir_open (REMOTE_VOLUME_MONITORS_DIR, 0, &error); + if (dir == NULL) + { + g_warning ("cannot open directory " REMOTE_VOLUME_MONITORS_DIR ": %s", error->message); + g_error_free (error); + } + else + { + const char *name; + + while ((name = g_dir_read_name (dir)) != NULL) + { + GKeyFile *key_file; + char *type_name; + char *path; + char *dbus_name; + gboolean is_native; + int native_priority; + + type_name = NULL; + key_file = NULL; + dbus_name = NULL; + path = NULL; + + if (!g_str_has_suffix (name, ".monitor")) + goto cont; + + path = g_build_filename (REMOTE_VOLUME_MONITORS_DIR, name, NULL); + + key_file = g_key_file_new (); + error = NULL; + if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error)) + { + g_warning ("error loading key-value file %s: %s", path, error->message); + g_error_free (error); + goto cont; + } + + type_name = g_key_file_get_string (key_file, "RemoteVolumeMonitor", "Name", &error); + if (error != NULL) + { + g_warning ("error extracting Name key from %s: %s", path, error->message); + g_error_free (error); + goto cont; + } + + dbus_name = g_key_file_get_string (key_file, "RemoteVolumeMonitor", "DBusName", &error); + if (error != NULL) + { + g_warning ("error extracting DBusName key from %s: %s", path, error->message); + g_error_free (error); + goto cont; + } + + is_native = g_key_file_get_boolean (key_file, "RemoteVolumeMonitor", "IsNative", &error); + if (error != NULL) + { + g_warning ("error extracting IsNative key from %s: %s", path, error->message); + g_error_free (error); + goto cont; + } + + if (is_native) + { + native_priority = g_key_file_get_integer (key_file, "RemoteVolumeMonitor", "NativePriority", &error); + if (error != NULL) + { + g_warning ("error extracting NativePriority key from %s: %s", path, error->message); + g_error_free (error); + goto cont; + } + } + else + { + native_priority = 0; + } + + register_volume_monitor (G_TYPE_MODULE (module), + type_name, + dbus_name, + is_native, + native_priority); + + cont: + + g_free (type_name); + g_free (dbus_name); + g_free (path); + if (key_file != NULL) + g_key_file_free (key_file); + } + g_dir_close (dir); + } +} diff --git a/gnome-2-24/monitor/proxy/gproxyvolumemonitor.h b/gnome-2-24/monitor/proxy/gproxyvolumemonitor.h new file mode 100644 index 00000000..4768ba8f --- /dev/null +++ b/gnome-2-24/monitor/proxy/gproxyvolumemonitor.h @@ -0,0 +1,77 @@ +/* -*- 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 + */ + +#ifndef __G_PROXY_VOLUME_MONITOR_H__ +#define __G_PROXY_VOLUME_MONITOR_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define G_TYPE_PROXY_VOLUME_MONITOR (g_proxy_volume_monitor_get_type ()) +#define G_PROXY_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_PROXY_VOLUME_MONITOR, GProxyVolumeMonitor)) +#define G_PROXY_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_PROXY_VOLUME_MONITOR, GProxyVolumeMonitorClass)) +#define G_IS_PROXY_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_PROXY_VOLUME_MONITOR)) +#define G_IS_PROXY_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_PROXY_VOLUME_MONITOR)) + +typedef struct _GProxyVolumeMonitor GProxyVolumeMonitor; +typedef struct _GProxyVolumeMonitorClass GProxyVolumeMonitorClass; + +/* Forward definitions */ +typedef struct _GProxyDrive GProxyDrive; +typedef struct _GProxyVolume GProxyVolume; +typedef struct _GProxyMount GProxyMount; + +struct _GProxyVolumeMonitorClass { + GNativeVolumeMonitorClass parent_class; + char *dbus_name; + gboolean is_native; + int is_supported_nr; +}; + +GType g_proxy_volume_monitor_get_type (void) G_GNUC_CONST; + +void g_proxy_volume_monitor_register (GIOModule *module); +GProxyDrive *g_proxy_volume_monitor_get_drive_for_id (GProxyVolumeMonitor *volume_monitor, + const char *id); +GProxyVolume *g_proxy_volume_monitor_get_volume_for_id (GProxyVolumeMonitor *volume_monitor, + const char *id); +GProxyMount *g_proxy_volume_monitor_get_mount_for_id (GProxyVolumeMonitor *volume_monitor, + const char *id); +DBusConnection *g_proxy_volume_monitor_get_dbus_connection (GProxyVolumeMonitor *volume_monitor); +const char *g_proxy_volume_monitor_get_dbus_name (GProxyVolumeMonitor *volume_monitor); + +gboolean g_proxy_volume_monitor_setup_session_bus_connection (gboolean need_integration); +void g_proxy_volume_monitor_teardown_session_bus_connection (void); + + +GHashTable *_get_identifiers (DBusMessageIter *iter); + +GIcon *_g_icon_new_from_serialized_data (const char *gicon_data); + +G_END_DECLS + +#endif /* __G_PROXY_VOLUME_MONITOR_H__ */ diff --git a/gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.c b/gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.c new file mode 100644 index 00000000..3ee5bbf8 --- /dev/null +++ b/gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.c @@ -0,0 +1,1155 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* gvfs - extensions for gio + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gdbusutils.h" +#include "gvfsproxyvolumemonitordaemon.h" + +static GVolumeMonitor *monitor = NULL; +static DBusConnection *connection = NULL; +static GType the_volume_monitor_type; +static const char *the_dbus_name = NULL; + +static void monitor_try_create (void); + +static char * +_g_icon_serialize (GIcon *icon) +{ + char *ret; + + g_return_val_if_fail (icon != NULL, NULL); + g_return_val_if_fail (G_IS_ICON (icon), NULL); + + /* We encode icons as a series of whitespace-separated tokens. + * The first token is the type of the icon. To help decoding, + * the number of tokens is prepended as the first token (not + * included in the count). + */ + if (G_IS_FILE_ICON (icon)) + { + GFileIcon *file_icon = G_FILE_ICON (icon); + GFile *file; + char *uri; + char *escaped_uri; + + file = g_file_icon_get_file (file_icon); + uri = g_file_get_uri (file); + escaped_uri = g_uri_escape_string (uri, NULL, TRUE); + + ret = g_strdup_printf ("2 GFileIcon %s", escaped_uri); + + g_free (uri); + g_free (escaped_uri); + } + else if (G_IS_THEMED_ICON (icon)) + { + GThemedIcon *themed_icon = G_THEMED_ICON (icon); + char *escaped_name; + char **names; + GString *s; + + g_object_get (themed_icon, + "names", &names, + NULL); + + s = g_string_new (0); + g_string_append_printf (s, "%d GThemedIcon", g_strv_length (names) + 1); + + if (names != NULL) + { + int n; + for (n = 0; names[n] != NULL; n++) + { + escaped_name = g_uri_escape_string (names[n], NULL, TRUE); + g_string_append_c (s, ' '); + g_string_append (s, escaped_name); + g_free (escaped_name); + } + } + + ret = g_string_free (s, FALSE); + + g_strfreev (names); + } + else if (G_IS_EMBLEMED_ICON (icon)) + { + char *base, *s; + GList *emblems, *e; + int n; + GString *str; + + /* GEmblemedIcons are encoded as + * + * GEmblemedIcon [ ]* + */ + str = g_string_new (""); + base = _g_icon_serialize (g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon))); + emblems = g_emblemed_icon_get_emblems (G_EMBLEMED_ICON (icon)); + g_string_append_printf (str, "GEmblemedIcon %s %d", base, g_list_length (emblems)); + n = atoi (base) + 2; + g_free (base); + for (e = emblems; e; e = e->next) + { + s = _g_icon_serialize (g_emblem_get_icon (G_EMBLEM (e->data))); + g_string_append_printf (str, " %d %s", g_emblem_get_origin (G_EMBLEM (e->data)), s); + n += atoi (s) + 2; + g_free (s); + } + + s = g_string_free (str, FALSE); + ret = g_strdup_printf ("%d %s", n + 1, s); + g_free (s); + } + else + { + ret = NULL; + g_warning ("unknown icon type; please add support"); + } + + return ret; +} + +/* string id + * string name + * string gicon_data + * boolean can-eject + * boolean can-poll-for-media + * boolean has-media + * boolean is-media-removable + * array:string volume-ids + * dict:string->string identifiers + */ +#define DRIVE_STRUCT_TYPE "(sssbbbbasa{ss})" + +static void +append_drive (GDrive *drive, DBusMessageIter *iter_array) +{ + DBusMessageIter iter_struct; + DBusMessageIter iter_volume_array; + DBusMessageIter iter_identifiers; + char *id; + char *name; + GIcon *icon; + char *icon_data; + gboolean can_eject; + gboolean can_poll_for_media; + gboolean has_media; + gboolean is_media_removable; + GList *volumes, *l; + char **identifiers; + int n; + + dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct); + + id = g_strdup_printf ("%p", drive); + name = g_drive_get_name (drive); + icon = g_drive_get_icon (drive); + icon_data = _g_icon_serialize (icon); + can_eject = g_drive_can_eject (drive); + can_poll_for_media = g_drive_can_poll_for_media (drive); + has_media = g_drive_has_media (drive); + is_media_removable = g_drive_is_media_removable (drive); + volumes = g_drive_get_volumes (drive); + identifiers = g_drive_enumerate_identifiers (drive); + + if (name == NULL) + name = g_strdup (""); + + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &id); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &icon_data); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &can_eject); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &can_poll_for_media); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &has_media); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &is_media_removable); + + dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_volume_array); + for (l = volumes; l != NULL; l = l->next) + { + GVolume *volume = G_VOLUME (l->data); + char *volume_id; + volume_id = g_strdup_printf ("%p", volume); + dbus_message_iter_append_basic (&iter_volume_array, DBUS_TYPE_STRING, &volume_id); + g_free (volume_id); + } + dbus_message_iter_close_container (&iter_struct, &iter_volume_array); + + dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "{ss}", &iter_identifiers); + for (n = 0; identifiers[n] != NULL; n++) + { + DBusMessageIter iter_dict_entry; + char *id_value; + id_value = g_drive_get_identifier (drive, identifiers[n]); + dbus_message_iter_open_container (&iter_identifiers, + DBUS_TYPE_DICT_ENTRY, + NULL, + &iter_dict_entry); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &(identifiers[n])); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &id_value); + dbus_message_iter_close_container (&iter_identifiers, &iter_dict_entry); + g_free (id_value); + } + dbus_message_iter_close_container (&iter_struct, &iter_identifiers); + + g_strfreev (identifiers); + g_list_foreach (volumes, (GFunc) g_object_unref, NULL); + g_list_free (volumes); + g_free (icon_data); + g_object_unref (icon); + g_free (name); + g_free (id); + + dbus_message_iter_close_container (iter_array, &iter_struct); +} + +/* string id + * string name + * string gicon_data + * string uuid + * string activation_uri + * boolean can-mount + * boolean should-automount + * string drive-id + * string mount-id + * dict:string->string identifiers + */ +#define VOLUME_STRUCT_TYPE "(sssssbbssa{ss})" + +static void +append_volume (GVolume *volume, DBusMessageIter *iter_array) +{ + DBusMessageIter iter_struct; + DBusMessageIter iter_identifiers; + char *id; + char *name; + GIcon *icon; + char *icon_data; + char *uuid; + GFile *activation_root; + char *activation_uri; + gboolean can_mount; + gboolean should_automount; + GDrive *drive; + char *drive_id; + GMount *mount; + char *mount_id; + char **identifiers; + int n; + + dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct); + + id = g_strdup_printf ("%p", volume); + name = g_volume_get_name (volume); + icon = g_volume_get_icon (volume); + icon_data = _g_icon_serialize (icon); + uuid = g_volume_get_uuid (volume); + activation_root = g_volume_get_activation_root (volume); + if (activation_root == NULL) + activation_uri = g_strdup (""); + else + activation_uri = g_file_get_uri (activation_root); + can_mount = g_volume_can_mount (volume); + should_automount = g_volume_should_automount (volume); + drive = g_volume_get_drive (volume); + if (drive == NULL) + drive_id = g_strdup (""); + else + drive_id = g_strdup_printf ("%p", drive); + mount = g_volume_get_mount (volume); + if (mount == NULL) + mount_id = g_strdup (""); + else + mount_id = g_strdup_printf ("%p", mount); + identifiers = g_volume_enumerate_identifiers (volume); + + if (name == NULL) + name = g_strdup (""); + if (uuid == NULL) + uuid = g_strdup (""); + + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &id); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &icon_data); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &uuid); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &activation_uri); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &can_mount); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &should_automount); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &drive_id); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &mount_id); + + dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "{ss}", &iter_identifiers); + for (n = 0; identifiers[n] != NULL; n++) + { + DBusMessageIter iter_dict_entry; + char *id_value; + id_value = g_volume_get_identifier (volume, identifiers[n]); + dbus_message_iter_open_container (&iter_identifiers, + DBUS_TYPE_DICT_ENTRY, + NULL, + &iter_dict_entry); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &(identifiers[n])); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &id_value); + dbus_message_iter_close_container (&iter_identifiers, &iter_dict_entry); + g_free (id_value); + } + dbus_message_iter_close_container (&iter_struct, &iter_identifiers); + + g_strfreev (identifiers); + g_free (mount_id); + if (mount != NULL) + g_object_unref (mount); + g_free (drive_id); + if (drive != NULL) + g_object_unref (drive); + g_free (uuid); + if (activation_root != NULL) + g_object_unref (activation_root); + g_free (activation_uri); + g_free (icon_data); + g_object_unref (icon); + g_free (name); + g_free (id); + + dbus_message_iter_close_container (iter_array, &iter_struct); +} + +/* string id + * string name + * string gicon_data + * string uuid + * string root_uri + * boolean can-unmount + * string volume-id + * array:string x-content-types + */ +#define MOUNT_STRUCT_TYPE "(sssssbsas)" + +static void +append_mount (GMount *mount, DBusMessageIter *iter_array) +{ + DBusMessageIter iter_struct; + DBusMessageIter iter_x_content_types_array; + char *id; + char *name; + GIcon *icon; + char *icon_data; + char *uuid; + GFile *root; + char *root_uri; + gboolean can_unmount; + GVolume *volume; + char *volume_id; + char **x_content_types; + int n; + + dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct); + + id = g_strdup_printf ("%p", mount); + name = g_mount_get_name (mount); + icon = g_mount_get_icon (mount); + icon_data = _g_icon_serialize (icon); + uuid = g_mount_get_uuid (mount); + root = g_mount_get_root (mount); + root_uri = g_file_get_uri (root); + can_unmount = g_mount_can_unmount (mount); + volume = g_mount_get_volume (mount); + if (volume == NULL) + volume_id = g_strdup (""); + else + volume_id = g_strdup_printf ("%p", volume); + + if (name == NULL) + name = g_strdup (""); + if (uuid == NULL) + uuid = g_strdup (""); + + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &id); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &icon_data); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &uuid); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &root_uri); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &can_unmount); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &volume_id); + + dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_x_content_types_array); + x_content_types = (char **) g_object_get_data (G_OBJECT (mount), "x-content-types"); + if (x_content_types != NULL) + { + for (n = 0; x_content_types[n] != NULL; n++) + dbus_message_iter_append_basic (&iter_x_content_types_array, DBUS_TYPE_STRING, &(x_content_types[n])); + } + dbus_message_iter_close_container (&iter_struct, &iter_x_content_types_array); + + g_free (volume_id); + if (volume != NULL) + g_object_unref (volume); + g_free (root_uri); + g_object_unref (root); + g_free (uuid); + g_free (icon_data); + g_object_unref (icon); + g_free (name); + g_free (id); + + dbus_message_iter_close_container (iter_array, &iter_struct); +} + +static DBusHandlerResult +handle_list (DBusConnection *connection, DBusMessage *message) +{ + GList *drives; + GList *volumes; + GList *mounts; + DBusMessageIter iter; + DBusMessageIter iter_array; + DBusMessage *reply; + + drives = g_volume_monitor_get_connected_drives (monitor); + volumes = g_volume_monitor_get_volumes (monitor); + mounts = g_volume_monitor_get_mounts (monitor); + + reply = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply, &iter); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DRIVE_STRUCT_TYPE, &iter_array); + g_list_foreach (drives, (GFunc) append_drive, &iter_array); + dbus_message_iter_close_container (&iter, &iter_array); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, VOLUME_STRUCT_TYPE, &iter_array); + g_list_foreach (volumes, (GFunc) append_volume, &iter_array); + dbus_message_iter_close_container (&iter, &iter_array); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, MOUNT_STRUCT_TYPE, &iter_array); + g_list_foreach (mounts, (GFunc) append_mount, &iter_array); + dbus_message_iter_close_container (&iter, &iter_array); + + g_list_foreach (drives, (GFunc) g_object_unref, NULL); + g_list_free (drives); + g_list_foreach (volumes, (GFunc) g_object_unref, NULL); + g_list_free (volumes); + g_list_foreach (mounts, (GFunc) g_object_unref, NULL); + g_list_free (mounts); + + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +mount_unmount_cb (GMount *mount, GAsyncResult *result, DBusMessage *message) +{ + GError *error; + DBusMessage *reply; + + error = NULL; + if (!g_mount_unmount_finish (mount, result, &error)) + { + reply = _dbus_message_new_from_gerror (message, error); + g_error_free (error); + } + else + { + reply = dbus_message_new_method_return (message); + } + + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (message); + dbus_message_unref (reply); +} + +static DBusHandlerResult +handle_mount_unmount (DBusConnection *connection, DBusMessage *message) +{ + const char *id; + dbus_uint32_t unmount_flags; + DBusError dbus_error; + GList *mounts, *l; + GMount *mount; + DBusHandlerResult ret; + + mounts = NULL; + unmount_flags = 0; + ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_error_init (&dbus_error); + if (!dbus_message_get_args (message, &dbus_error, + DBUS_TYPE_STRING, &id, + DBUS_TYPE_UINT32 &unmount_flags, + DBUS_TYPE_INVALID)) + { + g_warning ("Error parsing args for MountUnmount(): %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + ret = DBUS_HANDLER_RESULT_HANDLED; + + mount = NULL; + mounts = g_volume_monitor_get_mounts (monitor); + for (l = mounts; l != NULL; l = l->next) + { + char *mount_id; + + mount = G_MOUNT (l->data); + mount_id = g_strdup_printf ("%p", mount); + if (strcmp (mount_id, id) == 0) + break; + + g_free (mount_id); + } + if (l == NULL) + mount = NULL; + + if (mount == NULL) + { + DBusMessage *reply; + reply = dbus_message_new_error (message, + "org.gtk.Private.RemoteVolumeMonitor.NotFound", + "The given mount was not found"); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + goto out; + } + + g_mount_unmount (mount, + unmount_flags, + NULL, + (GAsyncReadyCallback) mount_unmount_cb, + dbus_message_ref (message)); + + out: + if (mounts != NULL) + { + g_list_foreach (mounts, (GFunc) g_object_unref, NULL); + g_list_free (mounts); + } + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +volume_mount_cb (GVolume *volume, GAsyncResult *result, DBusMessage *message) +{ + GError *error; + DBusMessage *reply; + + error = NULL; + if (!g_volume_mount_finish (volume, result, &error)) + { + reply = _dbus_message_new_from_gerror (message, error); + g_error_free (error); + } + else + { + reply = dbus_message_new_method_return (message); + } + + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (message); + dbus_message_unref (reply); +} + +static DBusHandlerResult +handle_volume_mount (DBusConnection *connection, DBusMessage *message) +{ + const char *id; + dbus_uint32_t mount_flags; + dbus_bool_t use_mount_operation; + DBusError dbus_error; + GList *volumes, *l; + GVolume *volume; + DBusHandlerResult ret; + GMountOperation *mount_operation; + + volume = NULL; + ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_error_init (&dbus_error); + if (!dbus_message_get_args (message, &dbus_error, + DBUS_TYPE_STRING, &id, + DBUS_TYPE_UINT32, &mount_flags, + DBUS_TYPE_BOOLEAN, &use_mount_operation, + DBUS_TYPE_INVALID)) + { + g_warning ("Error parsing args for VolumeMount(): %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + ret = DBUS_HANDLER_RESULT_HANDLED; + + volume = NULL; + volumes = g_volume_monitor_get_volumes (monitor); + for (l = volumes; l != NULL; l = l->next) + { + char *volume_id; + + volume = G_VOLUME (l->data); + volume_id = g_strdup_printf ("%p", volume); + if (strcmp (volume_id, id) == 0) + break; + + g_free (volume_id); + } + if (l == NULL) + volume = NULL; + + if (volume == NULL) + { + DBusMessage *reply; + reply = dbus_message_new_error (message, + "org.gtk.Private.RemoteVolumeMonitor.NotFound", + "The given volume was not found"); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + goto out; + } + + mount_operation = NULL; + if (use_mount_operation) + mount_operation = g_mount_operation_new (); + + g_volume_mount (volume, + mount_flags, + mount_operation, + NULL, + (GAsyncReadyCallback) volume_mount_cb, + dbus_message_ref (message)); + + if (mount_operation != NULL) + g_object_unref (mount_operation); + + out: + if (volumes != NULL) + { + g_list_foreach (volumes, (GFunc) g_object_unref, NULL); + g_list_free (volumes); + } + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +drive_eject_cb (GDrive *drive, GAsyncResult *result, DBusMessage *message) +{ + GError *error; + DBusMessage *reply; + + error = NULL; + if (!g_drive_eject_finish (drive, result, &error)) + { + reply = _dbus_message_new_from_gerror (message, error); + g_error_free (error); + } + else + { + reply = dbus_message_new_method_return (message); + } + + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (message); + dbus_message_unref (reply); +} + +static DBusHandlerResult +handle_drive_eject (DBusConnection *connection, DBusMessage *message) +{ + const char *id; + dbus_uint32_t unmount_flags; + DBusError dbus_error; + GList *drives, *l; + GDrive *drive; + DBusHandlerResult ret; + + drive = NULL; + unmount_flags = 0; + ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_error_init (&dbus_error); + if (!dbus_message_get_args (message, &dbus_error, + DBUS_TYPE_STRING, &id, + DBUS_TYPE_UINT32 &unmount_flags, + DBUS_TYPE_INVALID)) + { + g_warning ("Error parsing args for DriveEject(): %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + ret = DBUS_HANDLER_RESULT_HANDLED; + + drive = NULL; + drives = g_volume_monitor_get_connected_drives (monitor); + for (l = drives; l != NULL; l = l->next) + { + char *drive_id; + + drive = G_DRIVE (l->data); + drive_id = g_strdup_printf ("%p", drive); + if (strcmp (drive_id, id) == 0) + break; + + g_free (drive_id); + } + if (l == NULL) + drive = NULL; + + if (drive == NULL) + { + DBusMessage *reply; + reply = dbus_message_new_error (message, + "org.gtk.Private.RemoteVolumeMonitor.NotFound", + "The given drive was not found"); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + goto out; + } + + g_drive_eject (drive, + unmount_flags, + NULL, + (GAsyncReadyCallback) drive_eject_cb, + dbus_message_ref (message)); + + out: + if (drives != NULL) + { + g_list_foreach (drives, (GFunc) g_object_unref, NULL); + g_list_free (drives); + } + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +drive_poll_for_media_cb (GDrive *drive, GAsyncResult *result, DBusMessage *message) +{ + GError *error; + DBusMessage *reply; + + error = NULL; + if (!g_drive_poll_for_media_finish (drive, result, &error)) + { + reply = _dbus_message_new_from_gerror (message, error); + g_error_free (error); + } + else + { + reply = dbus_message_new_method_return (message); + } + + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (message); + dbus_message_unref (reply); +} + +static DBusHandlerResult +handle_drive_poll_for_media (DBusConnection *connection, DBusMessage *message) +{ + const char *id; + DBusError dbus_error; + GList *drives, *l; + GDrive *drive; + DBusHandlerResult ret; + + drive = NULL; + ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_error_init (&dbus_error); + if (!dbus_message_get_args (message, &dbus_error, + DBUS_TYPE_STRING, &id, + DBUS_TYPE_INVALID)) + { + g_warning ("Error parsing args for DrivePollForMedia(): %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + ret = DBUS_HANDLER_RESULT_HANDLED; + + drive = NULL; + drives = g_volume_monitor_get_connected_drives (monitor); + for (l = drives; l != NULL; l = l->next) + { + char *drive_id; + + drive = G_DRIVE (l->data); + drive_id = g_strdup_printf ("%p", drive); + if (strcmp (drive_id, id) == 0) + break; + + g_free (drive_id); + } + if (l == NULL) + drive = NULL; + + if (drive == NULL) + { + DBusMessage *reply; + reply = dbus_message_new_error (message, + "org.gtk.Private.RemoteVolumeMonitor.NotFound", + "The given drive was not found"); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + goto out; + } + + g_drive_poll_for_media (drive, + NULL, + (GAsyncReadyCallback) drive_poll_for_media_cb, + dbus_message_ref (message)); + + out: + if (drives != NULL) + { + g_list_foreach (drives, (GFunc) g_object_unref, NULL); + g_list_free (drives); + } + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static DBusHandlerResult +handle_is_supported (DBusConnection *connection, DBusMessage *message) +{ + dbus_bool_t is_supported; + DBusMessage *reply; + DBusMessageIter iter; + + /* if monitor wasn't created on startup; try again */ + if (monitor == NULL) + monitor_try_create (); + + is_supported = (monitor != NULL); + + reply = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &is_supported); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static DBusHandlerResult +filter_function (DBusConnection *connection, DBusMessage *message, void *user_data) +{ + DBusHandlerResult ret; + + ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "IsSupported") && + strcmp (dbus_message_get_path (message), "/") == 0) + { + ret = handle_is_supported (connection, message); + } + else + { + if (monitor != NULL) + { + if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "List") && + strcmp (dbus_message_get_path (message), "/") == 0) + ret = handle_list (connection, message); + + else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "MountUnmount") && + strcmp (dbus_message_get_path (message), "/") == 0) + ret = handle_mount_unmount (connection, message); + + else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "VolumeMount") && + strcmp (dbus_message_get_path (message), "/") == 0) + ret = handle_volume_mount (connection, message); + + else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "DriveEject") && + strcmp (dbus_message_get_path (message), "/") == 0) + ret = handle_drive_eject (connection, message); + + else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "DrivePollForMedia") && + strcmp (dbus_message_get_path (message), "/") == 0) + ret = handle_drive_poll_for_media (connection, message); + } + } + + return ret; +} + +typedef void (*AppendFunc) (void *object, DBusMessageIter *iter); + +static void +emit_signal (DBusConnection *connection, const char *signal_name, void *object, AppendFunc func) +{ + char *id; + DBusMessage *message; + DBusMessageIter iter; + + id = g_strdup_printf ("%p", object); + + message = dbus_message_new_signal ("/", "org.gtk.Private.RemoteVolumeMonitor", signal_name); + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &the_dbus_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &id); + + func (object, &iter); + + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); + + + g_free (id); +} + +static void +drive_changed (GVolumeMonitor *monitor, GDrive *drive, DBusConnection *connection) +{ + emit_signal (connection, "DriveChanged", drive, (AppendFunc) append_drive); +} + +static void +drive_connected (GVolumeMonitor *monitor, GDrive *drive, DBusConnection *connection) +{ + emit_signal (connection, "DriveConnected", drive, (AppendFunc) append_drive); +} + +static void +drive_disconnected (GVolumeMonitor *monitor, GDrive *drive, DBusConnection *connection) +{ + emit_signal (connection, "DriveDisconnected", drive, (AppendFunc) append_drive); +} + +static void +drive_eject_button (GVolumeMonitor *monitor, GDrive *drive, DBusConnection *connection) +{ + g_warning ("drive eject button!"); + emit_signal (connection, "DriveEjectButton", drive, (AppendFunc) append_drive); +} + +static void +volume_changed (GVolumeMonitor *monitor, GVolume *volume, DBusConnection *connection) +{ + emit_signal (connection, "VolumeChanged", volume, (AppendFunc) append_volume); +} + +static void +volume_added (GVolumeMonitor *monitor, GVolume *volume, DBusConnection *connection) +{ + emit_signal (connection, "VolumeAdded", volume, (AppendFunc) append_volume); +} + +static void +volume_removed (GVolumeMonitor *monitor, GVolume *volume, DBusConnection *connection) +{ + emit_signal (connection, "VolumeRemoved", volume, (AppendFunc) append_volume); +} + +static void +mount_changed (GVolumeMonitor *monitor, GMount *mount, DBusConnection *connection) +{ + emit_signal (connection, "MountChanged", mount, (AppendFunc) append_mount); +} + +static void +mount_sniff_x_content_type (GMount *mount) +{ + char **x_content_types; + x_content_types = g_mount_guess_content_type_sync (mount, TRUE, NULL, NULL); + g_object_set_data_full (G_OBJECT (mount), "x-content-types", x_content_types, (GDestroyNotify) g_strfreev); +} + +static void +mount_added (GVolumeMonitor *monitor, GMount *mount, DBusConnection *connection) +{ + mount_sniff_x_content_type (mount); + emit_signal (connection, "MountAdded", mount, (AppendFunc) append_mount); +} + +static void +mount_pre_unmount (GVolumeMonitor *monitor, GMount *mount, DBusConnection *connection) +{ + emit_signal (connection, "MountPreUnmount", mount, (AppendFunc) append_mount); +} + +static void +mount_removed (GVolumeMonitor *monitor, GMount *mount, DBusConnection *connection) +{ + emit_signal (connection, "MountRemoved", mount, (AppendFunc) append_mount); +} + +void +g_vfs_proxy_volume_monitor_daemon_init (void) +{ + /* avoid loading the gio proxy module which will spawn ourselves + * + * see remote-volume-monitor-module.c + */ + g_setenv ("GVFS_REMOTE_VOLUME_MONITOR_IGNORE", "1", TRUE); + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, GVFS_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + dbus_threads_init_default (); + g_thread_init (NULL); + g_type_init (); +} + + +static void +monitor_try_create (void) +{ + GVolumeMonitorClass *klass; + GList *mounts; + GList *l; + + monitor = NULL; + klass = G_VOLUME_MONITOR_CLASS (g_type_class_ref (the_volume_monitor_type)); + if (klass == NULL) + { + g_warning ("Can't get class for type"); + goto fail; + } + + if (klass->is_supported != NULL) + { + if (! (klass->is_supported ())) + { + g_warning ("monitor says it's not supported"); + goto fail; + } + } + + monitor = G_VOLUME_MONITOR (g_object_new (the_volume_monitor_type, NULL)); + if (monitor == NULL) + { + g_warning ("Cannot instantiate volume monitor"); + goto fail; + } + + mounts = g_volume_monitor_get_mounts (monitor); + for (l = mounts; l != NULL; l = l->next) + mount_sniff_x_content_type (G_MOUNT (l->data)); + g_list_foreach (mounts, (GFunc) g_object_unref, NULL); + g_list_free (mounts); + + fail: + if (klass != NULL) + g_type_class_unref (klass); +} + +int +g_vfs_proxy_volume_monitor_daemon_main (int argc, + char *argv[], + const char *dbus_name, + GType volume_monitor_type) +{ + int rc; + int ret; + GMainLoop *loop; + DBusError dbus_error; + + ret = 1; + + loop = g_main_loop_new (NULL, FALSE); + + /* need to start up regardless of whether we can instantiate a + * volume monitor; this is because the proxy will need to be able to + * call IsSupported() on our D-Bus interface. + */ + + the_volume_monitor_type = volume_monitor_type; + the_dbus_name = dbus_name; + + /* try and create the monitor */ + monitor_try_create (); + + dbus_error_init (&dbus_error); + connection = dbus_bus_get (DBUS_BUS_SESSION, &dbus_error); + if (dbus_error_is_set (&dbus_error)) + { + g_warning ("Cannot connect to session bus: %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + _g_dbus_connection_integrate_with_main (connection); + + rc = dbus_bus_request_name (connection, dbus_name, 0, &dbus_error); + if (dbus_error_is_set (&dbus_error)) + { + g_warning ("dbus_bus_request_name failed: %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + g_warning ("Cannot become primary owner"); + goto out; + } + + if (!dbus_connection_add_filter (connection, filter_function, NULL, NULL)) + { + g_warning ("Cannot add filter function"); + goto out; + } + + if (monitor != NULL) + { + g_signal_connect (monitor, "drive-changed", (GCallback) drive_changed, connection); + g_signal_connect (monitor, "drive-connected", (GCallback) drive_connected, connection); + g_signal_connect (monitor, "drive-disconnected", (GCallback) drive_disconnected, connection); + g_signal_connect (monitor, "drive-eject-button", (GCallback) drive_eject_button, connection); + + g_signal_connect (monitor, "volume-changed", (GCallback) volume_changed, connection); + g_signal_connect (monitor, "volume-added", (GCallback) volume_added, connection); + g_signal_connect (monitor, "volume-removed", (GCallback) volume_removed, connection); + + g_signal_connect (monitor, "mount-changed", (GCallback) mount_changed, connection); + g_signal_connect (monitor, "mount-added", (GCallback) mount_added, connection); + g_signal_connect (monitor, "mount-pre-unmount", (GCallback) mount_pre_unmount, connection); + g_signal_connect (monitor, "mount-removed", (GCallback) mount_removed, connection); + } + + g_main_loop_run (loop); + g_main_loop_unref (loop); + + ret = 0; + +out: + return ret; +} diff --git a/gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.h b/gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.h new file mode 100644 index 00000000..d6c767db --- /dev/null +++ b/gnome-2-24/monitor/proxy/gvfsproxyvolumemonitordaemon.h @@ -0,0 +1,35 @@ +/* -*- 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 + */ + +#ifndef __G_VFS_PROXY_VOLUME_MONITOR_DAEMON_H__ +#define __G_VFS_PROXY_VOLUME_MONITOR_DAEMON_H__ + +#include + +void g_vfs_proxy_volume_monitor_daemon_init (void); +int g_vfs_proxy_volume_monitor_daemon_main (int argc, + char *argv[], + const char *dbus_name, + GType volume_monitor_type); + +#endif diff --git a/gnome-2-24/monitor/proxy/remote-volume-monitor-module.c b/gnome-2-24/monitor/proxy/remote-volume-monitor-module.c new file mode 100644 index 00000000..90945141 --- /dev/null +++ b/gnome-2-24/monitor/proxy/remote-volume-monitor-module.c @@ -0,0 +1,64 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* gvfs - extensions for gio + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include + +#include +#include +#include +#include + +#include "gproxyvolumemonitor.h" +#include "gproxyvolume.h" +#include "gproxymount.h" +#include "gproxydrive.h" + +void +g_io_module_load (GIOModule *module) +{ + /* see gvfsproxyvolumemonitor.c:g_vfs_proxy_volume_monitor_daemon_init() */ + if (g_getenv ("GVFS_REMOTE_VOLUME_MONITOR_IGNORE") != NULL) + goto out; + + bindtextdomain (GETTEXT_PACKAGE, GVFS_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + g_proxy_drive_register (module); + g_proxy_mount_register (module); + g_proxy_volume_register (module); + g_proxy_volume_monitor_register (module); +out: + ; + } + +void +g_io_module_unload (GIOModule *module) +{ + if (g_getenv ("GVFS_REMOTE_VOLUME_MONITOR_IGNORE") != NULL) + goto out; + + g_proxy_volume_monitor_teardown_session_bus_connection (); + +out: + ; +} -- cgit v1.2.1