X Window中提供了三种方式实现client之间的传输数据。(这里强调,这种数据传输不同于我们所说的进程间通信,由于X环境的特殊性,两个client可以运行于两个互不联通网络环境中,而在同一个x server中显示。)这三种方式分别为:selections、cut buffers和drag-and-drop。这里只介绍前两种,至于darg-and-drop方式,它与selections相关,这里就不进行介绍了。
首先,Copy&Paste有主动和被动模式之分。主动模式就是在数据的传输过程中,数据的所有者要参与整个过程,若数据所在的窗口或者整个程序关闭,数据也就不存在。selections和drag-and-drop属于主动模式。而cut buffers方式属于被动模式,当数据被选中并传输到cut buffer后,这些数据就一直存在cut buffer中,数据的所有者不用参与到后续的过程。
先介绍selections 的工作原理。
X window 支持任意数量的selections。但是,我们最常见的只有两种selection。一种叫Primary selection,当我们在窗口中选中目标对象,该对象就被存放在Primary selection中,当我们在另一个窗口中单击鼠标的中间键,就会将Primary selection中的数据加入到当前窗口中;另一种叫Clipboard selection。当我们选中目标对象后,在菜单栏中选择编辑-复制,就会将该对象存入Clipboard selection中。我们可以通过xclip这个程序看查看Primary selection和Clipboard selection的内容。这里就不对这个命令进行介始。可以参考xclip命令的使用。
selections的工作过程如下:
1.对象被选中后,对应的client通过XSetSelectionOwner()函数,向x server宣告对该selection的所用权;
XSetSelectionOwner(display, selection, owner, time)
Display *display;
Atom selection;
Window owner;
Time time;
这个函数是告知server owner窗口拥有这个display下的selection的所有权。
2.当要粘贴时,要求者requester通过XConvertSelection()函数对selection进行请求;
XConvertSelection(display, selection, target, property, requestor, time)
Display *display;
Atom selection, target;
Atom property;
Window requestor;
Time time;
这个函数是告诉server,它希望把dipslay下面的selection中的内容转换在target格式,然后写入到requestor窗口的property属性中。
3.此时,Owner会收到SelectionRequest Event消息;
SelectionRequest
owner :WINDOW
selection :ATOM
target :ATOM
property :ATOM or None
requestor :WINDOW
time :TIMESTAMP or CurrentTime
这条消息的意思是希望owner窗口将它所拥有的selection转换成target格式,然后存入requestor窗口的property属性中。
4.不管成功与否,requestor都会收到SelectionNotify 消息;
SelectionNotify
requestor :WINDOW
selection, target :ATOM
property :ATOM or None
time :TIMESTAMP or CurrentTime
若成功,client就从requestor窗口的property属性中读取数据,最后使用XGetWindowProperty, delete=True把property删除。
5.Owner得到PropertyNotify消息,被告知数据已经传送完毕。
以上就是使用selection进行copy&paste的简单过程。事实上,如果传输的数据量很大,数据将分成多块进行传送,但是原理不变。
前面说到另外一种数据传输方式--cut buffers,cut buffers是一种比selections简单得多,但是低效的peer-to-peer communication,现在已经被遗弃了。但是有一些老的软件仍然支持它。还有如Xvnc这样的软件,里面就只实现cut buffers。cut buffers是一种被动的数据传输模式,只支持文本的copy,并且不能像selections那样进行格式转换。
cut buffers方式使用了在screen0 的root window中的8个cut buffers属性进行数据存取。这8个属性的以CUT_BUFFER0~CUT_BUFFER7进行命名。当Owner每次存入数据前,要先确定CUT_BUFFER属性是否存在,然后对这8个属性进行“反转”,即将CUT_BUFFER0 改名为CUT_BUFFER1,CUT_BUFFER1改名为CUT_BUFFER2……,CUT_BUFFER7改名为CUT_BUFFER0,然后再将数据存入CUT_BUFFER0。Requestor在读取完CUT_BUFFER0 后,也要做一次“反转”,将CUT_BUFFER7变成CUT_BUFFER6,CUT_BUFFER6变成CUT_BUFFER5……CUT_BUFFER0 变成CUT_BUFFER7。cut buffers的低效也可以从这里很明显地看出来。
参考:
http://en.wikipedia.org/wiki/X_Window_selection
http://www.jwz.org/doc/x-cut-and-paste.html
http://tronche.com/gui/x/icccm/sec-2.html
http://fanqiang.chinaunix.net/a4/b8/20010602/180800316_b.html