原理介绍
在 X11 中,剪贴板被称为selection,使用的是X11中的ICCCM协议,窗口间通信协议。
X11 剪贴板是 X Window 系统中的一种机制,用于在应用程序之间复制和粘贴文本、图像等数据。X11 提供了多种选择(Selection)用于处理剪贴板操作,主要包括 PRIMARY、SECONDARY 和 CLIPBOARD 三种。
selection的协议内容见: ,当你把这些通信都调用一遍,你应该就能理解X11剪贴板是如何工作的。
或者参考:
参考这些内容实现了一个剪贴板,并按需要做了小量的改动,记录步骤和说明如下文。
首先要了解了X11中属性 Property这个概念,窗口管理ICCCM和EWMH协议的实现都是通过Property里的数据来实现的。在我的另一篇文档中有说明属性是如何使用的。剪贴板操作也是通过传递Property来实现数据在不同的窗口间复制粘贴。
具体步骤
当复制发生时,需要先设置本身为剪贴板的owner,通过XSetSelectionOwner函数来修改,成为owner后就可以收到SelectionClear/SelectionRequest事件,SelectionClear是另一个窗口获取剪贴板owner,SelectionRequest是另一个窗口来获取剪贴板内容,如果是获取"TARGETS ",则是想获取剪贴板里面的数据有哪些Property,如果是获取其他指定Property,则是真正的获取Property对应的数据了。
//复制文件后
:~$ xclip -o -target TARGETS -selection clipboard
peony-qt/is-cut
text/uri-list
text/x-moz-url
text/plain
peony-qt/encoded-uris
UTF8_STRING
STRING
TEXT
TARGETS
MULTIPLE
TIMESTAMP
SAVE_TARGETS
//然后获取指定Property
~$ xclip -o -target text/uri-list -selection clipboard
file:///home/warlice/i3.log
~$ xclip -o -target peony-qt/is-cut -selection clipboard
false
//复制文本后
~$ xclip -o -target TARGETS -selection clipboard
text/plain
UTF8_STRING
STRING
TEXT
TARGETS
MULTIPLE
TIMESTAMP
SAVE_TARGETS
//然后获取指定Property
~$ xclip -o -target text/plain -selection clipboard
arlice
简单描述一般窗口发生复制粘贴的通信步骤如下:
A window copy(control + c) :
XSetSelectionOwner
XChangeProperty TARGET
XChangeProperty anytype
B window paste(control + v) :
A window
while OnSelectionRequest target
A window XSendEvent target
B window SelectionRequest property in target
A window
while OnSelectionRequest property in target
A window XSendEvent anyproperty
最终B window XGetWindowProperty from A window
从上面的步骤可以看出,实际在处理SelectionRequest事件返回的XSendEvent时,把Property提供给请求者就完成了粘贴操作。 但是有一个问题,如果做为owner的窗口关闭了,就相当于剪贴板没有复制过了,所以X11上有一些框架就自带剪贴板窗口,即使提供数据的窗口程序退出了,数据也还保存在剪贴板窗口上。
需要一个 clipboard manager进程作为 clipboard 的 owner。 当其它进程进行复制操作成为 owner 时,clipboard manager应当进行以下操作:
向新的 owner 询问所有数据,并将这些数据保存起来;
重新将自己声明为 owner。
简单描述自定义实现的剪贴板管理器的步骤如下:
XSetSelectionOwner
till OnSelectionClear
XConvertSelection
while SelectionNotify
XChangeProperty target/anyproperty
XSetSelectionOwner
while OnSelectionRequest target
XSendEvent target
while OnSelectionRequest anyproperty
XSendEvent anyproperty
最终window XGetWindowProperty from ClipBoardManager
在收到SelectionClear事件时,将所以复制的内容都XConvertSelection到自己这个窗口上,包括TARGETS 和所有类型的内容,并且可以取出来想到的类型数据保存,再通过XSetSelectionOwner将当前窗口重新设置为owner。在收到SelectionRequest事件时,按需要返回TARGET类型和对应类型的内容。
即可以实现,实时获取剪贴板数据和更新自定义数据到剪贴板,具体在我们的实现中就是将复制的内容传给Android,并且在Android复制后,将内容写进UTF8_STRING属性,清除其他属性,实现Android和Linux的剪贴板同步。
现在还只实现了在Xserver内的所有类型复制,Xserver和Android的剪贴板只实现了文本同步,实际上文件复制同步只是对不同类型的复制内容的处理实现罢了。