spice的usb必须有一个管理usb设备界面,因此在spice-gtk设计了一个usb_device_widget.c来管理USB设备。可以枚举当前的USB设备,添加USB设备到spice,从spice删除USB设备,通过usb_device_manager.c来管理。
1、通过 spice_usb_device_widget_new创建GtkWidget
GtkWidget *spice_usb_device_widget_new(SpiceSession *session,const gchar *device_format_string)
{return g_object_new(SPICE_TYPE_USB_DEVICE_WIDGET,"orientation", GTK_ORIENTATION_VERTICAL,"session", session,"device-format-string", device_format_string,"spacing", 6,NULL);
}
2、通过构造函数绑定usb_device_manager
static void spice_usb_device_widget_constructed(GObject *gobject)
{SpiceUsbDeviceWidget *self;SpiceUsbDeviceWidgetPrivate *priv;GPtrArray *devices = NULL;GError *err = NULL;gchar *str;self = SPICE_USB_DEVICE_WIDGET(gobject);priv = self->priv;if (!priv->session) {g_error("SpiceUsbDeviceWidget constructed without a session");}priv->label = gtk_label_new(NULL);str = g_strdup_printf("<b>%s</b>", _("Select USB devices to redirect"));gtk_label_set_markup(GTK_LABEL (priv->label), str);g_free(str);gtk_label_set_xalign(GTK_LABEL(priv->label), 0.0);gtk_label_set_yalign(GTK_LABEL(priv->label), 0.5);gtk_box_pack_start(GTK_BOX(self), priv->label, FALSE, FALSE, 0);//获取usb_device_managerpriv->manager = spice_usb_device_manager_get(priv->session, &err);if (err) {spice_usb_device_widget_show_info_bar(self, err->message,GTK_MESSAGE_WARNING,"dialog-warning");g_clear_error(&err);return;}//新增USB设备的信号,界面进行相应处理g_signal_connect(priv->manager, "device-added",G_CALLBACK(device_added_cb), self);//删除USB设备的信号,界面进行相应处理g_signal_connect(priv->manager, "device-removed",G_CALLBACK(device_removed_cb), self);//USB设备错误信号,界面进行相应处理g_signal_connect(priv->manager, "device-error",G_CALLBACK(device_error_cb), self);//清空界面USB设备列表spice_usb_device_widget_add_empty_cd(self);//首次获取当前已经连接的USB设备并显示devices = spice_usb_device_manager_get_devices(priv->manager);if (devices != NULL) {int i;for (i = 0; i < devices->len; i++) {device_added_cb(NULL, g_ptr_array_index(devices, i), self);}g_ptr_array_unref(devices);}spice_usb_device_widget_update_status(self);
}
3、核心usb_device_manager的对外接口
//获取格式描述
SPICE_GTK_AVAILABLE_IN_0_8
gchar *spice_usb_device_get_description(SpiceUsbDevice *device, const gchar *format); //获取指针
SPICE_GTK_AVAILABLE_IN_0_27
gconstpointer spice_usb_device_get_libusb_device(const SpiceUsbDevice *device);//获取管理器句柄SpiceUsbDeviceManager
SPICE_GTK_AVAILABLE_IN_0_8
SpiceUsbDeviceManager *spice_usb_device_manager_get(SpiceSession *session,GError **err);//获取设备列表
SPICE_GTK_AVAILABLE_IN_0_8
GPtrArray *spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *manager);//过滤出设备列表
SPICE_GTK_AVAILABLE_IN_0_20
GPtrArray* spice_usb_device_manager_get_devices_with_filter(SpiceUsbDeviceManager *manager,const gchar *filter);//usb是否已经连接
SPICE_GTK_AVAILABLE_IN_0_8
gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device);//异步连接设备,结果通过回调函数GAsyncReadyCallback返回
SPICE_GTK_AVAILABLE_IN_0_8
void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device,GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data);//异步断开设备,结果通过回调函数GAsyncReadyCallback返回
SPICE_GTK_AVAILABLE_IN_0_32
void spice_usb_device_manager_disconnect_device_async(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device,GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data);//在spice_usb_device_manager_connect_device_async的GAsyncReadyCallback回调函数中,可以获取连接结果
SPICE_GTK_AVAILABLE_IN_0_8
gboolean spice_usb_device_manager_connect_device_finish(SpiceUsbDeviceManager *manager,GAsyncResult *res,GError **err);//在spice_usb_device_manager_disconnect_device_async的GAsyncReadyCallback回调函数中,可以获取断开结果
SPICE_GTK_AVAILABLE_IN_0_32
gboolean spice_usb_device_manager_disconnect_device_finish(SpiceUsbDeviceManager *manager,GAsyncResult *res,GError **err);//过时接口
#ifndef SPICE_DISABLE_DEPRECATED
SPICE_GTK_DEPRECATED_IN_0_32_FOR(spice_usb_device_manager_disconnect_device_async)
void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device);
#endif//能否重定向
SPICE_GTK_AVAILABLE_IN_0_10
gboolean spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device,GError **err);//判断是否在USB重定向,弹出提示告诉用户
SPICE_GTK_AVAILABLE_IN_0_32
gboolean spice_usb_device_manager_is_redirecting(SpiceUsbDeviceManager *manager);//创建共享的CDROM设备
SPICE_GTK_AVAILABLE_IN_0_38
gboolean spice_usb_device_manager_create_shared_cd_device(SpiceUsbDeviceManager *manager,gchar *filename,GError **err);//是CDROM设备
SPICE_GTK_AVAILABLE_IN_0_38
gboolean spice_usb_device_manager_is_device_shared_cd(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device);//文件描述符分配USB操作句柄
SPICE_GTK_AVAILABLE_IN_0_40
SpiceUsbDevice *spice_usb_device_manager_allocate_device_for_file_descriptor(SpiceUsbDeviceManager *manager,int file_descriptor,GError **err);
4、USB设备描述字符串,显示给用户看
gchar *spice_usb_backend_device_get_description(SpiceUsbDevice *dev, const gchar *format)
{guint16 bus, address, vid, pid;gchar *description, *descriptor, *manufacturer = NULL, *product = NULL;g_return_val_if_fail(dev != NULL, NULL);bus = dev->device_info.bus;address = dev->device_info.address;vid = dev->device_info.vid;pid = dev->device_info.pid;if ((vid > 0) && (pid > 0)) {descriptor = g_strdup_printf("[%04x:%04x]", vid, pid);} else {descriptor = g_strdup("");}if (dev->libusb_device) {spice_usb_util_get_device_strings(bus, address, vid, pid, &manufacturer, &product);} else {product = device_ops(dev->edev)->get_product_description(dev->edev);}if (!format) {format = _("%s %s %s at %d-%d");}description = g_strdup_printf(format, manufacturer ? manufacturer : "",product, descriptor, bus, address);g_free(manufacturer);g_free(descriptor);g_free(product);return description;
}
5、是否为CDROM设备
gboolean
spice_usb_device_manager_is_device_shared_cd(SpiceUsbDeviceManager *manager, SpiceUsbDevice *device)
{
#ifdef USE_USBREDIR/* TODO This function currently return TRUE for all emulated* devices. Currently only shared CDs are implemented as shared* devices but this will break adding new emulated devices.* Check VID/PID in the future.*/gboolean is_cd = (spice_usb_backend_device_get_libdev(device) == NULL);return is_cd;
#elsereturn FALSE;
#endif
}gconstpointer spice_usb_backend_device_get_libdev(const SpiceUsbDevice *dev)
{return dev->libusb_device;
}