前言
衆所周知,spice的拖拽特性只支持從主機到客戶機,不支持從客戶機到主機,即便是最新版本也無該功能支持。我針對公司的桌面雲開發了該功能,注意我的大部分涉及產品的博客都只講原理不放代碼,望理解。
客戶機 – 虛擬機。
主機 – 運行spice-gtk的終端設備。
spice-gtk: 運行在主機端。
spice-vdagent: 運行在客戶機端。
1)從主機到客戶機的拖拽原理:
主機到客戶機拖拽相對好實現,因爲spice-gtk直接利用gtk2.0/3.0的特性,獲取拖入widget文件的路徑,之後首先在client端通過socket將文件數據發送到qemu端,qemu通過libspice-server將數據發送到客戶機端,而客戶機通過/dev/virtio-ports/下的設備來和qemu通信。
2)從客戶機到主機的拖拽思路:
理解了從主機到客戶機的拖拽思路後,客戶機到主機的拖拽思路也與此類似,唯一的難點在於文件路徑的獲取。
3)如何獲取客戶機中希望拖拽到主機的文件路徑?
我的想法是在鼠標左鍵按下時,在spice-gtk端通過調用gdk_display_warp_pointer激活鼠標陷入,並在鼠標移動到spice widget邊緣時觸發信號禁止鼠標移動,此時spice-gtk發送VD_AGENT_FILE_XREAD_DND_WINDOW信號到spice-vdagent端,之後客戶機通過XCreateWindow在鼠標所在位置創建一個100x100的透明window,並通過XPending等待信號,當等待到第一個XdndEnter信號時,發送VD_AGENT_DND_WINDOW_REPLY到spice-gtk端,spice-gtk獲取到信號後開始發送釋放鼠標的信號,之後spice-vdagent端就能獲取到該文件路徑,並且摧毀window。
4)調用流程圖如下:
注:vdagentd是一個daemon,不含x11相關的對象,所以window的創建必須在vdagent中完成。
基本時序圖如上,後面就是文件拷貝的細節不例舉了。
5)結論
可能會有不同的實現方式,不過這套流程實際測試和後續使用中還是驗證過了,其中重點在於vdagent一定要收到了xwindow的XdndEnter信號後纔回發VDAGENT_DND_PATH_REPLY,而非在prepare drop target window完成後即回發。