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_manager
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,"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;
#else
return FALSE;
#endif
}
gconstpointer spice_usb_backend_device_get_libdev(const SpiceUsbDevice *dev)
{
return dev->libusb_device;
}