[Spice-devel] [PATCH spice-gtk 5/8] usb-device-manager: Make spice_usb_device_manager_connect_device async

Hans de Goede hdegoede at redhat.com
Wed Nov 16 09:49:48 PST 2011


With the (upcoming) introduction of the usb device node acl helper, which
uses policykit, spice_usbredir_channel_connect() may take a long time as
it will be waiting for the helper, which will be waiting for policykit which
may be interacting with the user. So spice_usbredir_channel_connect() will
need to become async, and since spice_usb_device_manager_connect_device
calls spice_usbredir_channel_connect it thus also needs to become async.

Note that this patch only changes spice_usb_device_manager_connect_device's
API to use the standard GIO async API, it is not actually async after this
patch since spice_usbredir_channel_connect is not yet async.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 gtk/Makefile.am                 |    2 +-
 gtk/map-file                    |    3 +-
 gtk/usb-device-manager.c        |  110 ++++++++++++++++++++++++++++-----------
 gtk/usb-device-manager.h        |   13 ++++-
 vapi/Makefile.am                |    1 +
 vapi/spice-client-glib-2.0.deps |    1 +
 6 files changed, 94 insertions(+), 36 deletions(-)
 create mode 100644 vapi/spice-client-glib-2.0.deps

diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index a3960a7..17efc89 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -571,7 +571,7 @@ gtk_introspection_files =			\
 	$(NULL)
 
 SpiceClientGLib-2.0.gir: libspice-client-glib-2.0.la
-SpiceClientGLib_2_0_gir_INCLUDES = GObject-2.0
+SpiceClientGLib_2_0_gir_INCLUDES = GObject-2.0 Gio-2.0
 SpiceClientGLib_2_0_gir_CFLAGS = $(SPICE_COMMON_CPPFLAGS)
 SpiceClientGLib_2_0_gir_LIBS = libspice-client-glib-2.0.la
 SpiceClientGLib_2_0_gir_FILES = $(glib_introspection_files)
diff --git a/gtk/map-file b/gtk/map-file
index f9bc46c..b6b84f1 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -87,7 +87,8 @@ spice_usb_device_manager_get_type;
 spice_usb_device_manager_get;
 spice_usb_device_manager_get_devices;
 spice_usb_device_manager_is_device_connected;
-spice_usb_device_manager_connect_device;
+spice_usb_device_manager_connect_device_async;
+spice_usb_device_manager_connect_device_finish;
 spice_usb_device_manager_disconnect_device;
 spice_util_get_debug;
 spice_util_get_version_string;
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 2fb3dbb..9b02066 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -22,7 +22,6 @@
 #include "config.h"
 
 #include <glib-object.h>
-#include <gio/gio.h> /* For GInitable */
 
 #include "glib-compat.h"
 
@@ -424,6 +423,27 @@ static gboolean spice_usb_device_manager_source_callback(gpointer user_data)
     return TRUE;
 }
 
+static void spice_usb_device_manager_auto_connect_cb(GObject      *gobject,
+                                                     GAsyncResult *res,
+                                                     gpointer      user_data)
+{
+    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
+    SpiceUsbDevice *device = user_data;
+    GError *err = NULL;
+
+    spice_usb_device_manager_connect_device_finish(self, res, &err);
+    if (err) {
+        gchar *desc = spice_usb_device_get_description(device);
+        g_prefix_error(&err, "Could not auto-redirect %s: ", desc);
+        g_free(desc);
+
+        g_warning("%s", err->message);
+        g_signal_emit(self, signals[AUTO_CONNECT_FAILED], 0, device, err);
+        g_error_free(err);
+    }
+    g_object_unref(device);
+}
+
 static void spice_usb_device_manager_dev_added(GUsbDeviceList *devlist,
                                                GUsbDevice     *_device,
                                                GUdevDevice    *udev,
@@ -436,17 +456,9 @@ static void spice_usb_device_manager_dev_added(GUsbDeviceList *devlist,
     g_ptr_array_add(priv->devices, g_object_ref(device));
 
     if (priv->auto_connect) {
-        GError *err = NULL;
-        spice_usb_device_manager_connect_device(manager, device, &err);
-        if (err) {
-            gchar *desc = spice_usb_device_get_description(device);
-            g_prefix_error(&err, "Could not auto-redirect %s: ", desc);
-            g_free(desc);
-
-            g_warning("%s", err->message);
-            g_signal_emit(manager, signals[AUTO_CONNECT_FAILED], 0, device, err);
-            g_error_free(err);
-        }
+        spice_usb_device_manager_connect_device_async(manager, device, NULL,
+                                   spice_usb_device_manager_auto_connect_cb,
+                                   g_object_ref(device));
     }
 
     SPICE_DEBUG("device added %p", device);
@@ -570,36 +582,47 @@ gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *sel
 }
 
 /**
- * spice_usb_device_manager_connect_device:
+ * spice_usb_device_manager_connect_device_async:
  * @manager: the #SpiceUsbDeviceManager manager
  * @device: a #SpiceUsbDevice to redirect
- *
- * Returns: %TRUE if @device has been successfully connected and
- * associated with a redirection chanel
+ * @cancellable: a #GCancellable or NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to callback
  */
-gboolean spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *self,
-                                                 SpiceUsbDevice *device, GError **err)
+void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
+                                             SpiceUsbDevice *device,
+                                             GCancellable *cancellable,
+                                             GAsyncReadyCallback callback,
+                                             gpointer user_data)
 {
-    g_return_val_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self), FALSE);
-    g_return_val_if_fail(device != NULL, FALSE);
-    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+    GSimpleAsyncResult *result;
+
+    g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
+    g_return_if_fail(device != NULL);
 
     SPICE_DEBUG("connecting device %p", device);
 
+    result = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
+                               spice_usb_device_manager_connect_device_async);
+
 #ifdef USE_USBREDIR
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
+    GError *e = NULL;
     guint i;
 
     if (spice_usb_device_manager_is_device_connected(self, device)) {
-        g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+        g_simple_async_result_set_error(result,
+                            SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
                             "Cannot connect an already connected usb device");
-        return FALSE;
+        goto done;
     }
 
     if (!priv->source) {
-        priv->source = g_usb_source_new(priv->main_context, priv->context, err);
-        if (*err)
-            return FALSE;
+        priv->source = g_usb_source_new(priv->main_context, priv->context, &e);
+        if (e) {
+            g_simple_async_result_take_error(result, e);
+            goto done;
+        }
 
         g_usb_source_set_callback(priv->source,
                                   spice_usb_device_manager_source_callback,
@@ -612,14 +635,39 @@ gboolean spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *self,
         if (spice_usbredir_channel_get_device(channel))
             continue; /* Skip already used channels */
 
-        return spice_usbredir_channel_connect(channel, priv->context,
-                                              (GUsbDevice *)device, err);
+        if (!spice_usbredir_channel_connect(channel, priv->context,
+                                            (GUsbDevice *)device, &e)) {
+            g_simple_async_result_take_error(result, e);
+            goto done;
+        }
+
+        goto done;
     }
 #endif
 
-    g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
-                        "No free USB channel");
-    return FALSE;
+    g_simple_async_result_set_error(result,
+                            SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            "No free USB channel");
+#ifdef USE_USBREDIR
+done:
+#endif
+    g_simple_async_result_complete_in_idle(result);
+    g_object_unref(result);
+}
+
+gboolean spice_usb_device_manager_connect_device_finish(
+    SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err)
+{
+    GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+    g_return_val_if_fail(g_simple_async_result_is_valid(res, G_OBJECT(self),
+                               spice_usb_device_manager_connect_device_async),
+                         FALSE);
+
+    if (g_simple_async_result_propagate_error(simple, err))
+        return FALSE;
+
+    return TRUE;
 }
 
 /**
diff --git a/gtk/usb-device-manager.h b/gtk/usb-device-manager.h
index 00f8eb2..2417674 100644
--- a/gtk/usb-device-manager.h
+++ b/gtk/usb-device-manager.h
@@ -22,6 +22,7 @@
 #define __SPICE_USB_DEVICE_MANAGER_H__
 
 #include "spice-client.h"
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
@@ -96,9 +97,15 @@ GPtrArray *spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *manager);
 
 gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *manager,
                                                       SpiceUsbDevice *device);
-gboolean spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *manager,
-                                                 SpiceUsbDevice *device,
-                                                 GError **err);
+void spice_usb_device_manager_connect_device_async(
+                                             SpiceUsbDeviceManager *manager,
+                                             SpiceUsbDevice *device,
+                                             GCancellable *cancellable,
+                                             GAsyncReadyCallback callback,
+                                             gpointer user_data);
+gboolean spice_usb_device_manager_connect_device_finish(
+    SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err);
+
 void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *manager,
                                                 SpiceUsbDevice *device);
 
diff --git a/vapi/Makefile.am b/vapi/Makefile.am
index 87ffb8a..49f8509 100644
--- a/vapi/Makefile.am
+++ b/vapi/Makefile.am
@@ -4,6 +4,7 @@ if WITH_VALA
 vapidir = $(datadir)/vala/vapi
 vapi_DATA =						\
 	spice-client-glib-2.0.vapi			\
+	spice-client-glib-2.0.deps			\
 	spice-client-gtk-$(SPICE_GTK_API_VERSION).deps	\
 	spice-client-gtk-$(SPICE_GTK_API_VERSION).vapi	\
 	$(NULL)
diff --git a/vapi/spice-client-glib-2.0.deps b/vapi/spice-client-glib-2.0.deps
new file mode 100644
index 0000000..cd10dfd
--- /dev/null
+++ b/vapi/spice-client-glib-2.0.deps
@@ -0,0 +1 @@
+gio-2.0
-- 
1.7.7.3



More information about the Spice-devel mailing list