[Spice-commits] 6 commits - configure.ac gtk/channel-usbredir-priv.h gtk/channel-usbredir.c gtk/map-file gtk/spice-client-glib-usb-acl-helper.c gtk/spicy.c gtk/usb-acl-helper.c gtk/usb-device-manager-priv.h gtk/usb-device-manager.c gtk/usb-device-manager.h gtk/usb-device-widget.c

Hans de Goede jwrdegoede at kemper.freedesktop.org
Thu Feb 23 00:14:22 PST 2012


 configure.ac                           |    6 -
 gtk/channel-usbredir-priv.h            |    6 +
 gtk/channel-usbredir.c                 |   80 ++++++++++++-
 gtk/map-file                           |    1 
 gtk/spice-client-glib-usb-acl-helper.c |    5 
 gtk/spicy.c                            |    7 +
 gtk/usb-acl-helper.c                   |   13 +-
 gtk/usb-device-manager-priv.h          |    3 
 gtk/usb-device-manager.c               |  116 ++++++++++++++++++-
 gtk/usb-device-manager.h               |    9 +
 gtk/usb-device-widget.c                |  196 +++++++++++++++++++++++++++------
 11 files changed, 390 insertions(+), 52 deletions(-)

New commits:
commit 2e4a9c91849f93d9a09e3bffedadc30e667455f9
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sun Feb 19 00:29:39 2012 +0100

    usbredir: Add awareness of host/guest side filtering
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/configure.ac b/configure.ac
index bf9b4ed..6e8c8e3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -346,7 +346,7 @@ if test "x$enable_usbredir" = "xno"; then
   have_usbredir="no"
 else
   PKG_CHECK_MODULES([USBREDIR],
-                    [gudev-1.0 libusb-1.0 >= 1.0.9 libusbredirhost >= 0.3.4 libusbredirparser >= 0.3.4],
+                    [gudev-1.0 libusb-1.0 >= 1.0.9 libusbredirhost >= 0.4 libusbredirparser >= 0.4],
                     [have_usbredir=yes],
                     [have_usbredir=no])
   if test "x$have_usbredir" = "xno" && test "x$enable_usbredir" = "xyes"; then
diff --git a/gtk/channel-usbredir-priv.h b/gtk/channel-usbredir-priv.h
index 10dd479..5d28c79 100644
--- a/gtk/channel-usbredir-priv.h
+++ b/gtk/channel-usbredir-priv.h
@@ -22,6 +22,7 @@
 #define __SPICE_CLIENT_USBREDIR_CHANNEL_PRIV_H__
 
 #include <libusb.h>
+#include <usbredirfilter.h>
 #include "spice-client.h"
 
 G_BEGIN_DECLS
@@ -49,6 +50,11 @@ void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel);
 
 libusb_device *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel);
 
+void spice_usbredir_channel_get_guest_filter(
+                          SpiceUsbredirChannel               *channel,
+                          const struct usbredirfilter_rule  **rules_ret,
+                          int                                *rules_count_ret);
+
 G_END_DECLS
 
 #endif /* __SPICE_CLIENT_USBREDIR_CHANNEL_PRIV_H__ */
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index fa7dce0..eb81fe5 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -408,6 +408,22 @@ libusb_device *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel)
     return channel->priv->device;
 }
 
+G_GNUC_INTERNAL
+void spice_usbredir_channel_get_guest_filter(
+                          SpiceUsbredirChannel               *channel,
+                          const struct usbredirfilter_rule  **rules_ret,
+                          int                                *rules_count_ret)
+{
+    SpiceUsbredirChannelPrivate *priv = channel->priv;
+
+    g_return_if_fail(priv->host != NULL);
+
+    usbredirhost_get_guest_filter(priv->host, rules_ret, rules_count_ret);
+}
+
+/* ------------------------------------------------------------------ */
+/* callbacks (any context)                                            */
+
 /* Note that this function must be re-entrant safe, as it can get called
    from both the main thread as well as from the usb event handling thread */
 static void usbredir_write_flush_callback(void *user_data)
@@ -422,9 +438,6 @@ static void usbredir_write_flush_callback(void *user_data)
     usbredirhost_write_guest_data(priv->host);
 }
 
-/* ------------------------------------------------------------------ */
-/* callbacks (any context)                                            */
-
 static void usbredir_log(void *user_data, int level, const char *msg)
 {
     SpiceUsbredirChannel *channel = user_data;
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 959e0ab..37cc88b 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -921,8 +921,9 @@ spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager  *self,
                                              GError                **err)
 {
 #ifdef USE_USBREDIR
+    const struct usbredirfilter_rule *guest_filter_rules = NULL;
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
-    int i;
+    int i, guest_filter_rules_count;
     gboolean enabled;
 
     g_return_val_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self), FALSE);
@@ -946,6 +947,21 @@ spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager  *self,
     if (spice_usb_device_manager_is_device_connected(self, device))
         return TRUE;
 
+    /* We assume all channels have the same filter, so we just take the
+       filter from the first channel */
+    spice_usbredir_channel_get_guest_filter(
+        g_ptr_array_index(priv->channels, 0),
+        &guest_filter_rules, &guest_filter_rules_count);
+
+    if (guest_filter_rules &&
+            usbredirhost_check_device_filter(
+                            guest_filter_rules, guest_filter_rules_count,
+                            (libusb_device *)device, 0) != 0) {
+        g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            _("Some USB devices are blocked by host policy"));
+        return FALSE;
+    }
+
     /* Check if there are free channels */
     for (i = 0; i < priv->channels->len; i++) {
         SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);
commit e84b55a675bd5c25173194e4ee2518d9412d42f0
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Feb 21 11:50:03 2012 +0100

    usbredir: Add a spice_usb_device_manager_can_redirect_device function
    
    Add a spice_usb_device_manager_can_redirect_device function and use this
    in SpiceUsbDeviceWidget to check if redirection is available.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/map-file b/gtk/map-file
index 320dae3..81cd682 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -85,6 +85,7 @@ spice_smartcard_reader_get_type;
 spice_smartcard_reader_is_software;
 spice_usb_device_get_description;
 spice_usb_device_get_type;
+spice_usb_device_manager_can_redirect_device;
 spice_usb_device_manager_connect_device_async;
 spice_usb_device_manager_connect_device_finish;
 spice_usb_device_manager_disconnect_device;
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index dea0ab5..959e0ab 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -212,7 +212,7 @@ static gboolean spice_usb_device_manager_initable_init(GInitable  *initable,
     return TRUE;
 #else
     g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
-                        "USB redirection support not compiled in");
+                        _("USB redirection support not compiled in"));
     return FALSE;
 #endif
 }
@@ -578,10 +578,17 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager  *self,
     g_ptr_array_add(priv->devices, device);
 
     if (priv->auto_connect) {
-        if (usbredirhost_check_device_filter(
-                priv->auto_conn_filter_rules,
-                priv->auto_conn_filter_rules_count,
-                device, 0) == 0)
+        gboolean can_redirect, auto_ok;
+
+        can_redirect = spice_usb_device_manager_can_redirect_device(
+                                        self, (SpiceUsbDevice *)device, NULL);
+
+        auto_ok = usbredirhost_check_device_filter(
+                            priv->auto_conn_filter_rules,
+                            priv->auto_conn_filter_rules_count,
+                            device, 0) == 0;
+
+        if (can_redirect && auto_ok)
             spice_usb_device_manager_connect_device_async(self,
                                    (SpiceUsbDevice *)device, NULL,
                                    spice_usb_device_manager_auto_connect_cb,
@@ -861,7 +868,7 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
 
     g_simple_async_result_set_error(result,
                             SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
-                            "No free USB channel");
+                            _("No free USB channel"));
 #ifdef USE_USBREDIR
 done:
 #endif
@@ -908,6 +915,58 @@ void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,
 #endif
 }
 
+gboolean
+spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager  *self,
+                                             SpiceUsbDevice         *device,
+                                             GError                **err)
+{
+#ifdef USE_USBREDIR
+    SpiceUsbDeviceManagerPrivate *priv = self->priv;
+    int i;
+    gboolean enabled;
+
+    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);
+
+    g_object_get(G_OBJECT(priv->session), "enable-usbredir", &enabled, NULL);
+    if (!enabled) {
+        g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            _("USB redirection is disabled"));
+        return FALSE;
+    }
+
+    if (!priv->channels->len) {
+        g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            _("The connected VM is not configured for USB redirection"));
+        return FALSE;
+    }
+
+    /* Skip the other checks for already connected devices */
+    if (spice_usb_device_manager_is_device_connected(self, device))
+        return TRUE;
+
+    /* Check if there are free channels */
+    for (i = 0; i < priv->channels->len; i++) {
+        SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);
+
+        if (!spice_usbredir_channel_get_device(channel))
+            break;
+    }
+    if (i == priv->channels->len) {
+        g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            _("There are no free USB channels"));
+        return FALSE;
+    }
+
+    return TRUE;
+#else
+    g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                        _("USB redirection support not compiled in"));
+    return FALSE;
+#endif
+}
+
 /**
  * spice_usb_device_get_description:
  * @device: #SpiceUsbDevice to get the description of
diff --git a/gtk/usb-device-manager.h b/gtk/usb-device-manager.h
index eabfd00..de0e2ba 100644
--- a/gtk/usb-device-manager.h
+++ b/gtk/usb-device-manager.h
@@ -110,6 +110,11 @@ gboolean spice_usb_device_manager_connect_device_finish(
 void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *manager,
                                                 SpiceUsbDevice *device);
 
+gboolean
+spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager  *self,
+                                             SpiceUsbDevice         *device,
+                                             GError                **err);
+
 G_END_DECLS
 
 #endif /* __SPICE_USB_DEVICE_MANAGER_H__ */
diff --git a/gtk/usb-device-widget.c b/gtk/usb-device-widget.c
index 1bfffc0..faaeace 100644
--- a/gtk/usb-device-widget.c
+++ b/gtk/usb-device-widget.c
@@ -71,6 +71,7 @@ struct _SpiceUsbDeviceWidgetPrivate {
     gchar *device_format_string;
     SpiceUsbDeviceManager *manager;
     GtkWidget *info_bar;
+    gchar *err_msg;
 };
 
 static guint signals[LAST_SIGNAL] = { 0, };
@@ -167,11 +168,9 @@ static GObject *spice_usb_device_widget_constructor(
     GObject *obj;
     SpiceUsbDeviceWidget *self;
     SpiceUsbDeviceWidgetPrivate *priv;
-    const gchar *err_msg = NULL;
     GPtrArray *devices = NULL;
     GError *err = NULL;
     GtkWidget *label;
-    gboolean enabled;
     gchar *str;
     int i;
 
@@ -187,28 +186,6 @@ static GObject *spice_usb_device_widget_constructor(
     if (!priv->session)
         g_error("SpiceUsbDeviceWidget constructed without a session");
 
-    g_object_get(G_OBJECT(priv->session), "enable-usbredir", &enabled, NULL);
-    if (!enabled)
-        err_msg = _("USB redirection is disabled");
-
-    if (!err_msg && !spice_session_has_channel_type(priv->session,
-                                                    SPICE_CHANNEL_USBREDIR))
-        err_msg = _("The connected VM is not configured for USB redirection");
-
-    if (!err_msg) {
-        priv->manager = spice_usb_device_manager_get(priv->session, &err);
-        if (!err) {
-            g_signal_connect(priv->manager, "device-added",
-                             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;
-    }
-
     label = gtk_label_new(NULL);
     str = g_strdup_printf("<b>%s</b>", _("Select USB devices to redirect"));
     gtk_label_set_markup(GTK_LABEL (label), str);
@@ -216,14 +193,24 @@ static GObject *spice_usb_device_widget_constructor(
     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
     gtk_box_pack_start(GTK_BOX(self), label, FALSE, FALSE, 0);
 
-    if (err_msg) {
-        spice_usb_device_widget_show_info_bar(self, err_msg,
+    priv->manager = spice_usb_device_manager_get(priv->session, &err);
+    if (err) {
+        spice_usb_device_widget_show_info_bar(self, err->message,
                                               GTK_MESSAGE_WARNING,
                                               GTK_STOCK_DIALOG_WARNING);
         g_clear_error(&err);
         return obj;
     }
 
+    g_signal_connect(priv->manager, "device-added",
+                     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);
+
     for (i = 0; i < devices->len; i++)
         device_added_cb(NULL, g_ptr_array_index(devices, i), self);
 
@@ -351,6 +338,60 @@ static SpiceUsbDevice *get_usb_device(GtkWidget *widget)
     return g_object_get_data(G_OBJECT(widget), "usb-device");
 }
 
+static void check_can_redirect(GtkWidget *widget, gpointer user_data)
+{
+    SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);
+    SpiceUsbDeviceWidgetPrivate *priv = self->priv;
+    SpiceUsbDevice *device;
+    gboolean can_redirect;
+    GError *err = NULL;
+
+    device = get_usb_device(widget);
+    if (!device)
+        return; /* Non device widget, ie the info_bar */
+
+    can_redirect = spice_usb_device_manager_can_redirect_device(priv->manager,
+                                                                device, &err);
+    gtk_widget_set_sensitive(widget, can_redirect);
+
+    /* If we can not redirect this device, append the error message to
+       err_msg, but only if it is *not* already there! */
+    if (!can_redirect) {
+        if (priv->err_msg) {
+            if (!strstr(priv->err_msg, err->message)) {
+                gchar *old_err_msg = priv->err_msg;
+
+                priv->err_msg = g_strdup_printf("%s\n%s", priv->err_msg,
+                                                err->message);
+                g_free(old_err_msg);
+            }
+        } else {
+            priv->err_msg = g_strdup(err->message);
+        }
+    }
+
+    g_clear_error(&err);
+}
+
+static gboolean spice_usb_device_widget_update_status(gpointer user_data)
+{
+    SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);
+    SpiceUsbDeviceWidgetPrivate *priv = self->priv;
+
+    gtk_container_foreach(GTK_CONTAINER(self), check_can_redirect, self);
+
+    if (priv->err_msg) {
+        spice_usb_device_widget_show_info_bar(self, priv->err_msg,
+                                              GTK_MESSAGE_INFO,
+                                              GTK_STOCK_DIALOG_WARNING);
+        g_free(priv->err_msg);
+        priv->err_msg = NULL;
+    } else {
+        spice_usb_device_widget_hide_info_bar(self);
+    }
+    return FALSE;
+}
+
 typedef struct _connect_cb_data {
     GtkWidget *check;
     SpiceUsbDeviceWidget *self;
@@ -379,6 +420,7 @@ static void connect_cb(GObject *gobject, GAsyncResult *res, gpointer user_data)
         g_error_free(err);
 
         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->check), FALSE);
+        spice_usb_device_widget_update_status(self);
     }
 
     g_object_unref(data->check);
@@ -407,6 +449,7 @@ static void checkbox_clicked_cb(GtkWidget *check, gpointer user_data)
         spice_usb_device_manager_disconnect_device(priv->manager,
                                                    device);
     }
+    spice_usb_device_widget_update_status(self);
 }
 
 static void checkbox_usb_device_destroy_notify(gpointer data)
@@ -459,6 +502,8 @@ static void device_removed_cb(SpiceUsbDeviceManager *manager,
 
     gtk_container_foreach(GTK_CONTAINER(self),
                           destroy_widget_by_usb_device, device);
+
+    spice_usb_device_widget_update_status(self);
 }
 
 static void set_inactive_by_usb_device(GtkWidget *widget, gpointer user_data)
@@ -474,4 +519,6 @@ static void device_error_cb(SpiceUsbDeviceManager *manager,
 
     gtk_container_foreach(GTK_CONTAINER(self),
                           set_inactive_by_usb_device, device);
+
+    spice_usb_device_widget_update_status(self);
 }
commit fdb494f7ece881485e473736b89ca48721e90e72
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Feb 20 20:31:39 2012 +0100

    usb-device-widget: Use an info_bar for error messages
    
    And in general gnome-hig-ify usb-device-widget:
    * Use spacing instead of padding so that there is no padding at the
      outside/border of the widget, allowing the user to control the border size.
    * Use multiple of 6 as spacing / indentation values
    * Show the label left justified and bold, show the checkboxes (and the info
      bar) 12 pixels indented from the label
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/spicy.c b/gtk/spicy.c
index 40b724e..0486610 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -437,13 +437,16 @@ static void menu_cb_select_usb_devices(GtkAction *action, void *data)
                     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
                     NULL);
     gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
+    gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
+    gtk_box_set_spacing(GTK_BOX(gtk_bin_get_child(GTK_BIN(dialog))), 12);
+
     area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
 
     usb_device_widget = spice_usb_device_widget_new(win->conn->session,
                                                     "%s %s");
     g_signal_connect(usb_device_widget, "connect-failed",
                      G_CALLBACK(usb_connect_failed), NULL);
-    gtk_box_pack_start(GTK_BOX(area), usb_device_widget, TRUE, TRUE, 5);
+    gtk_box_pack_start(GTK_BOX(area), usb_device_widget, TRUE, TRUE, 0);
 
     /* This shrinks the dialog when USB devices are unplugged */
     g_signal_connect(usb_device_widget, "remove",
diff --git a/gtk/usb-device-widget.c b/gtk/usb-device-widget.c
index 4b504ca..1bfffc0 100644
--- a/gtk/usb-device-widget.c
+++ b/gtk/usb-device-widget.c
@@ -70,6 +70,7 @@ struct _SpiceUsbDeviceWidgetPrivate {
     SpiceSession *session;
     gchar *device_format_string;
     SpiceUsbDeviceManager *manager;
+    GtkWidget *info_bar;
 };
 
 static guint signals[LAST_SIGNAL] = { 0, };
@@ -118,6 +119,48 @@ static void spice_usb_device_widget_set_property(GObject       *gobject,
     }
 }
 
+static void spice_usb_device_widget_hide_info_bar(SpiceUsbDeviceWidget *self)
+{
+    SpiceUsbDeviceWidgetPrivate *priv = self->priv;
+
+    if (priv->info_bar) {
+        gtk_widget_destroy(priv->info_bar);
+        priv->info_bar = NULL;
+    }
+}
+
+static void
+spice_usb_device_widget_show_info_bar(SpiceUsbDeviceWidget *self,
+                                      const gchar          *message,
+                                      GtkMessageType        message_type,
+                                      const gchar          *stock_icon_id)
+{
+    SpiceUsbDeviceWidgetPrivate *priv = self->priv;
+    GtkWidget *info_bar, *content_area, *hbox, *widget;
+
+    spice_usb_device_widget_hide_info_bar(self);
+
+    info_bar = gtk_info_bar_new();
+    gtk_info_bar_set_message_type(GTK_INFO_BAR(info_bar), message_type);
+
+    content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar));
+    hbox = gtk_hbox_new(FALSE, 12);
+    gtk_container_add(GTK_CONTAINER(content_area), hbox);
+
+    widget = gtk_image_new_from_stock(stock_icon_id,
+                                      GTK_ICON_SIZE_SMALL_TOOLBAR);
+    gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+
+    widget = gtk_label_new(message);
+    gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
+
+    priv->info_bar = gtk_alignment_new(0.0, 0.0, 1.0, 0.0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(priv->info_bar), 0, 0, 12, 0);
+    gtk_container_add(GTK_CONTAINER(priv->info_bar), info_bar);
+    gtk_box_pack_start(GTK_BOX(self), priv->info_bar, FALSE, FALSE, 0);
+    gtk_widget_show_all(priv->info_bar);
+}
+
 static GObject *spice_usb_device_widget_constructor(
     GType gtype, guint n_properties, GObjectConstructParam *properties)
 {
@@ -129,6 +172,7 @@ static GObject *spice_usb_device_widget_constructor(
     GError *err = NULL;
     GtkWidget *label;
     gboolean enabled;
+    gchar *str;
     int i;
 
     {
@@ -165,16 +209,21 @@ static GObject *spice_usb_device_widget_constructor(
             err_msg = err->message;
     }
 
+    label = gtk_label_new(NULL);
+    str = g_strdup_printf("<b>%s</b>", _("Select USB devices to redirect"));
+    gtk_label_set_markup(GTK_LABEL (label), str);
+    g_free(str);
+    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+    gtk_box_pack_start(GTK_BOX(self), label, FALSE, FALSE, 0);
+
     if (err_msg) {
-        label = gtk_label_new(err_msg);
-        gtk_box_pack_start(GTK_BOX(self), label, TRUE, TRUE, 5);
+        spice_usb_device_widget_show_info_bar(self, err_msg,
+                                              GTK_MESSAGE_WARNING,
+                                              GTK_STOCK_DIALOG_WARNING);
         g_clear_error(&err);
         return obj;
     }
 
-    label = gtk_label_new(_("Select USB devices to redirect"));
-    gtk_box_pack_start(GTK_BOX(self), label, TRUE, TRUE, 5);
-
     for (i = 0; i < devices->len; i++)
         device_added_cb(NULL, g_ptr_array_index(devices, i), self);
 
@@ -286,11 +335,22 @@ GtkWidget *spice_usb_device_widget_new(SpiceSession    *session,
     return g_object_new(SPICE_TYPE_USB_DEVICE_WIDGET,
                         "session", session,
                         "device-format-string", device_format_string,
+                        "spacing", 6,
                         NULL);
 }
 
 /* ------------------------------------------------------------------ */
 /* callbacks                                                          */
+
+static SpiceUsbDevice *get_usb_device(GtkWidget *widget)
+{
+    if (!GTK_IS_ALIGNMENT(widget))
+        return NULL;
+
+    widget = gtk_bin_get_child(GTK_BIN(widget));
+    return g_object_get_data(G_OBJECT(widget), "usb-device");
+}
+
 typedef struct _connect_cb_data {
     GtkWidget *check;
     SpiceUsbDeviceWidget *self;
@@ -359,13 +419,13 @@ static void device_added_cb(SpiceUsbDeviceManager *manager,
 {
     SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);
     SpiceUsbDeviceWidgetPrivate *priv = self->priv;
-    GtkWidget *check;
+    GtkWidget *align, *check;
     gchar *desc;
 
     desc = spice_usb_device_get_description(device,
                                             priv->device_format_string);
-
     check = gtk_check_button_new_with_label(desc);
+    g_free(desc);
 
     if (spice_usb_device_manager_is_device_connected(priv->manager,
                                                      device))
@@ -378,15 +438,17 @@ static void device_added_cb(SpiceUsbDeviceManager *manager,
     g_signal_connect(G_OBJECT(check), "clicked",
                      G_CALLBACK(checkbox_clicked_cb), self);
 
-    gtk_box_pack_start(GTK_BOX(self), check, TRUE, TRUE, 5);
-    gtk_widget_show(check);
-
-    g_free(desc);
+    align = gtk_alignment_new(0, 0, 0, 0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
+    gtk_container_add(GTK_CONTAINER(align), check);
+    gtk_box_pack_end(GTK_BOX(self), align, FALSE, FALSE, 0);
+    spice_usb_device_widget_update_status(self);
+    gtk_widget_show_all(align);
 }
 
 static void destroy_widget_by_usb_device(GtkWidget *widget, gpointer user_data)
 {
-    if (g_object_get_data(G_OBJECT(widget), "usb-device") == user_data)
+    if (get_usb_device(widget) == user_data)
         gtk_widget_destroy(widget);
 }
 
@@ -401,7 +463,7 @@ static void device_removed_cb(SpiceUsbDeviceManager *manager,
 
 static void set_inactive_by_usb_device(GtkWidget *widget, gpointer user_data)
 {
-    if (g_object_get_data(G_OBJECT(widget), "usb-device") == user_data)
+    if (get_usb_device(widget) == user_data)
         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE);
 }
 
commit 708d77a9ad51c659de0b5ef5a8225e8310f13499
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Feb 20 16:45:32 2012 +0100

    configure: Fix "USB redirection support" summary on --disable-usbredir
    
    When running "./configure --disable-usbredir" the
    "USB redirection support" line in the summary at the end of ./configure
    would be empty after "support" instead of ending with yes or no.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/configure.ac b/configure.ac
index 7332b6d..bf9b4ed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -343,7 +343,7 @@ AC_ARG_ENABLE([usbredir],
   [enable_usbredir="auto"])
 
 if test "x$enable_usbredir" = "xno"; then
-  AM_CONDITIONAL(WITH_USBREDIR, false)
+  have_usbredir="no"
 else
   PKG_CHECK_MODULES([USBREDIR],
                     [gudev-1.0 libusb-1.0 >= 1.0.9 libusbredirhost >= 0.3.4 libusbredirparser >= 0.3.4],
@@ -355,8 +355,8 @@ else
   if test "x$have_usbredir" = "xyes"; then
     AC_DEFINE(USE_USBREDIR, [1], [Define if supporting usbredir proxying])
   fi
-  AM_CONDITIONAL([WITH_USBREDIR], [test "x$have_usbredir" = "xyes"])
 fi
+AM_CONDITIONAL([WITH_USBREDIR], [test "x$have_usbredir" = "xyes"])
 
 AC_ARG_ENABLE([polkit],
   AS_HELP_STRING([--enable-polkit=@<:@auto/yes/no@:>@],
commit c64150541db0b8301f066901671bba1b7040599f
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sun Feb 19 09:27:54 2012 +0100

    usbredir: Treat the user cancelling the policykit dialog as a cancel
    
    Rather then treating it as any other error. This avoids showing an error
    dialog after the user pressed cancel in the policykit dialog.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/spice-client-glib-usb-acl-helper.c b/gtk/spice-client-glib-usb-acl-helper.c
index bd01979..aaa1180 100644
--- a/gtk/spice-client-glib-usb-acl-helper.c
+++ b/gtk/spice-client-glib-usb-acl-helper.c
@@ -177,6 +177,11 @@ static void check_authorization_cb(PolkitAuthority *authority,
         return;
     }
 
+    if (polkit_authorization_result_get_dismissed(result)) {
+        ERROR("CANCELED\n");
+        return;
+    }
+
     if (!polkit_authorization_result_get_is_authorized(result)) {
         ERROR("Not authorized\n");
         return;
diff --git a/gtk/usb-acl-helper.c b/gtk/usb-acl-helper.c
index b79e122..6a459c5 100644
--- a/gtk/usb-acl-helper.c
+++ b/gtk/usb-acl-helper.c
@@ -87,6 +87,13 @@ static void spice_usb_acl_helper_class_init(SpiceUsbAclHelperClass *klass)
 /* ------------------------------------------------------------------ */
 /* callbacks                                                          */
 
+static void async_result_set_cancelled(GSimpleAsyncResult *result)
+{
+    g_simple_async_result_set_error(result,
+                G_IO_ERROR, G_IO_ERROR_CANCELLED,
+                "Setting USB device node ACL cancelled");
+}
+
 static gboolean cb_out_watch(GIOChannel    *channel,
                              GIOCondition   cond,
                              gpointer      *user_data)
@@ -111,6 +118,8 @@ static gboolean cb_out_watch(GIOChannel    *channel,
             string[strlen(string) - 1] = 0;
             if (!strcmp(string, "SUCCESS")) {
                 success = TRUE;
+            } else if (!strcmp(string, "CANCELED")) {
+                async_result_set_cancelled(priv->result);
             } else {
                 g_simple_async_result_set_error(priv->result,
                             SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
@@ -278,9 +287,7 @@ void spice_usb_acl_helper_close_acl(SpiceUsbAclHelper *self)
 
     /* If the acl open has not completed yet report it as cancelled */
     if (priv->result) {
-        g_simple_async_result_set_error(priv->result,
-                    G_IO_ERROR, G_IO_ERROR_CANCELLED,
-                    "Setting USB device node ACL cancelled");
+        async_result_set_cancelled(priv->result);
         g_simple_async_result_complete_in_idle(priv->result);
     }
 
commit bde67bf22361da794e75effa2255d7f3a3c713e2
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Sat Feb 18 16:59:03 2012 +0100

    usbredir: Add device rejected errors
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index e22aa6c..fa7dce0 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -513,6 +513,42 @@ static void usbredir_free_lock(void *user_data) {
 }
 
 /* --------------------------------------------------------------------- */
+
+/* Events to be handled in main context */
+enum {
+    DEVICE_ERROR,
+};
+
+struct DEVICE_ERROR {
+    libusb_device *device;
+    GError *error;
+};
+
+/* main context */
+static void do_emit_main_context(GObject *object, int event, gpointer params)
+{
+    SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(object);
+    SpiceUsbredirChannelPrivate *priv = channel->priv;
+
+    switch (event) {
+    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) {
+            spice_usbredir_channel_disconnect_device(channel);
+            spice_usb_device_manager_device_error(
+                spice_usb_device_manager_get(
+                    spice_channel_get_session(SPICE_CHANNEL(channel)), NULL),
+                (SpiceUsbDevice *)p->device, p->error);
+        }
+        break;
+    }
+    default:
+        g_warn_if_reached();
+    }
+}
+
+/* --------------------------------------------------------------------- */
 /* coroutine context                                                     */
 static void spice_usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *msg)
 {
@@ -544,7 +580,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 +592,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/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-priv.h b/gtk/usb-device-manager-priv.h
index b0b2f74..912e3bf 100644
--- a/gtk/usb-device-manager-priv.h
+++ b/gtk/usb-device-manager-priv.h
@@ -31,6 +31,9 @@ gboolean spice_usb_device_manager_start_event_listening(
 void spice_usb_device_manager_stop_event_listening(
     SpiceUsbDeviceManager *manager);
 
+void spice_usb_device_manager_device_error(
+    SpiceUsbDeviceManager *manager, SpiceUsbDevice *device, GError *err);
+
 G_END_DECLS
 
 #endif /* __SPICE_USB_DEVICE_MANAGER_PRIV_H__ */
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index b6dfa20..dea0ab5 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));
 }
 
@@ -682,6 +705,12 @@ void spice_usb_device_manager_stop_event_listening(
     if (priv->event_listeners == 0)
         priv->event_thread_run = FALSE;
 }
+
+void spice_usb_device_manager_device_error(
+    SpiceUsbDeviceManager *self, SpiceUsbDevice *device, GError *err)
+{
+    g_signal_emit(self, signals[DEVICE_ERROR], 0, device, err);
+}
 #endif
 
 static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
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);
+}


More information about the Spice-commits mailing list