Nice! tested & worked as expected, code looks fine. ack On Mon, Jan 30, 2012 at 2:33 PM, Hans de Goede <hdego...@redhat.com> wrote: > This patch adds a SpiceUsbDeviceWidget which apps can use to easily > add an UI to select USB devices to redirect (or unredirect). > > See spicy for an example usage. > > Signed-off-by: Hans de Goede <hdego...@redhat.com> > --- > doc/reference/spice-gtk-docs.xml | 1 + > doc/reference/spice-gtk-sections.txt | 18 ++ > doc/reference/spice-gtk.types | 2 + > gtk/Makefile.am | 3 + > gtk/map-file | 2 + > gtk/spice-client-gtk.override | 2 + > gtk/spicy.c | 60 +++++- > gtk/usb-device-widget.c | 393 > ++++++++++++++++++++++++++++++++++ > gtk/usb-device-widget.h | 83 +++++++ > po/POTFILES.in | 1 + > 10 files changed, 555 insertions(+), 10 deletions(-) > create mode 100644 gtk/usb-device-widget.c > create mode 100644 gtk/usb-device-widget.h > > diff --git a/doc/reference/spice-gtk-docs.xml > b/doc/reference/spice-gtk-docs.xml > index 2b4336d..82cdce8 100644 > --- a/doc/reference/spice-gtk-docs.xml > +++ b/doc/reference/spice-gtk-docs.xml > @@ -42,6 +42,7 @@ > <title>GTK Widget, from spice-client-gtk</title> > <xi:include href="xml/spice-gtk-session.xml"/> > <xi:include href="xml/spice-widget.xml"/> > + <xi:include href="xml/usb-device-widget.xml"/> > </chapter> > > <chapter id="application-support"> > diff --git a/doc/reference/spice-gtk-sections.txt > b/doc/reference/spice-gtk-sections.txt > index 870352d..5e3af99 100644 > --- a/doc/reference/spice-gtk-sections.txt > +++ b/doc/reference/spice-gtk-sections.txt > @@ -342,6 +342,24 @@ SpiceDisplayPrivate > </SECTION> > > <SECTION> > +<FILE>usb-device-widget</FILE> > +<TITLE>SpiceUsbDeviceWidget</TITLE> > +SpiceUsbDeviceWidget > +SpiceUsbDeviceWidgetClass > +<SUBSECTION> > +spice_usb_device_widget_new > +<SUBSECTION Standard> > +SPICE_USB_DEVICE_WIDGET > +SPICE_IS_USB_DEVICE_WIDGET > +spice_usb_device_widget_get_type > +SPICE_USB_DEVICE_WIDGET_CLASS > +SPICE_IS_USB_DEVICE_WIDGET_CLASS > +SPICE_USB_DEVICE_WIDGET_GET_CLASS > +<SUBSECTION Private> > +SpiceUsbDeviceWidgetPrivate > +</SECTION> > + > +<SECTION> > <FILE>spice-util</FILE> > spice_util_set_debug > spice_util_get_version_string > diff --git a/doc/reference/spice-gtk.types b/doc/reference/spice-gtk.types > index a88ece1..ff80277 100644 > --- a/doc/reference/spice-gtk.types > +++ b/doc/reference/spice-gtk.types > @@ -18,6 +18,7 @@ > #include "spice-grabsequence.h" > #include "smartcard-manager.h" > #include "usb-device-manager.h" > +#include "usb-device-widget.h" > > spice_audio_get_type > spice_channel_event_get_type > @@ -40,3 +41,4 @@ spice_session_verify_get_type > spice_usbredir_channel_get_type > spice_usb_device_get_type > spice_usb_device_manager_get_type > +spice_usb_device_widget_get_type > diff --git a/gtk/Makefile.am b/gtk/Makefile.am > index 2cc0163..a5b6e29 100644 > --- a/gtk/Makefile.am > +++ b/gtk/Makefile.am > @@ -109,10 +109,12 @@ SPICE_GTK_SOURCES_COMMON = \ > vncdisplaykeymap.h \ > spice-grabsequence.c \ > spice-grabsequence.h \ > + usb-device-widget.c \ > $(NULL) > > nodist_SPICE_GTK_SOURCES_COMMON = \ > spice-widget-enums.c \ > + spice-marshal.c \ > $(NULL) > > if WITH_X11 > @@ -143,6 +145,7 @@ libspice_client_gtkinclude_HEADERS = \ > spice-gtk-session.h \ > spice-widget.h \ > spice-grabsequence.h \ > + usb-device-widget.h \ > $(NULL) > > nodist_libspice_client_gtkinclude_HEADERS = \ > diff --git a/gtk/map-file b/gtk/map-file > index 4b470bb..38f7c26 100644 > --- a/gtk/map-file > +++ b/gtk/map-file > @@ -91,6 +91,8 @@ spice_usb_device_manager_get; > spice_usb_device_manager_get_devices; > spice_usb_device_manager_get_type; > spice_usb_device_manager_is_device_connected; > +spice_usb_device_widget_get_type; > +spice_usb_device_widget_new; > spice_usbredir_channel_get_type; > spice_util_get_debug; > spice_util_get_version_string; > diff --git a/gtk/spice-client-gtk.override b/gtk/spice-client-gtk.override > index e393037..31e4f9e 100644 > --- a/gtk/spice-client-gtk.override > +++ b/gtk/spice-client-gtk.override > @@ -6,12 +6,14 @@ headers > #include "spice-widget.h" > #include "spice-gtk-session.h" > #include "spice-audio.h" > +#include "usb-device-widget.h" > %% > modulename spice_client_gtk > %% > import gobject.GObject as PyGObject_Type > import gtk.DrawingArea as PyGtkDrawingArea_Type > import gtk.Widget as PyGtkWidget_Type > +import gtk.VBox as PyGtkVBox_Type > %% > ignore-glob > *_get_type > diff --git a/gtk/spicy.c b/gtk/spicy.c > index e37ce82..c002a5e 100644 > --- a/gtk/spicy.c > +++ b/gtk/spicy.c > @@ -1,4 +1,3 @@ > -/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > /* > Copyright (C) 2010-2011 Red Hat, Inc. > > @@ -38,6 +37,7 @@ > #include "spice-common.h" > #include "spice-cmdline.h" > #include "spice-option.h" > +#include "usb-device-widget.h" > > /* config */ > static gboolean fullscreen = false; > @@ -98,10 +98,10 @@ static void connection_disconnect(spice_connection *conn); > static void connection_destroy(spice_connection *conn); > static void resolution_fullscreen(struct spice_window *win); > static void resolution_restore(struct spice_window *win); > -static void auto_connect_failed(SpiceUsbDeviceManager *manager, > - SpiceUsbDevice *device, > - GError *error, > - gpointer data); > +static void usb_connect_failed(GObject *object, > + SpiceUsbDevice *device, > + GError *error, > + gpointer data); > static gboolean is_gtk_session_property(const gchar *property); > > /* ------------------------------------------------------------------ */ > @@ -417,6 +417,35 @@ static void menu_cb_remove_smartcard(GtkAction *action, > void *data) > } > #endif > > +#ifdef USE_USBREDIR > +static void menu_cb_select_usb_devices(GtkAction *action, void *data) > +{ > + GtkWidget *dialog, *area, *usb_device_widget; > + struct spice_window *win = data; > + > + /* Create the widgets */ > + dialog = gtk_dialog_new_with_buttons( > + _("Select USB devices for redirection"), > + GTK_WINDOW(win->toplevel), > + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, > + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, > + NULL); > + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); > + 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); > + > + /* show and run */ > + gtk_widget_show_all(dialog); > + gtk_dialog_run(GTK_DIALOG(dialog)); > + gtk_widget_destroy(dialog); > +} > +#endif > + > static void menu_cb_bool_prop(GtkToggleAction *action, gpointer data) > { > struct spice_window *win = data; > @@ -708,6 +737,14 @@ static const GtkActionEntry entries[] = { > },{ > #endif > > +#ifdef USE_USBREDIR > + .name = "SelectUsbDevices", > + .label = N_("_Select USB Devices for redirection"), > + .callback = G_CALLBACK(menu_cb_select_usb_devices), > + .accelerator = "<shift>F10", > + },{ > +#endif > + > /* Help menu */ > .name = "About", > .stock_id = GTK_STOCK_ABOUT, > @@ -797,6 +834,9 @@ static char ui_xml[] = > " <menuitem action='InsertSmartcard'/>\n" > " <menuitem action='RemoveSmartcard'/>\n" > #endif > +#ifdef USE_USBREDIR > +" <menuitem action='SelectUsbDevices'/>\n" > +#endif > " </menu>\n" > " <menu action='OptionMenu'>\n" > " <menuitem action='grab-keyboard'/>\n" > @@ -1522,7 +1562,7 @@ static spice_connection *connection_new(void) > manager = spice_usb_device_manager_get(conn->session, NULL); > if (manager) { > g_signal_connect(manager, "auto-connect-failed", > - G_CALLBACK(auto_connect_failed), NULL); > + G_CALLBACK(usb_connect_failed), NULL); > } > > connections++; > @@ -1611,10 +1651,10 @@ signal_handler(int signum) > g_main_loop_quit(mainloop); > } > > -static void auto_connect_failed(SpiceUsbDeviceManager *manager, > - SpiceUsbDevice *device, > - GError *error, > - gpointer data) > +static void usb_connect_failed(GObject *object, > + SpiceUsbDevice *device, > + GError *error, > + gpointer data) > { > GtkWidget *dialog; > > diff --git a/gtk/usb-device-widget.c b/gtk/usb-device-widget.c > new file mode 100644 > index 0000000..7a57e27 > --- /dev/null > +++ b/gtk/usb-device-widget.c > @@ -0,0 +1,393 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2012 Red Hat, Inc. > + > + Red Hat Authors: > + Hans de Goede <hdego...@redhat.com> > + > + This library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + This library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with this library; if not, see > <http://www.gnu.org/licenses/>. > +*/ > + > +#include "config.h" > +#include <glib/gi18n.h> > +#include "spice-client.h" > +#include "spice-marshal.h" > +#include "usb-device-widget.h" > + > +/** > + * SECTION:usb-device-widget > + * @short_description: USB device selection widget > + * @title: Spice USB device selection widget > + * @section_id: > + * @see_also: > + * @stability: Stable > + * @include: usb-device-widget.h > + * > + * #SpiceUsbDeviceWidget is a gtk widget which apps can use to easily > + * add an UI to select USB devices to redirect (or unredirect). > + */ > + > +/* ------------------------------------------------------------------ */ > +/* Prototypes for callbacks */ > +static void device_added_cb(SpiceUsbDeviceManager *manager, > + SpiceUsbDevice *device, gpointer user_data); > +static void device_removed_cb(SpiceUsbDeviceManager *manager, > + SpiceUsbDevice *device, gpointer user_data); > + > +/* ------------------------------------------------------------------ */ > +/* gobject glue */ > + > +#define SPICE_USB_DEVICE_WIDGET_GET_PRIVATE(obj) \ > + (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_USB_DEVICE_WIDGET, \ > + SpiceUsbDeviceWidgetPrivate)) > + > +enum { > + PROP_0, > + PROP_SESSION, > + PROP_DEVICE_FORMAT_STRING, > +}; > + > +enum { > + CONNECT_FAILED, > + LAST_SIGNAL, > +}; > + > +struct _SpiceUsbDeviceWidgetPrivate { > + SpiceSession *session; > + gchar *device_format_string; > + SpiceUsbDeviceManager *manager; > +}; > + > +static guint signals[LAST_SIGNAL] = { 0, }; > + > +G_DEFINE_TYPE(SpiceUsbDeviceWidget, spice_usb_device_widget, GTK_TYPE_VBOX); > + > +static void spice_usb_device_widget_get_property(GObject *gobject, > + guint prop_id, > + GValue *value, > + GParamSpec *pspec) > +{ > + SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(gobject); > + SpiceUsbDeviceWidgetPrivate *priv = self->priv; > + > + switch (prop_id) { > + case PROP_SESSION: > + g_value_set_object(value, priv->session); > + break; > + case PROP_DEVICE_FORMAT_STRING: > + g_value_set_string(value, priv->device_format_string); > + break; > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); > + break; > + } > +} > + > +static void spice_usb_device_widget_set_property(GObject *gobject, > + guint prop_id, > + const GValue *value, > + GParamSpec *pspec) > +{ > + SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(gobject); > + SpiceUsbDeviceWidgetPrivate *priv = self->priv; > + > + switch (prop_id) { > + case PROP_SESSION: > + priv->session = g_value_dup_object(value); > + break; > + case PROP_DEVICE_FORMAT_STRING: > + priv->device_format_string = g_value_dup_string(value); > + break; > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); > + break; > + } > +} > + > +static GObject *spice_usb_device_widget_constructor( > + GType gtype, guint n_properties, GObjectConstructParam *properties) > +{ > + GObject *obj; > + SpiceUsbDeviceWidget *self; > + SpiceUsbDeviceWidgetPrivate *priv; > + const gchar *err_msg = NULL; > + GPtrArray *devices = NULL; > + GError *err = NULL; > + GtkWidget *label; > + gboolean enabled; > + int i; > + > + { > + /* Always chain up to the parent constructor */ > + GObjectClass *parent_class; > + parent_class = G_OBJECT_CLASS(spice_usb_device_widget_parent_class); > + obj = parent_class->constructor(gtype, n_properties, properties); > + } > + > + self = SPICE_USB_DEVICE_WIDGET(obj); > + priv = self->priv; > + 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); > + devices = spice_usb_device_manager_get_devices(priv->manager); > + } else > + err_msg = err->message; > + } > + > + if (err_msg) { > + label = gtk_label_new(err_msg); > + gtk_box_pack_start(GTK_BOX(self), label, TRUE, TRUE, 5); > + 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); > + > + g_ptr_array_unref(devices); > + > + return obj; > +} > + > +static void spice_usb_device_widget_finalize(GObject *object) > +{ > + SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(object); > + SpiceUsbDeviceWidgetPrivate *priv = self->priv; > + > + if (priv->manager) { > + g_signal_handlers_disconnect_by_func(priv->manager, > + device_added_cb, self); > + g_signal_handlers_disconnect_by_func(priv->manager, > + device_removed_cb, self); > + } > + g_object_unref(priv->session); > + g_free(priv->device_format_string); > +} > + > +static void spice_usb_device_widget_class_init( > + SpiceUsbDeviceWidgetClass *klass) > +{ > + GObjectClass *gobject_class = (GObjectClass *)klass; > + GParamSpec *pspec; > + > + g_type_class_add_private (klass, sizeof (SpiceUsbDeviceWidgetPrivate)); > + > + gobject_class->constructor = spice_usb_device_widget_constructor; > + gobject_class->finalize = spice_usb_device_widget_finalize; > + gobject_class->get_property = spice_usb_device_widget_get_property; > + gobject_class->set_property = spice_usb_device_widget_set_property; > + > + /** > + * SpiceUsbDeviceWidget:session: > + * > + * #SpiceSession this #SpiceUsbDeviceWidget is associated with > + * > + **/ > + pspec = g_param_spec_object("session", > + "Session", > + "SpiceSession", > + SPICE_TYPE_SESSION, > + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | > + G_PARAM_STATIC_STRINGS); > + g_object_class_install_property(gobject_class, PROP_SESSION, pspec); > + > + /** > + * SpiceUsbDeviceWidget:device-format-string: > + * > + * Format string to pass to spice_usb_device_get_description() for > getting > + * the device USB descriptions. > + */ > + pspec = g_param_spec_string("device-format-string", > + "Device format string", > + "Format string for device description", > + NULL, > + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | > + G_PARAM_STATIC_STRINGS); > + g_object_class_install_property(gobject_class, PROP_DEVICE_FORMAT_STRING, > + pspec); > + > + /** > + * SpiceUsbDeviceWidget::connect-failed: > + * @widget: The #SpiceUsbDeviceWidget that emitted the signal > + * @device: #SpiceUsbDevice boxed object corresponding to the added > device > + * @error: #GError describing the reason why the connect failed > + * > + * The #SpiceUsbDeviceWidget::connect-failed signal is emitted whenever > + * the user has requested for a device to be redirected and this has > + * failed. > + **/ > + signals[CONNECT_FAILED] = > + g_signal_new("connect-failed", > + G_OBJECT_CLASS_TYPE(gobject_class), > + G_SIGNAL_RUN_FIRST, > + G_STRUCT_OFFSET(SpiceUsbDeviceWidgetClass, > connect_failed), > + NULL, NULL, > + g_cclosure_user_marshal_VOID__BOXED_BOXED, > + G_TYPE_NONE, > + 2, > + SPICE_TYPE_USB_DEVICE, > + G_TYPE_ERROR); > +} > + > +static void spice_usb_device_widget_init(SpiceUsbDeviceWidget *self) > +{ > + self->priv = SPICE_USB_DEVICE_WIDGET_GET_PRIVATE(self); > +} > + > +/* ------------------------------------------------------------------ */ > +/* public api */ > + > +/** > + * spice_usb_device_widget_new: > + * @session: #SpiceSession for which to widget will control USB redirection > + * @device_format_string: String passed to spice_usb_device_get_description() > + * > + * Returns: a new #SpiceUsbDeviceWidget instance > + */ > +GtkWidget *spice_usb_device_widget_new(SpiceSession *session, > + const gchar *device_format_string) > +{ > + return g_object_new(SPICE_TYPE_USB_DEVICE_WIDGET, > + "session", session, > + "device-format-string", device_format_string, > + NULL); > +} > + > +/* ------------------------------------------------------------------ */ > +/* callbacks */ > +typedef struct _connect_cb_data { > + GtkWidget *check; > + SpiceUsbDeviceWidget *self; > +} connect_cb_data; > + > +static void connect_cb(GObject *gobject, GAsyncResult *res, gpointer > user_data) > +{ > + SpiceUsbDeviceManager *manager = SPICE_USB_DEVICE_MANAGER(gobject); > + connect_cb_data *data = user_data; > + SpiceUsbDeviceWidget *self = data->self; > + SpiceUsbDeviceWidgetPrivate *priv = self->priv; > + SpiceUsbDevice *device; > + GError *err = NULL; > + gchar *desc; > + > + spice_usb_device_manager_connect_device_finish(manager, res, &err); > + if (err) { > + device = g_object_get_data(G_OBJECT(data->check), "usb-device"); > + desc = spice_usb_device_get_description(device, > + priv->device_format_string); > + g_prefix_error(&err, "Could not redirect %s: ", desc); > + g_free(desc); > + > + SPICE_DEBUG("%s", err->message); > + g_signal_emit(self, signals[CONNECT_FAILED], 0, device, err); > + g_error_free(err); > + > + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->check), FALSE); > + } > + > + g_object_unref(data->check); > + g_object_unref(data->self); > + g_free(data); > +} > + > +static void checkbox_clicked_cb(GtkWidget *check, gpointer user_data) > +{ > + SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data); > + SpiceUsbDeviceWidgetPrivate *priv = self->priv; > + SpiceUsbDevice *device; > + > + device = g_object_get_data(G_OBJECT(check), "usb-device"); > + > + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check))) { > + connect_cb_data *data = g_new(connect_cb_data, 1); > + data->check = g_object_ref(check); > + data->self = g_object_ref(self); > + spice_usb_device_manager_connect_device_async(priv->manager, > + device, > + NULL, > + connect_cb, > + data); > + } else { > + spice_usb_device_manager_disconnect_device(priv->manager, > + device); > + } > +} > + > +static void checkbox_usb_device_destroy_notify(gpointer data) > +{ > + g_boxed_free(spice_usb_device_get_type(), data); > +} > + > +static void device_added_cb(SpiceUsbDeviceManager *manager, > + SpiceUsbDevice *device, gpointer user_data) > +{ > + SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data); > + SpiceUsbDeviceWidgetPrivate *priv = self->priv; > + GtkWidget *check; > + gchar *desc; > + > + desc = spice_usb_device_get_description(device, > + priv->device_format_string); > + > + check = gtk_check_button_new_with_label(desc); > + > + if (spice_usb_device_manager_is_device_connected(priv->manager, > + device)) > + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE); > + > + g_object_set_data_full( > + G_OBJECT(check), "usb-device", > + g_boxed_copy(spice_usb_device_get_type(), device), > + checkbox_usb_device_destroy_notify); > + 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); > +} > + > +static void destroy_widget_by_usb_device(GtkWidget *widget, gpointer > user_data) > +{ > + if (g_object_get_data(G_OBJECT(widget), "usb-device") == user_data) > + gtk_widget_destroy(widget); > +} > + > +static void device_removed_cb(SpiceUsbDeviceManager *manager, > + SpiceUsbDevice *device, gpointer user_data) > +{ > + SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data); > + > + gtk_container_foreach(GTK_CONTAINER(self), > + destroy_widget_by_usb_device, device); > +} > diff --git a/gtk/usb-device-widget.h b/gtk/usb-device-widget.h > new file mode 100644 > index 0000000..27ec795 > --- /dev/null > +++ b/gtk/usb-device-widget.h > @@ -0,0 +1,83 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2012 Red Hat, Inc. > + > + Red Hat Authors: > + Hans de Goede <hdego...@redhat.com> > + > + This library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + This library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with this library; if not, see > <http://www.gnu.org/licenses/>. > +*/ > +#ifndef __SPICE_USB_DEVICE_WIDGET_H__ > +#define __SPICE_USB_DEVICE_WIDGET_H__ > + > +#include <gtk/gtk.h> > +#include "spice-client.h" > + > +G_BEGIN_DECLS > + > +#define SPICE_TYPE_USB_DEVICE_WIDGET > (spice_usb_device_widget_get_type ()) > +#define SPICE_USB_DEVICE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST > ((obj), SPICE_TYPE_USB_DEVICE_WIDGET, SpiceUsbDeviceWidget)) > +#define SPICE_USB_DEVICE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST > ((klass), SPICE_TYPE_USB_DEVICE_WIDGET, SpiceUsbDeviceWidgetClass)) > +#define SPICE_IS_USB_DEVICE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE > ((obj), SPICE_TYPE_USB_DEVICE_WIDGET)) > +#define SPICE_IS_USB_DEVICE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE > ((klass), SPICE_TYPE_USB_DEVICE_WIDGET)) > +#define SPICE_USB_DEVICE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS > ((obj), SPICE_TYPE_USB_DEVICE_WIDGET, SpiceUsbDeviceWidgetClass)) > + > +typedef struct _SpiceUsbDeviceWidget SpiceUsbDeviceWidget; > +typedef struct _SpiceUsbDeviceWidgetClass SpiceUsbDeviceWidgetClass; > +typedef struct _SpiceUsbDeviceWidgetPrivate SpiceUsbDeviceWidgetPrivate; > + > +/** > + * SpiceUsbDeviceWidget: > + * @parent: Parent instance. > + * > + * The #SpiceUsbDeviceWidget struct is opaque and should not be accessed > directly. > + */ > +struct _SpiceUsbDeviceWidget > +{ > + GtkVBox parent; > + > + /*< private >*/ > + SpiceUsbDeviceWidgetPrivate *priv; > + /* Do not add fields to this struct */ > +}; > + > +/** > + * SpiceUsbDeviceWidgetClass: > + * @parent_class: Parent class. > + * @connect_failed: Signal class handler for the > #SpiceUsbDeviceWidget::connect-failed signal. > + * > + * Class structure for #SpiceUsbDeviceWidget. > + */ > +struct _SpiceUsbDeviceWidgetClass > +{ > + GtkVBoxClass parent_class; > + > + /* signals */ > + void (*connect_failed) (SpiceUsbDeviceWidget *widget, > + 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]; > +}; > + > +GType spice_usb_device_widget_get_type(void); > +GtkWidget *spice_usb_device_widget_new(SpiceSession *session, > + const gchar > *device_format_string); > + > +G_END_DECLS > + > +#endif /* __SPICE_USB_DEVICE_WIDGET_H__ */ > diff --git a/po/POTFILES.in b/po/POTFILES.in > index b008d10..3c87ed1 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -11,3 +11,4 @@ gtk/spice-option.c > gtk/spicy-stats.c > gtk/spicy.c > gtk/usb-device-manager.c > +gtk/usb-device-widget.c > -- > 1.7.7.6 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/spice-devel
-- Marc-André Lureau _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel