gvfs r2253 - in trunk: . monitor/proxy
- From: davidz svn gnome org
- To: svn-commits-list gnome org
- Subject: gvfs r2253 - in trunk: . monitor/proxy
- Date: Thu, 26 Feb 2009 18:17:52 +0000 (UTC)
Author: davidz
Date: Thu Feb 26 18:17:52 2009
New Revision: 2253
URL: http://svn.gnome.org/viewvc/gvfs?rev=2253&view=rev
Log:
2009-02-26 David Zeuthen <davidz redhat com>
Lots of proxy monitor fixes.
Reviewed by: Alexander Larsson <alexl redhat com>
o add support for proxying GMountOperation to the remote volume
monitor process.
o add support for proxying GCancellable to the remote volume
monitor process.
o make each volume monitor process track callers and cancels
operations initiated by callers that disconnects from the bus
o makes the client side proxy monitor track the remote monitor. If
the monitor process disconnects, then all drives/volumes/mounts
are removed. If the monitor process reconnects, we reseed the
internal monitor and add drives/volumes/mounts.
o Each monitor process now uses ALLOW_REPLACEMENT when claiming a
name and also kills itself on NameLost (e.g. if it is
replaced). Coupled with the above disconnection/reconnection logic
it this makes it a lot more tolerable to hack on a remote volume
monitor. Simply just compile it, start it and the
existing (system-wide) copy will kill itself. And all the
clients (Nautilus, panel, drive applet, gvfsd-computer, etc.) will
reconnect and do the right thing.
o make the get_mount_for_mount_path() method on the class
GNativeVolumeMonitor actually work. It turns out that at least
gvfs-mount -u needs that.
o use /org/gtk/Private/RemoteVolumeMonitor instead of / as the
object name. Cf. the version D-Bus debacle on Lennart Poettering's
blog.
o make the proxy monitor client module resident
o For shadow mounts, redirect can_eject() and eject() to the
volume for the shadow mount. Without this patch eject on
e.g. cdda:// volumes won't work since cdda:// volumes are
GDaedmonMount and these don't implement eject.
* monitor/proxy/*.[ch]: See above.
Modified:
trunk/ChangeLog
trunk/monitor/proxy/gproxydrive.c
trunk/monitor/proxy/gproxymount.c
trunk/monitor/proxy/gproxyshadowmount.c
trunk/monitor/proxy/gproxyvolume.c
trunk/monitor/proxy/gproxyvolume.h
trunk/monitor/proxy/gproxyvolumemonitor.c
trunk/monitor/proxy/gproxyvolumemonitor.h
trunk/monitor/proxy/gvfsproxyvolumemonitordaemon.c
trunk/monitor/proxy/remote-volume-monitor-module.c
Modified: trunk/monitor/proxy/gproxydrive.c
==============================================================================
--- trunk/monitor/proxy/gproxydrive.c (original)
+++ trunk/monitor/proxy/gproxydrive.c Thu Feb 26 18:17:52 2009
@@ -128,10 +128,11 @@
* boolean can-poll-for-media
* boolean has-media
* boolean is-media-removable
+ * boolean is-media-check-automatic
* array:string volume-ids
* dict:string->string identifiers
*/
-#define DRIVE_STRUCT_TYPE "(sssbbbasa{ss})"
+#define DRIVE_STRUCT_TYPE "(sssbbbbasa{ss})"
void
g_proxy_drive_update (GProxyDrive *drive,
@@ -146,6 +147,7 @@
dbus_bool_t can_poll_for_media;
dbus_bool_t has_media;
dbus_bool_t is_media_removable;
+ dbus_bool_t is_media_check_automatic;
GPtrArray *volume_ids;
GHashTable *identifiers;
@@ -164,6 +166,8 @@
dbus_message_iter_next (&iter_struct);
dbus_message_iter_get_basic (&iter_struct, &is_media_removable);
dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &is_media_check_automatic);
+ dbus_message_iter_next (&iter_struct);
volume_ids = g_ptr_array_new ();
dbus_message_iter_recurse (&iter_struct, &iter_volume_ids_iter);
@@ -210,6 +214,7 @@
drive->can_poll_for_media = can_poll_for_media;
drive->has_media = has_media;
drive->is_media_removable = is_media_removable;
+ drive->is_media_check_automatic = is_media_check_automatic;
drive->identifiers = identifiers != NULL ? g_hash_table_ref (identifiers) : NULL;
drive->volume_ids = g_strdupv ((char **) volume_ids->pdata);
@@ -397,32 +402,100 @@
}
typedef struct {
- GObject *object;
+ GProxyDrive *drive;
GAsyncReadyCallback callback;
gpointer user_data;
+
+ gchar *cancellation_id;
GCancellable *cancellable;
+ gulong cancelled_handler_id;
} DBusOp;
static void
+cancel_operation_reply_cb (DBusMessage *reply,
+ GError *error,
+ gpointer user_data)
+{
+ if (error != NULL)
+ {
+ g_warning ("Error from CancelOperation(): %s", error->message);
+ }
+}
+
+static void
+operation_cancelled (GCancellable *cancellable,
+ gpointer user_data)
+{
+ DBusOp *data = user_data;
+ GSimpleAsyncResult *simple;
+ DBusConnection *connection;
+ DBusMessage *message;
+ const char *name;
+
+ G_LOCK (proxy_drive);
+
+ simple = g_simple_async_result_new_error (G_OBJECT (data->drive),
+ data->callback,
+ data->user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+
+ /* Now tell the remote volume monitor that the op has been cancelled */
+ connection = g_proxy_volume_monitor_get_dbus_connection (data->drive->volume_monitor);
+ name = g_proxy_volume_monitor_get_dbus_name (data->drive->volume_monitor);
+ message = dbus_message_new_method_call (name,
+ "/org/gtk/Private/RemoteVolumeMonitor",
+ "org.gtk.Private.RemoteVolumeMonitor",
+ "CancelOperation");
+ dbus_message_append_args (message,
+ DBUS_TYPE_STRING,
+ &(data->cancellation_id),
+ DBUS_TYPE_INVALID);
+
+ G_UNLOCK (proxy_drive);
+
+ _g_dbus_connection_call_async (connection,
+ message,
+ -1,
+ (GAsyncDBusCallback) cancel_operation_reply_cb,
+ NULL);
+ dbus_message_unref (message);
+ dbus_connection_unref (connection);
+}
+
+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);
+ if (data->cancelled_handler_id > 0)
+ g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id);
+
+ if (!g_cancellable_is_cancelled (data->cancellable))
+ {
+ GSimpleAsyncResult *simple;
+
+ if (error != NULL)
+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->drive),
+ data->callback,
+ data->user_data,
+ error);
+ else
+ simple = g_simple_async_result_new (G_OBJECT (data->drive),
+ data->callback,
+ data->user_data,
+ NULL);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ }
- g_object_unref (data->object);
+ g_object_unref (data->drive);
+ g_free (data->cancellation_id);
+ if (data->cancellable != NULL)
+ g_object_unref (data->cancellable);
g_free (data);
}
@@ -442,22 +515,52 @@
G_LOCK (proxy_drive);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ GSimpleAsyncResult *simple;
+ simple = g_simple_async_result_new_error (G_OBJECT (drive),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ G_UNLOCK (proxy_drive);
+ goto out;
+ }
+
data = g_new0 (DBusOp, 1);
- data->object = g_object_ref (drive);
+ data->drive = g_object_ref (drive);
data->callback = callback;
data->user_data = user_data;
- data->cancellable = cancellable;
+
+ if (cancellable != NULL)
+ {
+ data->cancellation_id = g_strdup_printf ("%p", cancellable);
+ data->cancellable = g_object_ref (cancellable);
+ data->cancelled_handler_id = g_signal_connect (data->cancellable,
+ "cancelled",
+ G_CALLBACK (operation_cancelled),
+ data);
+ }
+ else
+ {
+ data->cancellation_id = g_strdup ("");
+ }
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",
"org.gtk.Private.RemoteVolumeMonitor",
"DriveEject");
dbus_message_append_args (message,
DBUS_TYPE_STRING,
&(proxy_drive->id),
+ DBUS_TYPE_STRING,
+ &(data->cancellation_id),
DBUS_TYPE_UINT32,
&_flags,
DBUS_TYPE_INVALID);
@@ -470,6 +573,8 @@
data);
dbus_connection_unref (connection);
dbus_message_unref (message);
+ out:
+ ;
}
static gboolean
@@ -487,21 +592,30 @@
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);
+ if (!g_cancellable_is_cancelled (data->cancellable))
+ {
+ GSimpleAsyncResult *simple;
- g_object_unref (data->object);
+ if (error != NULL)
+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->drive),
+ data->callback,
+ data->user_data,
+ error);
+ else
+ simple = g_simple_async_result_new (G_OBJECT (data->drive),
+ data->callback,
+ data->user_data,
+ NULL);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ }
+
+ g_object_unref (data->drive);
+ g_free (data->cancellation_id);
+ if (data->cancelled_handler_id > 0)
+ g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id);
+ if (data->cancellable != NULL)
+ g_object_unref (data->cancellable);
g_free (data);
}
@@ -519,22 +633,52 @@
G_LOCK (proxy_drive);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ GSimpleAsyncResult *simple;
+ simple = g_simple_async_result_new_error (G_OBJECT (drive),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ G_UNLOCK (proxy_drive);
+ goto out;
+ }
+
data = g_new0 (DBusOp, 1);
- data->object = g_object_ref (drive);
+ data->drive = g_object_ref (drive);
data->callback = callback;
data->user_data = user_data;
- data->cancellable = cancellable;
+
+ if (cancellable != NULL)
+ {
+ data->cancellation_id = g_strdup_printf ("%p", cancellable);
+ data->cancellable = g_object_ref (cancellable);
+ data->cancelled_handler_id = g_signal_connect (data->cancellable,
+ "cancelled",
+ G_CALLBACK (operation_cancelled),
+ data);
+ }
+ else
+ {
+ data->cancellation_id = g_strdup ("");
+ }
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",
"org.gtk.Private.RemoteVolumeMonitor",
"DrivePollForMedia");
dbus_message_append_args (message,
DBUS_TYPE_STRING,
&(proxy_drive->id),
+ DBUS_TYPE_STRING,
+ &(data->cancellation_id),
DBUS_TYPE_INVALID);
G_UNLOCK (proxy_drive);
@@ -545,6 +689,8 @@
data);
dbus_connection_unref (connection);
dbus_message_unref (message);
+ out:
+ ;
}
static gboolean
Modified: trunk/monitor/proxy/gproxymount.c
==============================================================================
--- trunk/monitor/proxy/gproxymount.c (original)
+++ trunk/monitor/proxy/gproxymount.c Thu Feb 26 18:17:52 2009
@@ -415,32 +415,99 @@
}
typedef struct {
- GObject *object;
+ GProxyMount *mount;
GAsyncReadyCallback callback;
gpointer user_data;
+
+ gchar *cancellation_id;
GCancellable *cancellable;
+ gulong cancelled_handler_id;
} DBusOp;
static void
+cancel_operation_reply_cb (DBusMessage *reply,
+ GError *error,
+ gpointer user_data)
+{
+ if (error != NULL)
+ {
+ g_warning ("Error from CancelOperation(): %s", error->message);
+ }
+}
+
+static void
+operation_cancelled (GCancellable *cancellable,
+ gpointer user_data)
+{
+ DBusOp *data = user_data;
+ GSimpleAsyncResult *simple;
+ DBusConnection *connection;
+ DBusMessage *message;
+ const char *name;
+
+ G_LOCK (proxy_mount);
+
+ simple = g_simple_async_result_new_error (G_OBJECT (data->mount),
+ data->callback,
+ data->user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+
+ /* Now tell the remote volume monitor that the op has been cancelled */
+ connection = g_proxy_volume_monitor_get_dbus_connection (data->mount->volume_monitor);
+ name = g_proxy_volume_monitor_get_dbus_name (data->mount->volume_monitor);
+ message = dbus_message_new_method_call (name,
+ "/org/gtk/Private/RemoteVolumeMonitor",
+ "org.gtk.Private.RemoteVolumeMonitor",
+ "CancelOperation");
+ dbus_message_append_args (message,
+ DBUS_TYPE_STRING,
+ &(data->cancellation_id),
+ DBUS_TYPE_INVALID);
+
+ G_UNLOCK (proxy_mount);
+
+ _g_dbus_connection_call_async (connection,
+ message,
+ -1,
+ (GAsyncDBusCallback) cancel_operation_reply_cb,
+ NULL);
+ dbus_message_unref (message);
+ dbus_connection_unref (connection);
+}
+
+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);
+ if (data->cancelled_handler_id > 0)
+ g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id);
- g_object_unref (data->object);
+ if (!g_cancellable_is_cancelled (data->cancellable))
+ {
+ GSimpleAsyncResult *simple;
+ if (error != NULL)
+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount),
+ data->callback,
+ data->user_data,
+ error);
+ else
+ simple = g_simple_async_result_new (G_OBJECT (data->mount),
+ data->callback,
+ data->user_data,
+ NULL);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ }
+
+ g_object_unref (data->mount);
+ g_free (data->cancellation_id);
+ if (data->cancellable != NULL)
+ g_object_unref (data->cancellable);
g_free (data);
}
@@ -460,22 +527,52 @@
G_LOCK (proxy_mount);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ GSimpleAsyncResult *simple;
+ simple = g_simple_async_result_new_error (G_OBJECT (mount),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ G_UNLOCK (proxy_mount);
+ goto out;
+ }
+
data = g_new0 (DBusOp, 1);
- data->object = g_object_ref (mount);
+ data->mount = g_object_ref (mount);
data->callback = callback;
data->user_data = user_data;
- data->cancellable = cancellable;
+
+ if (cancellable != NULL)
+ {
+ data->cancellation_id = g_strdup_printf ("%p", cancellable);
+ data->cancellable = g_object_ref (cancellable);
+ data->cancelled_handler_id = g_signal_connect (data->cancellable,
+ "cancelled",
+ G_CALLBACK (operation_cancelled),
+ data);
+ }
+ else
+ {
+ data->cancellation_id = g_strdup ("");
+ }
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",
"org.gtk.Private.RemoteVolumeMonitor",
"MountUnmount");
dbus_message_append_args (message,
DBUS_TYPE_STRING,
&(proxy_mount->id),
+ DBUS_TYPE_STRING,
+ &(data->cancellation_id),
DBUS_TYPE_UINT32,
&_flags,
DBUS_TYPE_INVALID);
@@ -489,6 +586,8 @@
dbus_message_unref (message);
dbus_connection_unref (connection);
+ out:
+ ;
}
static gboolean
Modified: trunk/monitor/proxy/gproxyshadowmount.c
==============================================================================
--- trunk/monitor/proxy/gproxyshadowmount.c (original)
+++ trunk/monitor/proxy/gproxyshadowmount.c Thu Feb 26 18:17:52 2009
@@ -263,12 +263,30 @@
gboolean res;
G_LOCK (proxy_shadow_mount);
- res = g_mount_can_eject (G_MOUNT (proxy_shadow_mount->real_mount));
+ res = g_volume_can_eject (G_VOLUME (proxy_shadow_mount->volume));
G_UNLOCK (proxy_shadow_mount);
return res;
}
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} EjectWrapperOp;
+
+static void
+eject_wrapper_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EjectWrapperOp *data = user_data;
+ data->callback (data->object, res, data->user_data);
+ g_object_unref (data->object);
+ g_free (data);
+}
+
static void
g_proxy_shadow_mount_eject (GMount *mount,
GMountUnmountFlags flags,
@@ -277,12 +295,15 @@
gpointer user_data)
{
GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount);
+ EjectWrapperOp *data;
- g_mount_eject (proxy_shadow_mount->real_mount,
- flags,
- cancellable,
- callback,
- user_data);
+ G_LOCK (proxy_shadow_mount);
+ data = g_new0 (EjectWrapperOp, 1);
+ data->object = g_object_ref (mount);
+ data->callback = callback;
+ data->user_data = user_data;
+ g_volume_eject (G_VOLUME (proxy_shadow_mount->volume), flags, cancellable, eject_wrapper_callback, data);
+ G_UNLOCK (proxy_shadow_mount);
}
static gboolean
@@ -291,10 +312,13 @@
GError **error)
{
GProxyShadowMount *proxy_shadow_mount = G_PROXY_SHADOW_MOUNT (mount);
+ gboolean res;
- return g_mount_eject_finish (proxy_shadow_mount->real_mount,
- result,
- error);
+ G_LOCK (proxy_shadow_mount);
+ res = g_volume_eject_finish (G_VOLUME (proxy_shadow_mount->volume), result, error);
+ G_UNLOCK (proxy_shadow_mount);
+
+ return res;
}
static void
Modified: trunk/monitor/proxy/gproxyvolume.c
==============================================================================
--- trunk/monitor/proxy/gproxyvolume.c (original)
+++ trunk/monitor/proxy/gproxyvolume.c Thu Feb 26 18:17:52 2009
@@ -63,6 +63,8 @@
gboolean should_automount;
GProxyShadowMount *shadow_mount;
+
+ GHashTable *hash_mount_op_id_to_data;
};
static void g_proxy_volume_volume_iface_init (GVolumeIface *iface);
@@ -141,6 +143,8 @@
g_object_unref (volume->volume_monitor);
}
+ g_hash_table_unref (volume->hash_mount_op_id_to_data);
+
if (G_OBJECT_CLASS (g_proxy_volume_parent_class)->finalize)
(*G_OBJECT_CLASS (g_proxy_volume_parent_class)->finalize) (object);
}
@@ -161,6 +165,7 @@
static void
g_proxy_volume_init (GProxyVolume *proxy_volume)
{
+ proxy_volume->hash_mount_op_id_to_data = g_hash_table_new (g_str_hash, g_str_equal);
}
GProxyVolume *
@@ -672,32 +677,60 @@
}
typedef struct {
- GObject *object;
+ GProxyVolume *volume;
GAsyncReadyCallback callback;
gpointer user_data;
+
+ gchar *cancellation_id;
GCancellable *cancellable;
+ gulong cancelled_handler_id;
+
+ gchar *mount_op_id;
+ GMountOperation *mount_operation;
+ gulong reply_handler_id;
} DBusOp;
static void
mount_cb (DBusMessage *reply,
- GError *error,
- DBusOp *data)
+ 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_in_idle (simple);
- g_object_unref (simple);
+ if (data->cancelled_handler_id > 0)
+ g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id);
+
+ if (!g_cancellable_is_cancelled (data->cancellable))
+ {
+ GSimpleAsyncResult *simple;
+
+ if (error != NULL)
+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->volume),
+ data->callback,
+ data->user_data,
+ error);
+ else
+ simple = g_simple_async_result_new (G_OBJECT (data->volume),
+ data->callback,
+ data->user_data,
+ NULL);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ }
+
+ /* free DBusOp */
+ if (strlen (data->mount_op_id) > 0)
+ g_hash_table_remove (data->volume->hash_mount_op_id_to_data, data->mount_op_id);
+ g_object_unref (data->volume);
+
+ g_free (data->mount_op_id);
+ if (data->reply_handler_id > 0)
+ g_signal_handler_disconnect (data->mount_operation, data->reply_handler_id);
+ if (data->mount_operation != NULL)
+ g_object_unref (data->mount_operation);
+
+ g_free (data->cancellation_id);
+ if (data->cancellable != NULL)
+ g_object_unref (data->cancellable);
- g_object_unref (data->object);
g_free (data);
}
@@ -720,6 +753,61 @@
}
static void
+cancel_operation_reply_cb (DBusMessage *reply,
+ GError *error,
+ gpointer user_data)
+{
+ if (error != NULL)
+ {
+ g_warning ("Error from CancelOperation(): %s", error->message);
+ }
+}
+
+static void
+mount_cancelled (GCancellable *cancellable,
+ gpointer user_data)
+{
+ DBusOp *data = user_data;
+ GSimpleAsyncResult *simple;
+ DBusConnection *connection;
+ DBusMessage *message;
+ const char *name;
+
+ G_LOCK (proxy_volume);
+
+ simple = g_simple_async_result_new_error (G_OBJECT (data->volume),
+ data->callback,
+ data->user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+
+ /* Now tell the remote volume monitor that the op has been cancelled */
+ connection = g_proxy_volume_monitor_get_dbus_connection (data->volume->volume_monitor);
+ name = g_proxy_volume_monitor_get_dbus_name (data->volume->volume_monitor);
+ message = dbus_message_new_method_call (name,
+ "/org/gtk/Private/RemoteVolumeMonitor",
+ "org.gtk.Private.RemoteVolumeMonitor",
+ "CancelOperation");
+ dbus_message_append_args (message,
+ DBUS_TYPE_STRING,
+ &(data->cancellation_id),
+ DBUS_TYPE_INVALID);
+
+ G_UNLOCK (proxy_volume);
+
+ _g_dbus_connection_call_async (connection,
+ message,
+ -1,
+ (GAsyncDBusCallback) cancel_operation_reply_cb,
+ NULL);
+ dbus_message_unref (message);
+ dbus_connection_unref (connection);
+}
+
+static void
g_proxy_volume_mount (GVolume *volume,
GMountMountFlags flags,
GMountOperation *mount_operation,
@@ -760,41 +848,302 @@
const char *name;
DBusMessage *message;
dbus_uint32_t _flags = flags;
- dbus_bool_t use_mount_operation = mount_operation != NULL;
- /* TODO: support mount_operation */
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ GSimpleAsyncResult *simple;
+ simple = g_simple_async_result_new_error (G_OBJECT (volume),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ G_UNLOCK (proxy_volume);
+ goto out;
+ }
data = g_new0 (DBusOp, 1);
- data->object = g_object_ref (volume);
+ data->volume = g_object_ref (volume);
data->callback = callback;
data->user_data = user_data;
- data->cancellable = cancellable;
+ if (cancellable != NULL)
+ {
+ data->cancellation_id = g_strdup_printf ("%p", cancellable);
+ data->cancellable = g_object_ref (cancellable);
+ data->cancelled_handler_id = g_signal_connect (data->cancellable,
+ "cancelled",
+ G_CALLBACK (mount_cancelled),
+ data);
+ }
+ else
+ {
+ data->cancellation_id = g_strdup ("");
+ }
+
+ if (mount_operation != NULL)
+ {
+ data->mount_op_id = g_strdup_printf ("%p", mount_operation);
+ data->mount_operation = g_object_ref (mount_operation);
+ g_hash_table_insert (proxy_volume->hash_mount_op_id_to_data,
+ data->mount_op_id,
+ data);
+ }
+ else
+ {
+ data->mount_op_id = g_strdup ("");
+ }
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",
"org.gtk.Private.RemoteVolumeMonitor",
"VolumeMount");
dbus_message_append_args (message,
DBUS_TYPE_STRING,
&(proxy_volume->id),
+ DBUS_TYPE_STRING,
+ &(data->cancellation_id),
DBUS_TYPE_UINT32,
&_flags,
- DBUS_TYPE_BOOLEAN,
- &use_mount_operation,
+ DBUS_TYPE_STRING,
+ &(data->mount_op_id),
DBUS_TYPE_INVALID);
G_UNLOCK (proxy_volume);
_g_dbus_connection_call_async (connection,
message,
- -1,
+ 30 * 60 * 1000, /* 30 minute timeout */
(GAsyncDBusCallback) mount_cb,
data);
dbus_message_unref (message);
dbus_connection_unref (connection);
}
+
+ out:
+ ;
+}
+
+
+static void
+mount_op_reply_cb (DBusMessage *reply,
+ GError *error,
+ DBusOp *data)
+{
+ if (error != NULL)
+ {
+ g_warning ("Error from MountOpReply(): %s", error->message);
+ }
+}
+
+static void
+mount_operation_reply (GMountOperation *mount_operation,
+ GMountOperationResult result,
+ gpointer user_data)
+{
+ DBusOp *data = user_data;
+ DBusConnection *connection;
+ const char *name;
+ DBusMessage *message;
+ const char *user_name;
+ const char *domain;
+ const char *password;
+ char *encoded_password;
+ dbus_uint32_t password_save;
+ dbus_uint32_t choice;
+ dbus_bool_t anonymous;
+
+ connection = g_proxy_volume_monitor_get_dbus_connection (data->volume->volume_monitor);
+ name = g_proxy_volume_monitor_get_dbus_name (data->volume->volume_monitor);
+
+ user_name = g_mount_operation_get_username (mount_operation);
+ domain = g_mount_operation_get_domain (mount_operation);
+ password = g_mount_operation_get_password (mount_operation);
+ password_save = g_mount_operation_get_password_save (mount_operation);
+ choice = g_mount_operation_get_choice (mount_operation);
+ anonymous = g_mount_operation_get_anonymous (mount_operation);
+
+ if (user_name == NULL)
+ user_name = "";
+ if (domain == NULL)
+ domain = "";
+ if (password == NULL)
+ password = "";
+
+ /* NOTE: this is not to add "security", it's merely to prevent accidental exposure
+ * of passwords when running dbus-monitor
+ */
+ encoded_password = g_base64_encode ((const guchar *) password, (gsize) (strlen (password) + 1));
+
+ message = dbus_message_new_method_call (name,
+ "/org/gtk/Private/RemoteVolumeMonitor",
+ "org.gtk.Private.RemoteVolumeMonitor",
+ "MountOpReply");
+ dbus_message_append_args (message,
+ DBUS_TYPE_STRING,
+ &(data->volume->id),
+ DBUS_TYPE_STRING,
+ &(data->mount_op_id),
+ DBUS_TYPE_INT32,
+ &result,
+ DBUS_TYPE_STRING,
+ &user_name,
+ DBUS_TYPE_STRING,
+ &domain,
+ DBUS_TYPE_STRING,
+ &encoded_password,
+ DBUS_TYPE_INT32,
+ &password_save,
+ DBUS_TYPE_INT32,
+ &choice,
+ DBUS_TYPE_BOOLEAN,
+ &anonymous,
+ DBUS_TYPE_INVALID);
+
+ _g_dbus_connection_call_async (connection,
+ message,
+ -1,
+ (GAsyncDBusCallback) mount_op_reply_cb,
+ data);
+
+ g_free (encoded_password);
+ dbus_message_unref (message);
+ dbus_connection_unref (connection);
+}
+
+void
+g_proxy_volume_handle_mount_op_ask_password (GProxyVolume *volume,
+ DBusMessageIter *iter)
+{
+ const char *mount_op_id;
+ const char *message;
+ const char *default_user;
+ const char *default_domain;
+ dbus_int32_t flags;
+ DBusOp *data;
+
+ dbus_message_iter_get_basic (iter, &mount_op_id);
+ dbus_message_iter_next (iter);
+
+ dbus_message_iter_get_basic (iter, &message);
+ dbus_message_iter_next (iter);
+
+ dbus_message_iter_get_basic (iter, &default_user);
+ dbus_message_iter_next (iter);
+
+ dbus_message_iter_get_basic (iter, &default_domain);
+ dbus_message_iter_next (iter);
+
+ dbus_message_iter_get_basic (iter, &flags);
+ dbus_message_iter_next (iter);
+
+ data = g_hash_table_lookup (volume->hash_mount_op_id_to_data, mount_op_id);
+
+ /* since eavesdropping is enabled on the session bus we get this signal even if it
+ * is for another application; so silently ignore it if it's not for us
+ */
+ if (data == NULL)
+ goto out;
+
+ if (data->reply_handler_id == 0)
+ {
+ data->reply_handler_id = g_signal_connect (data->mount_operation,
+ "reply",
+ G_CALLBACK (mount_operation_reply),
+ data);
+ }
+
+ g_signal_emit_by_name (data->mount_operation,
+ "ask-password",
+ message,
+ default_user,
+ default_domain,
+ flags);
+
+ out:
+ ;
+}
+
+void
+g_proxy_volume_handle_mount_op_ask_question (GProxyVolume *volume,
+ DBusMessageIter *iter)
+{
+ const char *mount_op_id;
+ const char *message;
+ GPtrArray *choices;
+ DBusMessageIter iter_array;
+ DBusOp *data;
+
+ choices = NULL;
+
+ dbus_message_iter_get_basic (iter, &mount_op_id);
+ dbus_message_iter_next (iter);
+
+ dbus_message_iter_get_basic (iter, &message);
+ dbus_message_iter_next (iter);
+
+ choices = g_ptr_array_new ();
+ dbus_message_iter_recurse (iter, &iter_array);
+ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
+ {
+ const char *choice;
+ dbus_message_iter_get_basic (&iter_array, &choice);
+ dbus_message_iter_next (&iter_array);
+
+ g_ptr_array_add (choices, g_strdup (choice));
+ }
+ g_ptr_array_add (choices, NULL);
+
+ data = g_hash_table_lookup (volume->hash_mount_op_id_to_data, mount_op_id);
+
+ /* since eavesdropping is enabled on the session bus we get this signal even if it
+ * is for another application; so silently ignore it if it's not for us
+ */
+ if (data == NULL)
+ goto out;
+
+ if (data->reply_handler_id == 0)
+ {
+ data->reply_handler_id = g_signal_connect (data->mount_operation,
+ "reply",
+ G_CALLBACK (mount_operation_reply),
+ data);
+ }
+
+ g_signal_emit_by_name (data->mount_operation,
+ "ask-question",
+ message,
+ choices->pdata);
+
+ out:
+ g_ptr_array_free (choices, TRUE);
+}
+
+void
+g_proxy_volume_handle_mount_op_aborted (GProxyVolume *volume,
+ DBusMessageIter *iter)
+{
+ const char *mount_op_id;
+ DBusOp *data;
+
+ dbus_message_iter_get_basic (iter, &mount_op_id);
+ dbus_message_iter_next (iter);
+
+ data = g_hash_table_lookup (volume->hash_mount_op_id_to_data, mount_op_id);
+
+ /* since eavesdropping is enabled on the session bus we get this signal even if it
+ * is for another application; so silently ignore it if it's not for us
+ */
+ if (data == NULL)
+ goto out;
+
+ g_signal_emit_by_name (data->mount_operation, "aborted");
+
+ out:
+ ;
}
static gboolean
Modified: trunk/monitor/proxy/gproxyvolume.h
==============================================================================
--- trunk/monitor/proxy/gproxyvolume.h (original)
+++ trunk/monitor/proxy/gproxyvolume.h Thu Feb 26 18:17:52 2009
@@ -53,6 +53,15 @@
GProxyShadowMount *g_proxy_volume_get_shadow_mount (GProxyVolume *volume);
+void g_proxy_volume_handle_mount_op_ask_password (GProxyVolume *volume,
+ DBusMessageIter *iter);
+
+void g_proxy_volume_handle_mount_op_ask_question (GProxyVolume *volume,
+ DBusMessageIter *iter);
+
+void g_proxy_volume_handle_mount_op_aborted (GProxyVolume *volume,
+ DBusMessageIter *iter);
+
G_END_DECLS
#endif /* __G_PROXY_VOLUME_H__ */
Modified: trunk/monitor/proxy/gproxyvolumemonitor.c
==============================================================================
--- trunk/monitor/proxy/gproxyvolumemonitor.c (original)
+++ trunk/monitor/proxy/gproxyvolumemonitor.c Thu Feb 26 18:17:52 2009
@@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* gvfs - extensions for gio
*
- * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2009 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
@@ -21,22 +21,9 @@
* Author: David Zeuthen <davidz redhat com>
*/
-/*
- * 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.
+/* TODO: handle force_rescan in g_mount_guess_content_type(); right now we
+ * just scan in the daemon first time the GMount is seen and
+ * cache that result forever.
*/
#include <config.h>
@@ -68,6 +55,9 @@
GHashTable *drives;
GHashTable *volumes;
GHashTable *mounts;
+
+ /* The unique D-Bus name of the remote monitor or NULL if disconnected */
+ gchar *unique_name;
};
G_DEFINE_DYNAMIC_TYPE_EXTENDED (GProxyVolumeMonitor,
@@ -107,11 +97,21 @@
};
static char *
-get_match_rule (GProxyVolumeMonitor *monitor)
+get_match_rule_for_signals (GProxyVolumeMonitor *monitor)
{
return g_strdup_printf ("type='signal',"
"interface='org.gtk.Private.RemoteVolumeMonitor',"
- "sender='%s'",
+ "sender='%s',",
+ g_proxy_volume_monitor_get_dbus_name (monitor));
+}
+
+static char *
+get_match_rule_for_name_owner_changed (GProxyVolumeMonitor *monitor)
+{
+ return g_strdup_printf ("type='signal',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "arg0='%s'",
g_proxy_volume_monitor_get_dbus_name (monitor));
}
@@ -135,20 +135,32 @@
g_hash_table_unref (monitor->volumes);
g_hash_table_unref (monitor->mounts);
+ g_free (monitor->unique_name);
+
dbus_connection_remove_filter (monitor->session_bus, filter_function, monitor);
- match_rule = get_match_rule (monitor);
+
+ match_rule = get_match_rule_for_signals (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);
+
+ match_rule = get_match_rule_for_name_owner_changed (monitor);
+ dbus_error_init (&dbus_error);
+ dbus_bus_remove_match (monitor->session_bus,
+ match_rule,
+ &dbus_error);
+ if (dbus_error_is_set (&dbus_error)) {
+ 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)
@@ -306,16 +318,35 @@
GHashTableIter vm_hash_iter;
GHashTableIter vol_hash_iter;
GProxyMount *candidate_mount;
+ static GVolumeMonitor *union_monitor = NULL;
- /* 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.
+ /* There's a problem here insofar that this static method on GNativeVolumeMonitor can
+ * be called *before* any of our monitors are constructed. Since this method doesn't
+ * pass in the class structure we *know* which native remote monitor to use.
*
- * 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.
+ * To work around that, we get the singleton GVolumeMonitor... This will trigger
+ * construction of a GUnionVolumeMonitor in gio which will construct the *appropriate*
+ * remote volume monitors to use (it's up to gio to pick which one to use).
+ *
+ * Note that we will *hold* on to this reference effectively making us a resident
+ * module. And effectively keeping volume monitoring alive.
+ *
+ * The reason we hold on to the reference is that otherwise we'd be constructing/destructing
+ * *all* proxy volume monitors (which includes synchronous D-Bus calls to seed the monitor)
+ * every time this method is called.
+ *
+ * Note that *simple* GIO apps that a) don't use volume monitors; and b) don't use the
+ * g_file_find_enclosing_mount() method will never see any volume monitor overhead.
*/
+ /* Note that g_volume_monitor_get() is thread safe. We don't want to call it while
+ * holding the proxy_vm lock since it might end up calling our constructor.
+ */
+ if (union_monitor == NULL)
+ union_monitor = g_volume_monitor_get ();
+
mount = NULL;
+
G_LOCK (proxy_vm);
/* First find the native volume monitor if one exists */
@@ -390,14 +421,24 @@
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);
+
+ /* listen to volume monitor signals */
+ match_rule = get_match_rule_for_signals (monitor);
+ dbus_bus_add_match (monitor->session_bus,
+ match_rule,
+ &dbus_error);
+ if (dbus_error_is_set (&dbus_error)) {
+ 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);
+
+ /* listen to when the owner of the service appears/disappears */
+ match_rule = get_match_rule_for_name_owner_changed (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);
}
@@ -470,178 +511,283 @@
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);
- }
- }
+ if (dbus_message_is_signal (message, "org.freedesktop.DBus", "NameOwnerChanged"))
+ {
+ GHashTableIter hash_iter;
+ GProxyMount *mount;
+ GProxyVolume *volume;
+ GProxyDrive *drive;
+ const gchar *name;
+ const gchar *old_owner;
+ const gchar *new_owner;
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_get_basic (&iter, &name);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &old_owner);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &new_owner);
+ dbus_message_iter_next (&iter);
- } 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)
- {
- GProxyShadowMount *shadow_mount;
+ if (strcmp (name, klass->dbus_name) != 0)
+ goto not_for_us;
- g_proxy_volume_update (volume, &iter);
- signal_emit_in_idle (volume, "changed", NULL);
- signal_emit_in_idle (monitor, "volume-changed", volume);
-
- shadow_mount = g_proxy_volume_get_shadow_mount (volume);
- if (shadow_mount != NULL)
- {
- signal_emit_in_idle (shadow_mount, "changed", NULL);
- signal_emit_in_idle (monitor, "mount-changed", shadow_mount);
- g_object_unref (shadow_mount);
- }
- }
- }
- 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);
+ if (monitor->unique_name != NULL && g_strcmp0 (new_owner, monitor->unique_name) != 0)
+ {
+ g_warning ("Owner %s of volume monitor %s disconnected from the bus; removing drives/volumes/mounts",
+ monitor->unique_name,
+ klass->dbus_name);
+
+ g_hash_table_iter_init (&hash_iter, monitor->mounts);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &mount))
+ {
+ signal_emit_in_idle (mount, "unmounted", NULL);
+ signal_emit_in_idle (monitor, "mount-removed", mount);
+ }
+ g_hash_table_remove_all (monitor->mounts);
+
+ g_hash_table_iter_init (&hash_iter, monitor->volumes);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &volume))
+ {
+ signal_emit_in_idle (volume, "removed", NULL);
+ signal_emit_in_idle (monitor, "volume-removed", volume);
+ }
+ g_hash_table_remove_all (monitor->volumes);
+
+ g_hash_table_iter_init (&hash_iter, monitor->drives);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &drive))
+ {
+ signal_emit_in_idle (drive, "disconnected", NULL);
+ signal_emit_in_idle (monitor, "drive-disconnected", drive);
+ }
+ g_hash_table_remove_all (monitor->drives);
+
+ g_free (monitor->unique_name);
+ monitor->unique_name = NULL;
+
+ /* TODO: maybe try to relaunch the monitor? */
+
+ }
+
+ if (strlen (new_owner) > 0 && monitor->unique_name == NULL)
+ {
+ g_warning ("New owner %s for volume monitor %s connected to the bus; seeding drives/volumes/mounts",
+ new_owner,
+ klass->dbus_name);
+
+ seed_monitor (monitor);
+
+ /* emit signals for all the drives/volumes/mounts "added" */
+ g_hash_table_iter_init (&hash_iter, monitor->drives);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &drive))
+ signal_emit_in_idle (monitor, "drive-connected", drive);
+
+ g_hash_table_iter_init (&hash_iter, monitor->volumes);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &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);
+ g_hash_table_iter_init (&hash_iter, monitor->mounts);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &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);
- }
- }
+ }
- }
+ }
+ else 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_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "MountOpAskPassword") ||
+ dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "MountOpAskQuestion") ||
+ dbus_message_is_signal (message, "org.gtk.Private.RemoteVolumeMonitor", "MountOpAborted"))
+ {
+ 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)
+ {
+ GProxyShadowMount *shadow_mount;
+
+ g_proxy_volume_update (volume, &iter);
+ signal_emit_in_idle (volume, "changed", NULL);
+ signal_emit_in_idle (monitor, "volume-changed", volume);
+
+ shadow_mount = g_proxy_volume_get_shadow_mount (volume);
+ if (shadow_mount != NULL)
+ {
+ signal_emit_in_idle (shadow_mount, "changed", NULL);
+ signal_emit_in_idle (monitor, "mount-changed", shadow_mount);
+ g_object_unref (shadow_mount);
+ }
+ }
+ }
+ 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 (strcmp (member, "MountOpAskPassword") == 0)
+ {
+ volume = g_hash_table_lookup (monitor->volumes, id);
+ if (volume != NULL)
+ g_proxy_volume_handle_mount_op_ask_password (volume, &iter);
+ }
+ else if (strcmp (member, "MountOpAskQuestion") == 0)
+ {
+ volume = g_hash_table_lookup (monitor->volumes, id);
+ if (volume != NULL)
+ g_proxy_volume_handle_mount_op_ask_question (volume, &iter);
+ }
+ else if (strcmp (member, "MountOpAborted") == 0)
+ {
+ volume = g_hash_table_lookup (monitor->volumes, id);
+ if (volume != NULL)
+ g_proxy_volume_handle_mount_op_aborted (volume, &iter);
+ }
+
+ }
+ 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);
@@ -706,7 +852,7 @@
is_supported = FALSE;
message = dbus_message_new_method_call (dbus_name,
- "/",
+ "/org/gtk/Private/RemoteVolumeMonitor",
"org.gtk.Private.RemoteVolumeMonitor",
"IsSupported");
if (message == NULL)
@@ -788,7 +934,7 @@
native_class->get_mount_for_mount_path = get_mount_for_mount_path;
}
-/* Must be called with no locks held */
+/* Call with proxy_vm lock held */
static void
seed_monitor (GProxyVolumeMonitor *monitor)
{
@@ -799,7 +945,7 @@
DBusMessageIter iter_array;
message = dbus_message_new_method_call (g_proxy_volume_monitor_get_dbus_name (monitor),
- "/",
+ "/org/gtk/Private/RemoteVolumeMonitor",
"org.gtk.Private.RemoteVolumeMonitor",
"List");
if (message == NULL)
@@ -869,6 +1015,8 @@
}
dbus_message_iter_next (&iter_reply);
+ monitor->unique_name = g_strdup (dbus_message_get_sender (reply));
+
dbus_message_unref (reply);
fail:
Modified: trunk/monitor/proxy/gproxyvolumemonitor.h
==============================================================================
--- trunk/monitor/proxy/gproxyvolumemonitor.h (original)
+++ trunk/monitor/proxy/gproxyvolumemonitor.h Thu Feb 26 18:17:52 2009
@@ -31,11 +31,12 @@
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))
+#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_PROXY_VOLUME_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), 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;
Modified: trunk/monitor/proxy/gvfsproxyvolumemonitordaemon.c
==============================================================================
--- trunk/monitor/proxy/gvfsproxyvolumemonitordaemon.c (original)
+++ trunk/monitor/proxy/gvfsproxyvolumemonitordaemon.c Thu Feb 26 18:17:52 2009
@@ -28,15 +28,173 @@
#include <dbus/dbus.h>
#include <glib/gi18n.h>
#include <stdlib.h>
+#include <glib/gprintf.h>
#include "gdbusutils.h"
#include "gvfsproxyvolumemonitordaemon.h"
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* #define DEBUG_ENABLED */
+
+#ifdef DEBUG_ENABLED
+static void
+print_debug (const gchar *format, ...)
+{
+ va_list var_args;
+
+ va_start (var_args, format);
+
+ g_print ("### debug: ");
+ g_vprintf (format, var_args);
+ g_print ("\n");
+
+ va_end (var_args);
+}
+#else
+static void
+print_debug (const gchar *format, ...)
+{
+}
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+GType g_proxy_mount_operation_get_type (void) G_GNUC_CONST;
+
+typedef struct
+{
+ GMountOperation parent_instance;
+} GProxyMountOperation;
+
+typedef struct
+{
+ GMountOperationClass parent_class;
+} GProxyMountOperationClass;
+
+
+static GMountOperation *
+g_proxy_mount_operation_new (void)
+{
+ return G_MOUNT_OPERATION (g_object_new (g_proxy_mount_operation_get_type(), NULL));
+}
+
+G_DEFINE_TYPE (GProxyMountOperation, g_proxy_mount_operation, G_TYPE_MOUNT_OPERATION)
+
+static void
+g_proxy_mount_operation_init (GProxyMountOperation *mount_operation)
+{
+}
+
+static void
+g_proxy_mount_operation_ask_password (GMountOperation *op,
+ const char *message,
+ const char *default_user,
+ const char *default_domain,
+ GAskPasswordFlags flags)
+{
+ /* do nothing */
+}
+
+static void
+g_proxy_mount_operation_ask_question (GMountOperation *op,
+ const char *message,
+ const char *choices[])
+{
+ /* do nothing */
+}
+
+static void
+g_proxy_mount_operation_class_init (GProxyMountOperationClass *klass)
+{
+ GMountOperationClass *mount_op_class;
+
+ mount_op_class = G_MOUNT_OPERATION_CLASS (klass);
+
+ mount_op_class->ask_password = g_proxy_mount_operation_ask_password;
+ mount_op_class->ask_question = g_proxy_mount_operation_ask_question;
+}
+
+
static GVolumeMonitor *monitor = NULL;
static DBusConnection *connection = NULL;
static GType the_volume_monitor_type;
static const char *the_dbus_name = NULL;
+static GList *outstanding_ops = NULL;
+
+static GHashTable *unique_names_being_watched = NULL;
+
+static void
+cancellable_destroyed_cb (gpointer user_data,
+ GObject *where_the_cancellable_was)
+{
+ outstanding_ops = g_list_remove (outstanding_ops, where_the_cancellable_was);
+}
+
+static void
+remove_name_owned_changed_for_unique_name (const gchar *unique_name)
+{
+ const gchar *match_rule;
+ DBusError dbus_error;
+
+ match_rule = g_hash_table_lookup (unique_names_being_watched, unique_name);
+ if (match_rule == NULL)
+ {
+ g_warning ("Was asked to remove match rule for unique_name %s but we don't have one", unique_name);
+ goto out;
+ }
+
+ dbus_error_init (&dbus_error);
+ dbus_bus_remove_match (connection,
+ match_rule,
+ &dbus_error);
+ if (dbus_error_is_set (&dbus_error)) {
+ g_warning ("cannot remove match rule '%s': %s: %s", match_rule, dbus_error.name, dbus_error.message);
+ dbus_error_free (&dbus_error);
+ }
+
+ g_hash_table_remove (unique_names_being_watched, unique_name);
+
+ out:
+ ;
+}
+
+static void
+ensure_name_owner_changed_for_unique_name (const gchar *unique_name)
+{
+ gchar *match_rule;
+ DBusError dbus_error;
+
+ if (g_hash_table_lookup (unique_names_being_watched, unique_name) != NULL)
+ goto out;
+
+ match_rule = g_strdup_printf ("type='signal',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "arg0='%s'",
+ unique_name);
+
+ dbus_error_init (&dbus_error);
+ dbus_bus_add_match (connection,
+ match_rule,
+ &dbus_error);
+ if (dbus_error_is_set (&dbus_error))
+ {
+ 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);
+ goto out;
+ }
+
+ g_hash_table_insert (unique_names_being_watched, g_strdup (unique_name), match_rule);
+
+ out:
+ ;
+}
+
static void monitor_try_create (void);
/* string id
@@ -46,10 +204,11 @@
* boolean can-poll-for-media
* boolean has-media
* boolean is-media-removable
+ * boolean is-media-check-automatic
* array:string volume-ids
* dict:string->string identifiers
*/
-#define DRIVE_STRUCT_TYPE "(sssbbbbasa{ss})"
+#define DRIVE_STRUCT_TYPE "(sssbbbbbasa{ss})"
static void
append_drive (GDrive *drive, DBusMessageIter *iter_array)
@@ -65,6 +224,7 @@
gboolean can_poll_for_media;
gboolean has_media;
gboolean is_media_removable;
+ gboolean is_media_check_automatic;
GList *volumes, *l;
char **identifiers;
int n;
@@ -82,6 +242,7 @@
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);
+ is_media_check_automatic = g_drive_is_media_check_automatic (drive);
volumes = g_drive_get_volumes (drive);
identifiers = g_drive_enumerate_identifiers (drive);
@@ -95,6 +256,7 @@
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_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &is_media_check_automatic);
dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_volume_array);
for (l = volumes; l != NULL; l = l->next)
@@ -108,7 +270,7 @@
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++)
+ for (n = 0; identifiers != NULL && identifiers[n] != NULL; n++)
{
DBusMessageIter iter_dict_entry;
char *id_value;
@@ -214,7 +376,7 @@
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++)
+ for (n = 0; identifiers != NULL && identifiers[n] != NULL; n++)
{
DBusMessageIter iter_dict_entry;
char *id_value;
@@ -343,6 +505,8 @@
DBusMessageIter iter_array;
DBusMessage *reply;
+ print_debug ("in handle_list");
+
drives = g_volume_monitor_get_connected_drives (monitor);
volumes = g_volume_monitor_get_volumes (monitor);
mounts = g_volume_monitor_get_mounts (monitor);
@@ -383,14 +547,20 @@
GError *error;
DBusMessage *reply;
+ print_debug ("in mount_unmount_cb");
+
+ g_object_set_data (G_OBJECT (mount), "cancellable", NULL);
+
error = NULL;
if (!g_mount_unmount_finish (mount, result, &error))
{
+ print_debug (" error: %s", error->message);
reply = _dbus_message_new_from_gerror (message, error);
g_error_free (error);
}
else
{
+ print_debug (" success");
reply = dbus_message_new_method_return (message);
}
@@ -403,6 +573,9 @@
handle_mount_unmount (DBusConnection *connection, DBusMessage *message)
{
const char *id;
+ const char *cancellation_id;
+ const char *sender;
+ GCancellable *cancellable;
dbus_uint32_t unmount_flags;
DBusError dbus_error;
GList *mounts, *l;
@@ -416,7 +589,8 @@
dbus_error_init (&dbus_error);
if (!dbus_message_get_args (message, &dbus_error,
DBUS_TYPE_STRING, &id,
- DBUS_TYPE_UINT32 &unmount_flags,
+ DBUS_TYPE_STRING, &cancellation_id,
+ DBUS_TYPE_UINT32, &unmount_flags,
DBUS_TYPE_INVALID))
{
g_warning ("Error parsing args for MountUnmount(): %s: %s", dbus_error.name, dbus_error.message);
@@ -424,8 +598,12 @@
goto out;
}
+ print_debug ("in handle_mount_unmount");
+
ret = DBUS_HANDLER_RESULT_HANDLED;
+ sender = dbus_message_get_sender (message);
+
mount = NULL;
mounts = g_volume_monitor_get_mounts (monitor);
for (l = mounts; l != NULL; l = l->next)
@@ -453,6 +631,26 @@
goto out;
}
+ if (g_object_get_data (G_OBJECT (mount), "cancellable") != NULL)
+ {
+ DBusMessage *reply;
+ reply = dbus_message_new_error (message,
+ "org.gtk.Private.RemoteVolumeMonitor.Failed",
+ "An operation is already pending");
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ goto out;
+ }
+
+ cancellable = g_cancellable_new ();
+ g_object_set_data_full (G_OBJECT (mount), "cancellable", cancellable, g_object_unref);
+ g_object_set_data_full (G_OBJECT (cancellable), "owner", g_strdup (sender), g_free);
+ g_object_set_data_full (G_OBJECT (cancellable), "cancellation_id", g_strdup (cancellation_id), g_free);
+ outstanding_ops = g_list_prepend (outstanding_ops, cancellable);
+ g_object_weak_ref (G_OBJECT (cancellable),
+ cancellable_destroyed_cb,
+ NULL);
+
g_mount_unmount (mount,
unmount_flags,
NULL,
@@ -470,20 +668,140 @@
/* ---------------------------------------------------------------------------------------------------- */
+static DBusHandlerResult
+handle_mount_op_reply (DBusConnection *connection, DBusMessage *message)
+{
+ const char *id;
+ const char *mount_op_id;
+ dbus_int32_t result;
+ const char *user_name;
+ const char *domain;
+ const char *encoded_password;
+ char *decoded_password;
+ gsize decoded_password_len;
+ dbus_int32_t password_save;
+ dbus_int32_t choice;
+ dbus_bool_t anonymous;
+ DBusError dbus_error;
+ DBusHandlerResult ret;
+ GList *volumes, *l;
+ GVolume *volume;
+ DBusMessage *reply;
+ GMountOperation *mount_operation;
+
+ volumes = NULL;
+ decoded_password = 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_STRING, &mount_op_id,
+ DBUS_TYPE_INT32, &result,
+ DBUS_TYPE_STRING, &user_name,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_STRING, &encoded_password,
+ DBUS_TYPE_INT32, &password_save,
+ DBUS_TYPE_INT32, &choice,
+ DBUS_TYPE_BOOLEAN, &anonymous,
+ DBUS_TYPE_INVALID))
+ {
+ g_warning ("Error parsing args for MountOpReply(): %s: %s", dbus_error.name, dbus_error.message);
+ dbus_error_free (&dbus_error);
+ goto out;
+ }
+
+ print_debug ("in handle_mount_op_reply");
+
+ 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 = g_object_get_data (G_OBJECT (volume), "mount_operation");
+ if (mount_operation == NULL)
+ {
+ DBusMessage *reply;
+ reply = dbus_message_new_error (message,
+ "org.gtk.Private.RemoteVolumeMonitor.NotFound",
+ "No outstanding mount operation");
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ goto out;
+ }
+
+ decoded_password = (gchar *) g_base64_decode (encoded_password, &decoded_password_len);
+
+ g_mount_operation_set_username (mount_operation, user_name);
+ g_mount_operation_set_domain (mount_operation, domain);
+ g_mount_operation_set_password (mount_operation, decoded_password);
+ g_mount_operation_set_password_save (mount_operation, password_save);
+ g_mount_operation_set_choice (mount_operation, choice);
+ g_mount_operation_set_anonymous (mount_operation, anonymous);
+
+ g_mount_operation_reply (mount_operation, result);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ out:
+ g_free (decoded_password);
+ if (volumes != NULL)
+ {
+ g_list_foreach (volumes, (GFunc) g_object_unref, NULL);
+ g_list_free (volumes);
+ }
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
volume_mount_cb (GVolume *volume, GAsyncResult *result, DBusMessage *message)
{
GError *error;
DBusMessage *reply;
+ print_debug ("in volume_mount_cb");
+
+ g_object_set_data (G_OBJECT (volume), "mount_operation", NULL);
+ g_object_set_data (G_OBJECT (volume), "cancellable", NULL);
+
error = NULL;
if (!g_volume_mount_finish (volume, result, &error))
{
+ print_debug (" error: %s", error->message);
reply = _dbus_message_new_from_gerror (message, error);
g_error_free (error);
}
else
{
+ print_debug (" success");
reply = dbus_message_new_method_return (message);
}
@@ -492,26 +810,170 @@
dbus_message_unref (reply);
}
+static void
+ask_password_cb (GMountOperation *mount_operation,
+ const gchar *message_to_show,
+ const gchar *default_user,
+ const gchar *default_domain,
+ GAskPasswordFlags flags,
+ gpointer user_data)
+{
+ gchar *id;
+ DBusMessage *message;
+ DBusMessageIter iter;
+ GVolume *volume;
+ const gchar *mount_op_id;
+ const gchar *mount_op_owner;
+
+ print_debug ("in ask_password_cb %s", message_to_show);
+
+ volume = G_VOLUME (user_data);
+
+ id = g_strdup_printf ("%p", volume);
+
+ mount_op_id = g_object_get_data (G_OBJECT (mount_operation), "mount_op_id");
+ mount_op_owner = g_object_get_data (G_OBJECT (mount_operation), "mount_op_owner");
+
+ message = dbus_message_new_signal ("/org/gtk/Private/RemoteVolumeMonitor",
+ "org.gtk.Private.RemoteVolumeMonitor",
+ "MountOpAskPassword");
+ 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);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &mount_op_id);
+
+ if (message_to_show == NULL)
+ message_to_show = "";
+
+ if (default_user == NULL)
+ default_user = "";
+
+ if (default_domain == NULL)
+ default_domain = "";
+
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &message_to_show);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &default_user);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &default_domain);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &flags);
+
+ dbus_message_set_destination (message, mount_op_owner);
+
+ dbus_connection_send (connection, message, NULL);
+ dbus_message_unref (message);
+
+ g_free (id);
+}
+
+static void
+ask_question_cb (GMountOperation *mount_operation,
+ const gchar *message_to_show,
+ gchar **choices,
+ gpointer user_data)
+{
+ gchar *id;
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessageIter iter_string_array;
+ const gchar *mount_op_id;
+ const gchar *mount_op_owner;
+ GVolume *volume;
+ guint n;
+
+ print_debug ("in ask_question_cb %s", message_to_show);
+
+ volume = G_VOLUME (user_data);
+
+ id = g_strdup_printf ("%p", volume);
+
+ mount_op_id = g_object_get_data (G_OBJECT (mount_operation), "mount_op_id");
+ mount_op_owner = g_object_get_data (G_OBJECT (mount_operation), "mount_op_owner");
+
+ message = dbus_message_new_signal ("/org/gtk/Private/RemoteVolumeMonitor",
+ "org.gtk.Private.RemoteVolumeMonitor",
+ "MountOpAskQuestion");
+ 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);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &mount_op_id);
+
+ if (message_to_show == NULL)
+ message_to_show = "";
+
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &message_to_show);
+
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &iter_string_array);
+ for (n = 0; choices != NULL && choices[n] != NULL; n++)
+ dbus_message_iter_append_basic (&iter_string_array, DBUS_TYPE_STRING, &(choices[n]));
+ dbus_message_iter_close_container (&iter, &iter_string_array);
+
+ dbus_message_set_destination (message, mount_op_owner);
+
+ dbus_connection_send (connection, message, NULL);
+ dbus_message_unref (message);
+
+ g_free (id);
+}
+
+static void
+aborted_cb (GMountOperation *mount_operation,
+ gpointer user_data)
+{
+ gchar *id;
+ DBusMessage *message;
+ DBusMessageIter iter;
+ GVolume *volume;
+ const gchar *mount_op_id;
+ const gchar *mount_op_owner;
+
+ print_debug ("in aborted_cb");
+
+ volume = G_VOLUME (user_data);
+
+ id = g_strdup_printf ("%p", volume);
+
+ mount_op_id = g_object_get_data (G_OBJECT (mount_operation), "mount_op_id");
+ mount_op_owner = g_object_get_data (G_OBJECT (mount_operation), "mount_op_owner");
+
+ message = dbus_message_new_signal ("/org/gtk/Private/RemoteVolumeMonitor",
+ "org.gtk.Private.RemoteVolumeMonitor",
+ "MountOpAborted");
+ 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);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &mount_op_id);
+
+ dbus_message_set_destination (message, mount_op_owner);
+
+ dbus_connection_send (connection, message, NULL);
+ dbus_message_unref (message);
+
+ g_free (id);
+}
+
static DBusHandlerResult
handle_volume_mount (DBusConnection *connection, DBusMessage *message)
{
const char *id;
+ const char *cancellation_id;
+ const char *sender;
dbus_uint32_t mount_flags;
- dbus_bool_t use_mount_operation;
+ const char *mount_op_id;
DBusError dbus_error;
GList *volumes, *l;
GVolume *volume;
DBusHandlerResult ret;
GMountOperation *mount_operation;
+ GCancellable *cancellable;
- volume = NULL;
+ volumes = 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_STRING, &cancellation_id,
DBUS_TYPE_UINT32, &mount_flags,
- DBUS_TYPE_BOOLEAN, &use_mount_operation,
+ DBUS_TYPE_STRING, &mount_op_id,
DBUS_TYPE_INVALID))
{
g_warning ("Error parsing args for VolumeMount(): %s: %s", dbus_error.name, dbus_error.message);
@@ -519,8 +981,12 @@
goto out;
}
+ print_debug ("in handle_volume_mount");
+
ret = DBUS_HANDLER_RESULT_HANDLED;
+ sender = dbus_message_get_sender (message);
+
volume = NULL;
volumes = g_volume_monitor_get_volumes (monitor);
for (l = volumes; l != NULL; l = l->next)
@@ -548,20 +1014,45 @@
goto out;
}
+ if (g_object_get_data (G_OBJECT (volume), "cancellable") != NULL)
+ {
+ DBusMessage *reply;
+ reply = dbus_message_new_error (message,
+ "org.gtk.Private.RemoteVolumeMonitor.Failed",
+ "An operation is already pending");
+ 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 ();
+ if (mount_op_id != NULL && strlen (mount_op_id) > 0)
+ {
+ mount_operation = g_proxy_mount_operation_new ();
+ g_signal_connect (mount_operation, "ask-password", G_CALLBACK (ask_password_cb), volume);
+ g_signal_connect (mount_operation, "ask-question", G_CALLBACK (ask_question_cb), volume);
+ g_signal_connect (mount_operation, "aborted", G_CALLBACK (aborted_cb), volume);
+ g_object_set_data_full (G_OBJECT (mount_operation), "mount_op_id", g_strdup (mount_op_id), g_free);
+ g_object_set_data_full (G_OBJECT (mount_operation), "mount_op_owner", g_strdup (sender), g_free);
+ g_object_set_data_full (G_OBJECT (volume), "mount_operation", mount_operation, g_object_unref);
+ }
+
+ cancellable = g_cancellable_new ();
+ g_object_set_data_full (G_OBJECT (volume), "cancellable", cancellable, g_object_unref);
+ g_object_set_data_full (G_OBJECT (cancellable), "owner", g_strdup (sender), g_free);
+ g_object_set_data_full (G_OBJECT (cancellable), "cancellation_id", g_strdup (cancellation_id), g_free);
+ outstanding_ops = g_list_prepend (outstanding_ops, cancellable);
+ g_object_weak_ref (G_OBJECT (cancellable),
+ cancellable_destroyed_cb,
+ NULL);
g_volume_mount (volume,
mount_flags,
mount_operation,
- NULL,
+ cancellable,
(GAsyncReadyCallback) volume_mount_cb,
dbus_message_ref (message));
- if (mount_operation != NULL)
- g_object_unref (mount_operation);
-
out:
if (volumes != NULL)
{
@@ -579,14 +1070,20 @@
GError *error;
DBusMessage *reply;
+ print_debug ("in drive_eject_cb");
+
+ g_object_set_data (G_OBJECT (drive), "cancellable", NULL);
+
error = NULL;
if (!g_drive_eject_finish (drive, result, &error))
{
+ print_debug (" error: %s", error->message);
reply = _dbus_message_new_from_gerror (message, error);
g_error_free (error);
}
else
{
+ print_debug (" success");
reply = dbus_message_new_method_return (message);
}
@@ -599,6 +1096,9 @@
handle_drive_eject (DBusConnection *connection, DBusMessage *message)
{
const char *id;
+ const char *cancellation_id;
+ const char *sender;
+ GCancellable *cancellable;
dbus_uint32_t unmount_flags;
DBusError dbus_error;
GList *drives, *l;
@@ -606,12 +1106,14 @@
DBusHandlerResult ret;
drive = NULL;
+ drives = 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_STRING, &cancellation_id,
DBUS_TYPE_UINT32 &unmount_flags,
DBUS_TYPE_INVALID))
{
@@ -620,8 +1122,12 @@
goto out;
}
+ print_debug ("in handle_drive_eject");
+
ret = DBUS_HANDLER_RESULT_HANDLED;
+ sender = dbus_message_get_sender (message);
+
drive = NULL;
drives = g_volume_monitor_get_connected_drives (monitor);
for (l = drives; l != NULL; l = l->next)
@@ -649,9 +1155,29 @@
goto out;
}
+ if (g_object_get_data (G_OBJECT (drive), "cancellable") != NULL)
+ {
+ DBusMessage *reply;
+ reply = dbus_message_new_error (message,
+ "org.gtk.Private.RemoteVolumeMonitor.Failed",
+ "An operation is already pending");
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ goto out;
+ }
+
+ cancellable = g_cancellable_new ();
+ g_object_set_data_full (G_OBJECT (drive), "cancellable", cancellable, g_object_unref);
+ g_object_set_data_full (G_OBJECT (cancellable), "owner", g_strdup (sender), g_free);
+ g_object_set_data_full (G_OBJECT (cancellable), "cancellation_id", g_strdup (cancellation_id), g_free);
+ outstanding_ops = g_list_prepend (outstanding_ops, cancellable);
+ g_object_weak_ref (G_OBJECT (cancellable),
+ cancellable_destroyed_cb,
+ NULL);
+
g_drive_eject (drive,
unmount_flags,
- NULL,
+ cancellable,
(GAsyncReadyCallback) drive_eject_cb,
dbus_message_ref (message));
@@ -672,14 +1198,20 @@
GError *error;
DBusMessage *reply;
+ print_debug ("in drive_poll_for_media_cb");
+
+ g_object_set_data (G_OBJECT (drive), "cancellable", NULL);
+
error = NULL;
if (!g_drive_poll_for_media_finish (drive, result, &error))
{
+ print_debug (" error: %s", error->message);
reply = _dbus_message_new_from_gerror (message, error);
g_error_free (error);
}
else
{
+ print_debug (" success");
reply = dbus_message_new_method_return (message);
}
@@ -692,17 +1224,22 @@
handle_drive_poll_for_media (DBusConnection *connection, DBusMessage *message)
{
const char *id;
+ const char *cancellation_id;
+ const char *sender;
+ GCancellable *cancellable;
DBusError dbus_error;
GList *drives, *l;
GDrive *drive;
DBusHandlerResult ret;
drive = NULL;
+ drives = 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_STRING, &cancellation_id,
DBUS_TYPE_INVALID))
{
g_warning ("Error parsing args for DrivePollForMedia(): %s: %s", dbus_error.name, dbus_error.message);
@@ -710,8 +1247,12 @@
goto out;
}
+ print_debug ("in handle_drive_poll_for_media");
+
ret = DBUS_HANDLER_RESULT_HANDLED;
+ sender = dbus_message_get_sender (message);
+
drive = NULL;
drives = g_volume_monitor_get_connected_drives (monitor);
for (l = drives; l != NULL; l = l->next)
@@ -739,8 +1280,28 @@
goto out;
}
+ if (g_object_get_data (G_OBJECT (drive), "cancellable") != NULL)
+ {
+ DBusMessage *reply;
+ reply = dbus_message_new_error (message,
+ "org.gtk.Private.RemoteVolumeMonitor.Failed",
+ "An operation is already pending");
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ goto out;
+ }
+
+ cancellable = g_cancellable_new ();
+ g_object_set_data_full (G_OBJECT (drive), "cancellable", cancellable, g_object_unref);
+ g_object_set_data_full (G_OBJECT (cancellable), "owner", g_strdup (sender), g_free);
+ g_object_set_data_full (G_OBJECT (cancellable), "cancellation_id", g_strdup (cancellation_id), g_free);
+ outstanding_ops = g_list_prepend (outstanding_ops, cancellable);
+ g_object_weak_ref (G_OBJECT (cancellable),
+ cancellable_destroyed_cb,
+ NULL);
+
g_drive_poll_for_media (drive,
- NULL,
+ cancellable,
(GAsyncReadyCallback) drive_poll_for_media_cb,
dbus_message_ref (message));
@@ -762,6 +1323,8 @@
DBusMessage *reply;
DBusMessageIter iter;
+ print_debug ("in handle_supported");
+
/* if monitor wasn't created on startup; try again */
if (monitor == NULL)
monitor_try_create ();
@@ -780,40 +1343,157 @@
/* ---------------------------------------------------------------------------------------------------- */
static DBusHandlerResult
+handle_cancel_operation (DBusConnection *connection, DBusMessage *message)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusError dbus_error;
+ dbus_bool_t was_cancelled;
+ const char *sender;
+ const char *cancellation_id;
+ GList *l;
+
+ was_cancelled = FALSE;
+
+ sender = dbus_message_get_sender (message);
+
+ dbus_error_init (&dbus_error);
+ if (!dbus_message_get_args (message, &dbus_error,
+ DBUS_TYPE_STRING, &cancellation_id,
+ DBUS_TYPE_INVALID))
+ {
+ g_warning ("Error parsing args for CancelOperation(): %s: %s", dbus_error.name, dbus_error.message);
+ dbus_error_free (&dbus_error);
+ goto out;
+ }
+
+ print_debug ("in handle_cancel_operation");
+
+ /* Find GCancellable to cancel */
+ for (l = outstanding_ops; l != NULL; l = l->next)
+ {
+ GCancellable *cancellable = G_CANCELLABLE (l->data);
+ const gchar *owner;
+ const gchar *id;
+
+ owner = g_object_get_data (G_OBJECT (cancellable), "owner");
+ id = g_object_get_data (G_OBJECT (cancellable), "cancellation_id");
+ if (g_strcmp0 (owner, sender) == 0 && g_strcmp0 (id, cancellation_id) == 0)
+ {
+ print_debug ("found op to cancel");
+ g_cancellable_cancel (cancellable);
+
+ was_cancelled = TRUE;
+ break;
+ }
+ }
+
+ if (!was_cancelled)
+ g_warning ("didn't find op to cancel");
+
+ out:
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &was_cancelled);
+ 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)
+ if (dbus_message_is_signal (message, "org.freedesktop.DBus", "NameLost"))
{
- ret = handle_is_supported (connection, message);
+ /* means that someone has claimed our name (we allow replacement) */
+ g_warning ("Got NameLost, some other instance replaced us");
+ exit (0);
+ }
+ else if (dbus_message_is_signal (message, "org.freedesktop.DBus", "NameOwnerChanged"))
+ {
+ DBusMessageIter iter;
+ const gchar *name;
+ const gchar *old_owner;
+ const gchar *new_owner;
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_get_basic (&iter, &name);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &old_owner);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &new_owner);
+ dbus_message_iter_next (&iter);
+
+ print_debug ("NameOwnerChanged: '%s' '%s' '%s'", name, old_owner, new_owner);
+
+ if (strlen (new_owner) == 0)
+ {
+ GList *l;
+
+ /* see if @name has outstanding ops; if so, cancel them */
+ for (l = outstanding_ops; l != NULL; l = l->next)
+ {
+ GCancellable *cancellable = G_CANCELLABLE (l->data);
+ const gchar *owner;
+
+ owner = g_object_get_data (G_OBJECT (cancellable), "owner");
+ print_debug ("looking at op for %s", owner);
+ if (g_strcmp0 (owner, name) == 0)
+ {
+ print_debug ("****** name has an outstanding op");
+ g_cancellable_cancel (cancellable);
+ }
+ }
+
+ remove_name_owned_changed_for_unique_name (name);
+ }
+
}
- else
+ else if (g_strcmp0 (dbus_message_get_interface (message), "org.gtk.Private.RemoteVolumeMonitor") == 0 &&
+ g_strcmp0 (dbus_message_get_path (message), "/org/gtk/Private/RemoteVolumeMonitor") == 0)
{
- if (monitor != NULL)
+ /* If someone is calling into this object and interface, start watching their name so
+ * we can cancel operations initiated by them when they disconnect
+ */
+ ensure_name_owner_changed_for_unique_name (dbus_message_get_sender (message));
+
+ if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "IsSupported"))
+ {
+ ret = handle_is_supported (connection, message);
+ }
+ else
{
- 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);
+ if (monitor != NULL)
+ {
+ if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "List"))
+ ret = handle_list (connection, message);
+
+ else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "CancelOperation"))
+ ret = handle_cancel_operation (connection, message);
+
+ else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "MountUnmount"))
+ ret = handle_mount_unmount (connection, message);
+
+ else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "MountOpReply"))
+ ret = handle_mount_op_reply (connection, message);
+
+ else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "VolumeMount"))
+ ret = handle_volume_mount (connection, message);
+
+ else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "DriveEject"))
+ ret = handle_drive_eject (connection, message);
+
+ else if (dbus_message_is_method_call (message, "org.gtk.Private.RemoteVolumeMonitor", "DrivePollForMedia"))
+ ret = handle_drive_poll_for_media (connection, message);
+
+ }
}
}
@@ -831,7 +1511,9 @@
id = g_strdup_printf ("%p", object);
- message = dbus_message_new_signal ("/", "org.gtk.Private.RemoteVolumeMonitor", signal_name);
+ message = dbus_message_new_signal ("/org/gtk/Private/RemoteVolumeMonitor",
+ "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);
@@ -1006,6 +1688,7 @@
the_volume_monitor_type = volume_monitor_type;
the_dbus_name = dbus_name;
+ unique_names_being_watched = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
/* try and create the monitor */
monitor_try_create ();
@@ -1021,7 +1704,12 @@
_g_dbus_connection_integrate_with_main (connection);
- rc = dbus_bus_request_name (connection, dbus_name, 0, &dbus_error);
+ rc = dbus_bus_request_name (connection,
+ dbus_name,
+ DBUS_NAME_FLAG_ALLOW_REPLACEMENT |
+ DBUS_NAME_FLAG_DO_NOT_QUEUE |
+ DBUS_NAME_FLAG_REPLACE_EXISTING,
+ &dbus_error);
if (dbus_error_is_set (&dbus_error))
{
g_warning ("dbus_bus_request_name failed: %s: %s", dbus_error.name, dbus_error.message);
Modified: trunk/monitor/proxy/remote-volume-monitor-module.c
==============================================================================
--- trunk/monitor/proxy/remote-volume-monitor-module.c (original)
+++ trunk/monitor/proxy/remote-volume-monitor-module.c Thu Feb 26 18:17:52 2009
@@ -41,6 +41,15 @@
if (g_getenv ("GVFS_REMOTE_VOLUME_MONITOR_IGNORE") != NULL)
goto out;
+ /* We make this module resident since we *may* hold on to an instance
+ * of the union monitor in the static method get_mount_for_mount_path()
+ * on GNativeVolumeMonitor. And it doesn't make much sense to unload
+ * the module *anyway*.
+ *
+ * See the comment gproxyvolumemonitor.c:get_mount_for_mount_path().
+ */
+ g_type_module_use (G_TYPE_MODULE (module));
+
bindtextdomain (GETTEXT_PACKAGE, GVFS_LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]