diff options
author | Hans de Goede <hdegoede@redhat.com> | 2012-01-26 15:12:01 +0100 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2012-01-31 14:31:38 +0100 |
commit | bf0350423caba9fb9f04103d18032a9a4ce912dd (patch) | |
tree | 164aec6bd02126ddf72e67fb10992a865d573440 | |
parent | 9e26b538db86f255e0cb2a20a064da8aa4e3315f (diff) |
Add a USB device selection widget
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 <hdegoede@redhat.com>
-rw-r--r-- | doc/reference/spice-gtk-docs.xml | 1 | ||||
-rw-r--r-- | doc/reference/spice-gtk-sections.txt | 18 | ||||
-rw-r--r-- | doc/reference/spice-gtk.types | 2 | ||||
-rw-r--r-- | gtk/Makefile.am | 5 | ||||
-rw-r--r-- | gtk/map-file | 2 | ||||
-rw-r--r-- | gtk/spice-client-gtk.override | 2 | ||||
-rw-r--r-- | gtk/spicy.c | 59 | ||||
-rw-r--r-- | gtk/usb-device-widget.c | 394 | ||||
-rw-r--r-- | gtk/usb-device-widget.h | 83 | ||||
-rw-r--r-- | po/POTFILES.in | 1 |
10 files changed, 558 insertions, 9 deletions
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..f294c76 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -101,6 +101,8 @@ SPICE_GTK_LIBADD_COMMON = \ $(NULL) SPICE_GTK_SOURCES_COMMON = \ + glib-compat.c \ + glib-compat.h \ spice-gtk-session.c \ spice-gtk-session-priv.h \ spice-widget.c \ @@ -109,10 +111,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 +147,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..cbc702e 100644 --- a/gtk/spicy.c +++ b/gtk/spicy.c @@ -38,6 +38,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 +99,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 +418,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 +738,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 +835,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 +1563,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 +1652,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..028723f --- /dev/null +++ b/gtk/usb-device-widget.c @@ -0,0 +1,394 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2012 Red Hat, Inc. + + Red Hat Authors: + Hans de Goede <hdegoede@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 "glib-compat.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 <hdegoede@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 |