国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

Spice下命令spicy的USB重定向過(guò)程分析

2019-11-06 06:33:33
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

在spice-gtk-0.30內(nèi)部有一個(gè)spicy命令用于鏈接遠(yuǎn)程的虛擬機(jī), 例如spicy -h 172.16.3.4 -p 6700 這樣就可以鏈接到虛擬桌面 其客戶端有個(gè)USB 設(shè)備重定向管理功能,在spicy內(nèi)有個(gè)Input選項(xiàng)卡,其子項(xiàng)有個(gè)“Select USB Devices for redirection”。選擇重定向USB 設(shè)備,點(diǎn)開(kāi)后就會(huì)出現(xiàn)列有USB設(shè)備的對(duì)話礦對(duì)話框,就可以選擇USB 設(shè)備進(jìn)行重定向。其如下圖所示: 這里寫(xiě)圖片描述 彈出的對(duì)話況如下所示: 這里寫(xiě)圖片描述 可以看到所有的USB設(shè)備都一GTK CheckButton的形式列出來(lái)了,那么當(dāng)選中里面的USB設(shè)備時(shí),本地的USB設(shè)備就會(huì)被重定向到虛擬桌面Win7下面: 其實(shí)現(xiàn)的流程如下: 這里寫(xiě)圖片描述

相關(guān)源文件:spicy.c、usb-device-manager.c、channel-usbredir.c、usb-device-widget.c 在usb-device-widget.c中的代碼如下:

static GObject *spice_usb_device_widget_constructor( GType gtype, guint n_PRoperties, GObjectConstructParam *properties){ GObject *obj; SpiceUsbDeviceWidget *self; SpiceUsbDeviceWidgetPrivate *priv; GPtrArray *devices = NULL; GError *err = NULL; GtkWidget *label; gchar *str; int i;printf("spice_usb_device_widget_constructor-------------usb-device-widget.c/n"); { /* 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"); label = gtk_label_new(NULL);//創(chuàng)建lable控件 str = g_strdup_printf("<b>%s</b>", _("Select USB devices to redirect"));//控件的內(nèi)容 gtk_label_set_markup(GTK_LABEL (label), str);//設(shè)置lable字體屬性 g_free(str); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);//設(shè)置對(duì)齊 gtk_box_pack_start(GTK_BOX(self), label, FALSE, FALSE, 0);//啟動(dòng)容器 priv->manager = spice_usb_device_manager_get(priv->session, &err);//從session中獲取manager 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);//設(shè)置回調(diào)函數(shù)用于處理USB熱插拔 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);//從manager內(nèi)獲取device列表是根據(jù)filter去獲取過(guò)濾USB設(shè)備規(guī)則,但是此處是將所有的USB設(shè)備都呈現(xiàn),因此filter為空 devices = spice_usb_device_manager_get_devices(priv->manager); if (!devices) goto end; for (i = 0; i < devices->len; i++)//以gtk內(nèi)checkbutton控件的模式列出所有設(shè)備 { device_added_cb(NULL, g_ptr_array_index(devices, i), self); printf("xxxxxxxxxxxxxxx--usb-device-widget.c/n"); } g_ptr_array_unref(devices);//清空devicesend: spice_usb_device_widget_update_status(self);//更新控件狀態(tài) return obj;}

在對(duì)話框構(gòu)建constructor內(nèi)會(huì)為每個(gè)USB設(shè)備建立CheckButton控件,如下:

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 *align, *check; gchar *desc;printf("device_added_cb-----usb-device-widget.c/n"); desc = spice_usb_device_get_description(device,//獲取usb設(shè)備描述符 priv->device_format_string); check = gtk_check_button_new_with_label(desc);//創(chuàng)建checkbutton g_free(desc);//創(chuàng)建完畢后就釋放掉 if (spice_usb_device_manager_is_device_connected(priv->manager,//檢測(cè)usb設(shè)備是否鏈接狀態(tài)如果是連接的就設(shè)置checkbutton為真 device)) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);//設(shè)置checkbutton為T(mén)ure g_object_set_data_full(//設(shè)置數(shù)據(jù)和回調(diào)函數(shù) 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",//注冊(cè)點(diǎn)擊checkbutton事件 G_CALLBACK(checkbox_clicked_cb), self);//當(dāng)點(diǎn)擊事件觸發(fā)時(shí)調(diào)用回調(diào)函數(shù)checkbox_clicked_cb align = gtk_alignment_new(0, 0, 0, 0);//創(chuàng)建對(duì)齊控件 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0); gtk_container_add(GTK_CONTAINER(align), check);//在checkbutton中添加對(duì)齊方式 gtk_box_pack_end(GTK_BOX(self), align, FALSE, FALSE, 0); spice_usb_device_widget_update_status(self);//更新usb控件狀態(tài) gtk_widget_show_all(align);}

在建立成功后注冊(cè)CheckButton的選中點(diǎn)擊事件:

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");//獲取數(shù)據(jù) if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check))) {//獲取checkbutton的狀態(tài),為T(mén)ure connect_cb_data *data = g_new(connect_cb_data, 1); data->check = g_object_ref(check); data->self = g_object_ref(self); printf("checkbox_clicked_cb---true-------usb-device-widget.c/n"); spice_usb_device_manager_connect_device_async(priv->manager,//重定向設(shè)備 device, NULL, connect_cb, data); } else {//如果狀態(tài)為False則斷開(kāi)鏈接 printf("checkbox_clicked_cb---false-------usb-device-widget.c/n"); spice_usb_device_manager_disconnect_device(priv->manager,//斷開(kāi)channel與device device); } spice_usb_device_widget_update_status(self);}

到此兩個(gè)事件,一個(gè)選中事件則調(diào)用spice_usb_device_manager_connect_device_async對(duì)該USB 設(shè)備俄進(jìn)行重定向 另一個(gè)取消選中,就會(huì)掉用spice_usb_device_manager_disconnect_device,斷開(kāi)channel和device的鏈接,取消重定向,

一先看看簡(jiǎn)單的取消的過(guò)程:這個(gè)函數(shù)在usb-device-manager.c文件內(nèi)定義如下:

void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self, SpiceUsbDevice *device){ g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self)); g_return_if_fail(device != NULL);//device為空退出 SPICE_DEBUG("disconnecting device %p", device);printf("spice_usb_device_manager_disconnect_device,disconnecting device %p ------usb-device-manager.c/n",device);#ifdef USE_USBREDIR SpiceUsbredirChannel *channel; channel = spice_usb_device_manager_get_channel_for_dev(self, device);//根據(jù)device獲取channel if (channel) spice_usbredir_channel_disconnect_device(channel);//清空channel內(nèi)的相關(guān)device并設(shè)置狀態(tài) #ifdef G_OS_WIN32 //沒(méi)有在windows下使用,因此代碼省略注銷 #endif #endif}

在這個(gè)函數(shù)內(nèi)部首先根據(jù)device獲取相匹配的Channel,在對(duì)Channel內(nèi)的device進(jìn)行清空:

static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev( SpiceUsbDeviceManager *manager, SpiceUsbDevice *device){#ifdef USE_USBREDIR SpiceUsbDeviceManagerPrivate *priv = manager->priv; guint i; for (i = 0; i < priv->channels->len; i++) {//獲取device相對(duì)應(yīng)的channel SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);//獲取channel libusb_device *libdev = spice_usbredir_channel_get_device(channel); if (spice_usb_device_equal_libdev(device, libdev))//如果兩者匹配就返回channel return channel;//返回device對(duì)應(yīng)的channel }#endif return NULL;}

清空函數(shù)spice_usbredir_channel_disconnect_device在channel-usbredir.c內(nèi)部

void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel){ SpiceUsbredirChannelPrivate *priv = channel->priv; CHANNEL_DEBUG(channel, "disconnecting device from usb channel %p", channel); printf("spice_usbredir_channel_disconnect_device, priv->state=%d---------channel-usbredir.c/n",priv->state); switch (priv->state) { case STATE_DISCONNECTED: case STATE_DISCONNECTING: break;#if USE_POLKIT case STATE_WAITING_FOR_ACL_HELPER: priv->state = STATE_DISCONNECTING; /* We're still waiting for the acl helper -> cancel it */ spice_usb_acl_helper_close_acl(priv->acl_helper); break;#endif case STATE_CONNECTED://設(shè)備處于鏈接狀態(tài) /* * This sets the usb event thread run condition to FALSE, therefor * it must be done before usbredirhost_set_device NULL, as * usbredirhost_set_device NULL will interrupt the * libusb_handle_events call in the thread. */ printf("STATE_CONNECTED --------channel-usbredir.c/n"); { SpiceSession *session = spice_channel_get_session(SPICE_CHANNEL(channel));//從SpiceChannel中獲取session if (session != NULL) spice_usb_device_manager_stop_event_listening(//停止監(jiān)聽(tīng) spice_usb_device_manager_get(session, NULL));//獲取USBmanager即從SpiceSession獲取SpiceUsbDeviceManager } /* This also closes the libusb handle we passed from open_device */ usbredirhost_set_device(priv->host, NULL);//清空usbhost libusb_unref_device(priv->device);//去掉引用計(jì)數(shù) priv->device = NULL;//清空設(shè)備 g_boxed_free(spice_usb_device_get_type(), priv->spice_device);//清空 priv->spice_device = NULL; priv->state = STATE_DISCONNECTED;//設(shè)置狀態(tài)為斷開(kāi)狀態(tài) break; }}

可以看到在該channel內(nèi)的device被清空了,首先就是要告知manager停止對(duì)該device的事件監(jiān)聽(tīng),退出這個(gè)device的事件線程,

spice_usb_device_manager_stop_event_listening如下:void spice_usb_device_manager_stop_event_listening( SpiceUsbDeviceManager *self){ SpiceUsbDeviceManagerPrivate *priv = self->priv; g_return_if_fail(priv->event_listeners > 0); priv->event_listeners--;//運(yùn)行監(jiān)聽(tīng)計(jì)數(shù)減1 printf("priv->event_listeners--= %d-----usb-device-manager.c/n",priv->event_listeners); if (priv->event_listeners == 0) priv->event_thread_run = FALSE;//設(shè)置線程運(yùn)行開(kāi)關(guān)為FALSE用來(lái)關(guān)閉該線程}
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 贵阳市| 锦州市| 灵石县| 大悟县| 青铜峡市| 原阳县| 新昌县| 通化县| 基隆市| 莱芜市| 武安市| 蓬莱市| 钦州市| 吉林省| 嘉黎县| 苏尼特右旗| 建湖县| 凤翔县| 轮台县| 南丹县| 荣昌县| 朝阳市| 南靖县| 班玛县| 炎陵县| 宝坻区| 大渡口区| 渭南市| 宿迁市| 鸡西市| 中山市| 汉阴县| 中方县| 信阳市| 台南县| 远安县| 定日县| 磐石市| 罗定市| 中西区| 四平市|