Signed-off-by: Hans de Goede <hdego...@redhat.com> --- gtk/channel-usbredir.c | 82 ++++++++++++++++++++++++++++++++++++++++++++- gtk/channel-usbredir.h | 4 ++ gtk/spicy.c | 2 + gtk/usb-device-manager.c | 37 +++++++++++++++++++++ gtk/usb-device-manager.h | 4 ++- gtk/usb-device-widget.c | 21 ++++++++++++ 6 files changed, 147 insertions(+), 3 deletions(-)
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c index e22aa6c..3b72372 100644 --- a/gtk/channel-usbredir.c +++ b/gtk/channel-usbredir.c @@ -33,6 +33,7 @@ #include "spice-client.h" #include "spice-common.h" +#include "spice-marshal.h" #include "spice-channel-priv.h" #include "glib-compat.h" @@ -98,6 +99,13 @@ static void usbredir_free_lock(void *user_data); G_DEFINE_TYPE(SpiceUsbredirChannel, spice_usbredir_channel, SPICE_TYPE_CHANNEL) +/* Signals */ +enum { + DEVICE_ERROR, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL]; /* ------------------------------------------------------------------ */ static void spice_usbredir_channel_init(SpiceUsbredirChannel *channel) @@ -128,6 +136,27 @@ static void spice_usbredir_channel_class_init(SpiceUsbredirChannelClass *klass) g_type_class_add_private(klass, sizeof(SpiceUsbredirChannelPrivate)); #endif + /** + * SpiceUsbredirChannel::device-error: + * @channel: #SpiceUsbredirChannel that emitted the signal + * @device: #SpiceUsbDevice boxed object corresponding to the device which has an error + * @error: #GError describing the error + * + * The #SpiceUsbredirChannel::device-error signal is emitted whenever an + * error happens which causes a device to no longer be available to the + * guest. + **/ + signals[DEVICE_ERROR] = + g_signal_new("device-error", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SpiceUsbredirChannelClass, device_error), + NULL, NULL, + g_cclosure_user_marshal_VOID__BOXED_BOXED, + G_TYPE_NONE, + 2, + SPICE_TYPE_USB_DEVICE, + G_TYPE_ERROR); } #ifdef USE_USBREDIR @@ -513,6 +542,34 @@ static void usbredir_free_lock(void *user_data) { } /* --------------------------------------------------------------------- */ +struct DEVICE_ERROR { + libusb_device *device; + GError *error; +}; + +/* main context */ +static void do_emit_main_context(GObject *object, int signum, gpointer params) +{ + SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(object); + SpiceUsbredirChannelPrivate *priv = channel->priv; + + switch (signum) { + case DEVICE_ERROR: { + struct DEVICE_ERROR *p = params; + /* Check that the device has not changed before we manage to run */ + if (p->device == priv->device) { + g_signal_emit(object, signals[DEVICE_ERROR], 0, + p->device, p->error); + spice_usbredir_channel_disconnect_device(channel); + } + break; + } + default: + g_warn_if_reached(); + } +} + +/* --------------------------------------------------------------------- */ /* coroutine context */ static void spice_usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *msg) { @@ -544,7 +601,7 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in) { SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(c); SpiceUsbredirChannelPrivate *priv = channel->priv; - int size; + int r, size; uint8_t *buf; g_return_if_fail(priv->host != NULL); @@ -556,7 +613,28 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in) priv->read_buf = buf; priv->read_buf_size = size; - usbredirhost_read_guest_data(priv->host); + r = usbredirhost_read_guest_data(priv->host); + if (r == usbredirhost_read_device_rejected) { + libusb_device *device = priv->device; + gchar *desc; + GError *err; + + g_return_if_fail(device != NULL); + + desc = spice_usb_device_get_description((SpiceUsbDevice *)device, + NULL); + err = g_error_new(SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, + "%s rejected by host", desc); + g_free(desc); + + SPICE_DEBUG("%s", err->message); + + g_boxed_copy(spice_usb_device_get_type(), device); + emit_main_context(channel, DEVICE_ERROR, device, err); + g_boxed_free(spice_usb_device_get_type(), device); + + g_error_free(err); + } } #endif /* USE_USBREDIR */ diff --git a/gtk/channel-usbredir.h b/gtk/channel-usbredir.h index c7263b9..9fe4c32 100644 --- a/gtk/channel-usbredir.h +++ b/gtk/channel-usbredir.h @@ -36,6 +36,8 @@ typedef struct _SpiceUsbredirChannel SpiceUsbredirChannel; typedef struct _SpiceUsbredirChannelClass SpiceUsbredirChannelClass; typedef struct _SpiceUsbredirChannelPrivate SpiceUsbredirChannelPrivate; +typedef struct _SpiceUsbDevice SpiceUsbDevice; + /** * SpiceUsbredirChannel: * @parent: Parent instance. @@ -60,6 +62,8 @@ struct _SpiceUsbredirChannelClass { SpiceChannelClass parent_class; /* signals */ + void (*device_error) (SpiceUsbredirChannel *channel, + SpiceUsbDevice *device, GError *error); /*< private >*/ /* Do not add fields to this struct */ diff --git a/gtk/spicy.c b/gtk/spicy.c index 2757bd7..40b724e 100644 --- a/gtk/spicy.c +++ b/gtk/spicy.c @@ -1573,6 +1573,8 @@ static spice_connection *connection_new(void) if (manager) { g_signal_connect(manager, "auto-connect-failed", G_CALLBACK(usb_connect_failed), NULL); + g_signal_connect(manager, "device-error", + G_CALLBACK(usb_connect_failed), NULL); } connections++; diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c index b6dfa20..cc67131 100644 --- a/gtk/usb-device-manager.c +++ b/gtk/usb-device-manager.c @@ -85,6 +85,7 @@ enum DEVICE_ADDED, DEVICE_REMOVED, AUTO_CONNECT_FAILED, + DEVICE_ERROR, LAST_SIGNAL, }; @@ -433,6 +434,28 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas SPICE_TYPE_USB_DEVICE, G_TYPE_ERROR); + /** + * SpiceUsbDeviceManager::device-error: + * @manager: #SpiceUsbDeviceManager that emitted the signal + * @device: #SpiceUsbDevice boxed object corresponding to the device which has an error + * @error: #GError describing the error + * + * The #SpiceUsbDeviceManager::device-error signal is emitted whenever an + * error happens which causes a device to no longer be available to the + * guest. + **/ + signals[DEVICE_ERROR] = + g_signal_new("device-error", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SpiceUsbDeviceManagerClass, device_error), + NULL, NULL, + g_cclosure_user_marshal_VOID__BOXED_BOXED, + G_TYPE_NONE, + 2, + SPICE_TYPE_USB_DEVICE, + G_TYPE_ERROR); + g_type_class_add_private(klass, sizeof(SpiceUsbDeviceManagerPrivate)); } @@ -461,6 +484,18 @@ static gboolean spice_usb_device_manager_get_udev_bus_n_address( /* ------------------------------------------------------------------ */ /* callbacks */ +#ifdef USE_USBREDIR +static void channel_device_error(GObject *object, + SpiceUsbDevice *device, + GError *err, + gpointer user_data) +{ + SpiceUsbDeviceManager *self = user_data; + + g_signal_emit(self, signals[DEVICE_ERROR], 0, device, err); +} +#endif + static void channel_new(SpiceSession *session, SpiceChannel *channel, gpointer user_data) { @@ -468,6 +503,8 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel, if (SPICE_IS_USBREDIR_CHANNEL(channel)) { #ifdef USE_USBREDIR + g_signal_connect(channel, "device-error", + G_CALLBACK(channel_device_error), self); spice_usbredir_channel_set_context(SPICE_USBREDIR_CHANNEL(channel), self->priv->context); spice_channel_connect(channel); diff --git a/gtk/usb-device-manager.h b/gtk/usb-device-manager.h index ec1a896..eabfd00 100644 --- a/gtk/usb-device-manager.h +++ b/gtk/usb-device-manager.h @@ -76,12 +76,14 @@ struct _SpiceUsbDeviceManagerClass SpiceUsbDevice *device); void (*auto_connect_failed) (SpiceUsbDeviceManager *manager, SpiceUsbDevice *device, GError *error); + void (*device_error) (SpiceUsbDeviceManager *manager, + SpiceUsbDevice *device, GError *error); /*< private >*/ /* * If adding fields to this struct, remove corresponding * amount of padding to avoid changing overall struct size */ - gchar _spice_reserved[SPICE_RESERVED_PADDING]; + gchar _spice_reserved[SPICE_RESERVED_PADDING - sizeof(void*)]; }; GType spice_usb_device_get_type(void); diff --git a/gtk/usb-device-widget.c b/gtk/usb-device-widget.c index 028723f..4b504ca 100644 --- a/gtk/usb-device-widget.c +++ b/gtk/usb-device-widget.c @@ -45,6 +45,8 @@ static void device_added_cb(SpiceUsbDeviceManager *manager, SpiceUsbDevice *device, gpointer user_data); static void device_removed_cb(SpiceUsbDeviceManager *manager, SpiceUsbDevice *device, gpointer user_data); +static void device_error_cb(SpiceUsbDeviceManager *manager, + SpiceUsbDevice *device, GError *err, gpointer user_data); /* ------------------------------------------------------------------ */ /* gobject glue */ @@ -156,6 +158,8 @@ static GObject *spice_usb_device_widget_constructor( G_CALLBACK(device_added_cb), self); g_signal_connect(priv->manager, "device-removed", G_CALLBACK(device_removed_cb), self); + g_signal_connect(priv->manager, "device-error", + G_CALLBACK(device_error_cb), self); devices = spice_usb_device_manager_get_devices(priv->manager); } else err_msg = err->message; @@ -189,6 +193,8 @@ static void spice_usb_device_widget_finalize(GObject *object) device_added_cb, self); g_signal_handlers_disconnect_by_func(priv->manager, device_removed_cb, self); + g_signal_handlers_disconnect_by_func(priv->manager, + device_error_cb, self); } g_object_unref(priv->session); g_free(priv->device_format_string); @@ -392,3 +398,18 @@ static void device_removed_cb(SpiceUsbDeviceManager *manager, gtk_container_foreach(GTK_CONTAINER(self), destroy_widget_by_usb_device, device); } + +static void set_inactive_by_usb_device(GtkWidget *widget, gpointer user_data) +{ + if (g_object_get_data(G_OBJECT(widget), "usb-device") == user_data) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE); +} + +static void device_error_cb(SpiceUsbDeviceManager *manager, + SpiceUsbDevice *device, GError *err, gpointer user_data) +{ + SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data); + + gtk_container_foreach(GTK_CONTAINER(self), + set_inactive_by_usb_device, device); +} -- 1.7.7.5 _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel