X Window核心协议

X Window 核心协议[1][2][3]X窗口系统的基础协议,它是一个以位图显示的网络化视窗系统,用来在Unix类Unix和其它操作系统上建立用户图形界面。X Window 系统基于主从式模型:单一服务器控管硬件输出入,如屏幕键盘鼠标;所有的应用程序都被视作客户端用户之间透过服务器来交互。交互部分由X Window核心协议来管理。还有其它与X窗口系统有关的协议,有的建立在X Window核心协议之上的,有的是独立的协议。

X Window 系统的标志

在X Window核心协议中,只会在网络上以异步方式发送四种数据包:请求、回应、事件和错误。请求是由客户端发送到服务器,告之进行一些动作(例如建立一个视窗),并回传以便持握的资料。回应是由服务器回传的若干资料。事件是由服务器发送的,其用来通知客户端某些用户的动作,或者发生了其它所关心的事件。错误是由服务器发送的数据包,其用来通知客户端,在处理其请求时,发生了一些错误。请求有可能产生回应、事件和错误;除此之外,协议并不要求数据包中的特定指令要以网络来发送。还有其它对核心协议的扩展,这些扩展有自己的请求、回应、事件和错误。

X Window 源于1984年的麻省理工学院(目前所发布的 X11 发表于1987年9月)。设计者鲍伯·斯凯夫勒(Bob Scheifler)和吉姆·杰提斯(Jim Gettys)早期对核心协议的原则是“机制,而非策略”,所以核心协议并未规定客户端之间以及客户端和用户之间的交互界面规范。这部分则由其它的独立规格[4]所规范,如ICCCMfreedesktop.org规范,且可由所使用的特定组件工具包自动强制执行。

概观

服务器和客户端之间的通信,是由通道上的交换数据包所完成。由客户端建立连接,且由客户端发送第一个数据包。数据包中包括将要使用的字节序、协议版本方面的信息,以及客户端期望服务器使用的认证种类。服务器以回传数据包来答复,数据包中陈述接受或拒绝连接,或要求进一步的验证。如果接受连接,接受数据包内会包含客户端接下来和服务器交互所需的资料。

 
客户端和服务器之间的交互示例。

建立连接之后,在客户端和服务器的通道上,会有四种交换数据包的类型:

  1. 请求:客户端请求服务器的信息,或者请求服务器执行一个动作。
  2. 回应:服务器回应请求。但并非所有的请求都会产生回应。
  3. 事件:服务器发送事件给客户端。如:键盘或鼠标的输入,或移动、调整、显示视窗等。
  4. 错误:如果请求无效时,服务器会发送一个错误数据包。因为请求是以排队方式处理,所以经由请求所产生的错误数据包,并不会立即发送出去。

请求和回应数据包可以有各种长度,事件和错误数据包的长度则固定是32字节

请求数据包的编号顺序是以服务器的接收为顺序:来自客户端的第一个请求编号为 1、第二个编号为 2,依此类推。请求的序列编号中最小的有效16位,包含在由请求所产生的回应和错误数据包之中,如果有的话。它们也包含在事件数据包中,以指出服务器正在处理或是刚刚完成的请求序列编号。

视窗

在X窗口系统以及各种图形化用户界面中,视窗即为一个顶层视窗。视窗也用来指视窗内部的视窗,这类视窗是父视窗的子视窗。图形化组件,如按钮菜单图标等等,都是使用视窗来实现的。

 
视窗可能的放置情形:1 是根视窗,与整个屏幕对应;2 和 3 是顶层视窗;4 和 5 是 2 的子视窗。超出父视窗的部分不会显示出来。

客户端可请求建立一个视窗。更严谨的说,客户端可请求建立现存视窗的子视窗。所以客户端所建立的视窗,皆以树状结构组织(层次结构结构)。树状结构的根即为根视窗,根视窗是服务器在启动时,所自动建立的特殊视窗。其余视窗都是根视窗的子视窗,顶层视窗就是根视窗下的第一个子视窗。如图所见,根视窗和屏幕同等大小,且在其余视窗的后面(被子视窗遮盖住)。

视窗里的内容并非在所有时候都能显示出来。更精确地说,在视窗移动、调整大小、被其它视窗遮盖、部分或整个视窗不可见时,视窗里的内容就有可能会被销毁。更精确地说,如果 X 服务器无法维护视窗内容的后备存放区(backing store)时,这些内容就会丢失。客户端可请求为视窗进行维护的后备存放区,但服务器没有义务要这样做。因此,客户端不可假设已得到后备存放区的维护。若视窗有一部分未指出内容时,就会发送一个事件,通知客户端重绘那部分内容。

每个视窗都关系一组属性值(Attribute),如视窗的几何性质(大小和位置)、背景图、是否请求了后备存放区等等。协议中还包含用来给客户端检阅和改变视窗属性值的请求。

视窗可以是 InputOutput(输出/输入)或 InputOnly(仅输入)。前者是显示在屏幕上用于绘图的视窗,而后者并不显示在屏幕上,仅用来接受输入。

 
FVWM视窗的结构。中央的大块白色区域是由客户端应用程序所建立的视窗。

平常可看到视窗周围的装饰性框架和标题栏(可能含有按钮),是由视窗管理器所建立的视窗,而非客户端所建立的。视窗管理器也处理与组件有关的输入,例如当用户点击并拖曳视窗的边框时,便会调整视窗大小。客户端所建立的视窗,通常可以忽略视窗管理器所带来的变化。还有一个改变必须注意,那就是改变亲属关系的视窗管理器,几乎所有新式的视窗管理器,都会将顶层视窗的亲属关系改变到一个视窗(不是根视窗)里去。从核心协议的角度来看,视窗管理器是一个客户端,与其它的应用程序没有区别。

关于视窗的资料,可执行 xwininfo 程序来获取。加上 -tree命令行参数,程序便会显示子视窗的树状结构,连同识别子和几何性质资料一起显示。

图形映射和可绘区

图形映射(pixmap)是存储器中可用来绘图的区域。与视窗不同,图形映射的内容并不会自动显示在屏幕上。不过图形映射的内容(或部分内容)可转换到视窗上,反之亦然。这就让双缓冲得以实现。大部分可在视窗上完成的图形化操作,也可以图形映射完成。

视窗和图形映射被统称为可绘区(drawable),且其资料内容都保留在服务器上。客户端可请求从服务器上,将可绘区的内容转换到客户端,反之亦然。

图形上下文和字体

客户端可请求很多种图形运算,如清空一块区域、复制一块区域到另一处,绘制一个点、线、矩形和文字。对清空而言,所有运算都有可能用在可绘区上(视窗和图形映射)。

图形上下文graphic context)包括了对图形运算的大部分请求,图形上下文是一种结构,包含有图形运算的参数。图形上下文包含前景色、背景色、文字的字体,以及各种图形参数。当请求图形运算时,客户端就包含一个图形上下文。很明显的,并非所有的图形上下文参数都会参与运算:例如,字体对于直线的绘制不产生作用。

核心协议规格使用了服务器侧的字体[5]。如字体是以文件形式存放,服务器经由本机的文件系统直接访问,或经由网络从字体服务器访问。客户端可向服务器请求有效的字体列表,且可请求服务器加载(没有的话)或卸载(客户端不再需要的话)字体。客户端可请求关于字体的信息(例如,ascent 字体),并以指定的字体来绘制指定的字符串。

 
xfontsel 程序可让用户查看字体的标记。

在X Window核心协议的层次上,字体的名称可以是任意的字符串。X 逻辑字体描述协议[6]规范了如何根据字体的属性来命名。这些协议也规范了可附属于字体的选用属性之值(value)。

xlsfonts 程序可输出存放在服务器上的字体列表。xfontsel 程序可显示字体的标记,并让用户选取字体的名称,以在其它视窗中粘贴。

目前已不再重视服务器侧字体的使用,而转向客户端侧字体的使用[7]。例如,借由支持Xftcairo程序库,以及XRender扩展,改由客户端(而非服务器)绘制字体。客户端侧字体在核心协议中尚未给出规范。

资源和识别子

所有关于视窗的资料、图形映射、字体等等,皆存放在服务器上。客户端知道那些对象的识别子,和服务器交互时,对象以整数为名称。例如,当客户端希望建立一个视窗时,便指定一个识别子,并请求服务器建立一个视窗。服务器会建立一个视窗,并与指定的识别子关系。稍后客户端可使用这个识别子进行请求,例如在视窗上画上一个字符串。以下存在于服务器上的对象,客户端可借由数值型的识别子得知:

  • 视窗(Window
  • 图形映射(Pixmap
  • 字体(Font
  • 色彩映射(Colormap)(即颜色表,稍后描述)
  • 图形上下文(Graphic context

这些对象就称作资源。当客户端请求建立某一种资源时,同时也为资源指定了一个识别子。例如,为了建立一个新视窗,客户端指定了视窗的属性值(亲属关系、宽、高等等)和识别子,最后识别子会和视窗关系。

识别子是三个最高有效位为0的32位整数。每一个客户端都有一组自己的识别子,其可用来建立新的资源。这组识别子是由服务器以包含在接受数据包(发送给客户端的数据包,通知已接受连接)中的两个整数所指定的。客户端以避免冲突的方式选取识别子:在视窗、图形映射、字体、色彩映射、图形上下文之中的两个对象,不可具有相同的识别子。

资源一经建立,其识别子就用于客户端向服务器请求与之有关的运算。部分运算会影响特定的资源(例如,请求移动视窗),其它的则要求存放在服务器上的资源资料(例如,请求视窗的属性值)。

识别子在服务器上是独一无二的,在多个客户端之间也不例外。例如,即使是由两个不同客户端所建立的视窗,也不会同时具有相同的识别子。即使某个对象不是由自己的客户端所建立的,只要指定相对应的识别子,就可访问另一个客户端所建立的任何对象。

连接到同一服务器的两个客户端,对同一资源可使用同一识别子。例如,若客户端建立一个 0x1e00021 识别子的视窗,并发送数值 0x1e00021 给其它的应用程序(透过任何有效的手法。例如,把数值存放在文件里,且这个文件可让其它的应用程序轻易访问),其它的应用程序即可对同一视窗进行操作。这个例子是来自X Window版本的Ghostview:程序建立一个子视窗,在环境变量中存放其识别子,并调用Ghostscript;程序绘制PostScript文件的内容,以显示在这个视窗上[8]

当建立资源的客户端关闭与服务器的连接时,资源就会正常的销毁。不过在关闭连接之前,客户端可以请求服务器不要销毁资源。

事件

事件是由服务器发送到客户端用以通信的数据包,发送一些客户端可能感兴趣的事情。例如,当用户按下按键或点击鼠标时,便会发送一个事件。事件不只用于输入:例如,发送的事件表明特定视窗建立了新的子视窗。

每一个事件都会涉及到视窗。例如,当用户的鼠标在视窗之内并点击时,这个事件就会涉及到那个视窗。事件数据包中含有那个视窗的识别子。

客户端可以请求服务器发送事件给另一个客户端,这可用于客户端之间的通信。例如,当客户端请求目前所选取的文字时,就会发送事件给客户端,以处理目前所持有的选取内容。

当再度观看内容已被销毁的区域时,有可能会发送 Expose(显露)事件。而且在某些情况下,视窗的内容可能会被销毁。例如,当视窗被其它视窗遮盖住,且服务器没有维护后备存放区时。此时服务器会产生一个 Expose 事件,以通知客户端重绘视窗已消失的部分。

 
事件的示例:当在视窗上按下按键时,会产生事件给客户端(取决于视窗的事件掩码,客户端可以改变事件掩码)。

大部分的事件只会在客户端预先表示关心时才会发送。因为客户端可能只需要关心某类型的事件。例如,客户端可能会关心关于键盘的事件,但却不关心关于鼠标的事件。即使在客户端并未明确请求的情况下,某几类事件也会不断的发送给客户端。

客户端可以设置视窗的属性值(attribute),以指明想要接收哪些事件。例如,当视窗的内容已销毁时,为重绘其内容,客户端就必须接收 Expose 事件,以通知视窗需要再次重绘。客户端要能接收到 Expose 事件,就要预先指明它所关心的事件,这部分可以适当设置视窗属性值的事件掩码来完成。

不同的客户端可以请求同一视窗的事件。甚至可对同一视窗设置不同的事件掩码。例如,某个客户端可以只对视窗请求键盘事件,而另一个客户端只对视窗请求鼠标事件。这是可以的,因为服务器会为每一个客户端维护事件掩码,而且是每一个视窗都维护一份独立的事件掩码。不过偶尔也有某几类事件,只能由一个客户端选择。特别是,这类事件回报鼠标按钮的点击,且部分变化会涉及到视窗管理器。

xev 程序显示视窗所涉及到的事件。xev -id WID 可对识别子为 WID 的视窗要求所有可能的事件,并将其输出。

示例

以下是服务器和程序之间的交互示例,这个程序会建立一个黑框视窗,按下按键后结束。在本例中,服务器并未发送任何回应,因为客户端的请求并不产生回应。这些请求有可能产生错误。

  1. 客户端开通与服务器的连接,并发送初始化数据包,来指定所要使用的比特顺序。
  2. 服务器接受连接(本例中不涉及验证)并发送适当的数据包。这些数据包含有其它的信息,如根视窗的识别子(例如,0x0000002b),以及客户端可建立哪些识别子。
  3. 客户端请求以 0x00200000 识别子建立一个默认的图形上下文(此一请求如同本例中的其余请求,并不会产生来自服务器的回应)。
  4. 客户端请求服务器以 0x00200001 识别子、大小 200x200、位置 (10,10) 等等,来建立一个顶层视窗(这部分指定以根视窗 0x0000002b 为父视窗)。
  5. 客户端请求改变视窗 0x00200001 的属性值(attribute),规定视窗要接收 Expose(显露)和 KeyPress(按键)事件。
  6. 客户端请求映射(显示在屏幕上)视窗 0x00200001
  7. 当视窗可见,且必须绘出其内容时,服务器传给客户端一个 Expose(显露)事件。
  8. 客户端对事件做出反应,请求绘制一个方框,它是透过发送与视窗 0x00200001 和图形上下文 0x00200000 一起的 PolyFillRectangle 请求来达成。

如果视窗被其它视窗遮盖住,且再次显露出来时,又刚好没有这部分的备存时:

  1. 服务器发送另一种 Expose(显露)事件,告知客户端必须再次重绘视窗。
  2. 客户端透过发送 PolyFillRectangle 请求的方式重绘视窗。

如果按下按键:

  1. 服务器传给客户端一个 KeyPress(按键)事件,通知它用户按下按键了。
  2. 客户端作出适当的反应(本例是退出程序)。

颜色

在协议层次里,颜色使用32位无负号整数来表示,称为像素值。以下因素会影响颜色的显示:

  1. 色彩深度
  2. 色彩映射(colormap),即含有红、绿、蓝强度值的表。
  3. 视觉类型(visual type),指明表如何用来表示颜色。

在最简单的情况下,色彩映射是一种每一项都含有RGB三值的表。像素值 x 所表示的颜色,就包含在表中第 x 项。如果客户端可以改变色彩映射的内容,那这种表示法就以伪彩色(PseudoColor视觉分类(visual class)来标识。视觉分类中的静态色(StaticColor)与伪彩色类似,只不过客户端不能修改色彩映射的内容。

在此总计有六种可能的视觉分类,每一种都使用不同的方式来表示 RGB 像素值。PseudoColorStaticColor 即其中两种。GrayScaleStaticGray 是另外的两种,其中最主要的差异是灰阶渐层的使用。

剩下的两种视觉分类和前述的差异在于,将像素值分成三个部分,并为红、绿、蓝的强度使用了三个独立的表。并根据这个表来表示颜色,如下流程将像素值转换成RGB色:

  1. 将像素值视为连续的比特序列
  2. 将比特序列分成三个部分
  3. 将每一个部分视为整数、并作为索引,以在这三个独立的表中查找到值。

这个机制需要以三个独立的表组成色彩映射,三个原色各一个表。转换以后仍是强度值的三联色。使用这个表示法的视觉分类有 DirectColorTrueColor,其中的差异是客户端不能修改后者的色彩映射。

以上六种以像素值表示颜色的机制,都需要附加一些参数来运作。这些参数可统合为视觉类型,其包含一个视觉分类和其它参数以表示颜色。每一个服务器都有一组固定的视觉类型,每一个类型都与数值型的识别子关系。其识别子是32位无负号整数,和资源或元素的识别子没有什么不同。

当接受来自客户端的连接时,服务器所发送的接受数据包里含有区块序列,每一个区块都包含有关于某一个单一屏幕的信息。就每一个屏幕而言,相关区块包含着其它区块的清单,每一个都涉及了屏幕所支持的色彩深度。就每一个屏幕所支缓的色度深度而言,这个清单中又包含视觉类型的清单。结果,每一个屏幕就关系著各种合适的色彩深度,而且每一个屏幕的每一个色彩深度都关系著各种合适的视觉类型。一个给定的视觉类型可用于更多的屏幕和各种不同的色彩深度。

就每一个视觉类型而言,接受数据包中还包含它的识别子和它所包含的实际参数(视觉分类等),客户端存放这些信息,因为之后就不能再请求。此外,客户端不能改变或建立新的视觉类型。建立新视窗的请求中,还包含有色彩深度和视觉类型的识别子,以此用来表示视窗的颜色。

色彩映射和控制屏幕的硬件(即绘图卡)是否使用调色板(palette)没有关系。调色板是一个表,也是用来表示颜色的。即使硬件并不使用调色板,服务器也能使用色彩映射。当硬件使用调色板时,就只能安装相当受限的少许色彩映射。更精确地说,当硬件根据色彩映射来显示颜色时,就可以说是安装了色彩映射。客户端可请求服务器安装一个色彩映射。不过需要将另一个色彩映射卸载:其影响是视窗如果使用了卸载的色彩映射,就不能显示正确的颜色,而出现怪异颜色的画面。这个问题可以用标准色彩映射来解决,标准色彩映射是像素值和颜色之间关系恒定的色彩映射。由于有这一性质,就可让不同的应用程序使用标准色彩映射。

色彩映射的建立由ICCCM协议管理。标准色彩映射由ICCCM和Xlib规格管理。

元素

元素(Atoms)是用来表示字符串的32位整数。本协议的设计者之所以引入元素,是为了以简短、大小恒定的方式表示字符串[9]:由于字符串可以是任意的长度,而元素总是32位整数。某些数据包可能会多次发送相同的字符串,元素的简短性可以削减指令所使用的数据包长度,进而增进网络的使用效率。大小恒定的元素有利于大小恒为32位组的事件:大小恒定的数据包可以包含元素,却不能包含过长的字符串。

更严谨的说,元素是存放在服务器上的字符串的识别子,相当于资源的识别子(视窗、图形映射等),但仍有两个不同点。首先,元素的识别子是由服务器选择的,而非客户端。换句话说,当客户端请求建立一个新的元素时,其仅仅发送字符串给服务器存放,而非字符串的识别子;元素的识别子是由服务器选择,并回传给客户端作为回应。其次,资源和元素之间的重大差异是,元素并未与客户端相连系。元素一经建立,就能一直存留至服务器结束或重置(此非资源的默认行为)。

元素是识别子,所以也是独一无二的。不过元素和资源的识别子可以相一致。与元素关系的字符串称作元素名。元素的名称一经建立就不能再更改,而且不能有两个相同名称的元素。故一般以元素的内容作为元素的名称:“元素 ABCD”意谓著,或更精确地说,“这个元素关系的字符串是 ABCD”或“元素的名称是 ABCD”。客户端可以请求建立新的元素,且可请求指定字符串的元素(识别子)。某些元素已预先定义(由服务器以特定的识别子和字符串所建立)。

元素运用于多个目的,主要与连接到同一服务器的不同客户端之间有关。特别是,元素用于与视窗属性的关系,以下详述。

所有存在于服务器上的元素列表,可使用 xlsatoms 程序输出。尤其这个程序可以元素的名称(元素所关系的字符串)列出每一个元素(识别子是一串数字)。

属性

每一个视窗都有一组预先定义的属性值(Attribute)和属性(Property),并存放在服务器上,客户端可以适当的请求方式取存。属性值是有关视窗方面的资料,如视窗的大小、位置、背景色等等。属性则是附属于视窗上的资料片断。与属性值相反,属性在X Window核心协议的层次中并没有其它含意。客户端可在视窗的属性中存放属性值资料。

属性是以名称、类型和值来描述,属性相当于指令式编程语言的变量,应用程序可以指定名称、类型和值来建立新的属性。属性和视窗关系:两个相同名称的属性可存在于两个不同的视窗,且可具有不同的类型和值。

属性的名称、类型和值皆为字符串;更精确地说就是元素,客户端可借由识别字,以访问存放在服务器上的字符串。客户端应用程序可以元素的识别子(含有属性的名称)访问特定的属性。

属性大多用于客户端之间的通信。例如,名称为 WM_NAME(属性名称就是元素所关系的字符串 "WM_NAME")的属性,是用来存放视窗的名称;视窗管理器通常会读取这个属性,并在视窗顶部显示名称。

某些客户端之间的通信也使用了根视窗的属性。例如,根据freedesktop视窗管理器规格[10]视窗管理器应该在根视窗的 _NET_ACTIVE_WINDOW 属性名中存放目前有效(active)视窗的识别子。X资源所含有的程序参数,同样也是存放在根视窗的属性里;借由这个方式,即使分别执行在不同电脑上,所有客户端仍可访问到那些参数。

xprop 程序可输出指定视窗的属性,xprop -root 则可输出根视窗每一个属性的名称、类型和值。

映射

 
这颗键永远会产生相同的键码,但 /7{ 这些符号是和三个不同的键符关系。

在X窗口系统中,键盘上的每一个物理按键都关系有 8~255 之间的号码,这些号码就称作键码(keycode)。一个键码仅仅标识一个按键,而非特定的字符或功能键(如“Page Up”)。字符或功能键则由键符(keysym)来标识。键码仅仅取决于实际按下的按键,键符则可取决于按下的 Shift 键或其它的修饰键

当按下或放开按键时,服务器会发送 KeyPressKeyRelease 的事件类型给适当的客户端。这些事件包含:

  1. 按下按键所产生的键码。
  2. 修饰键(Shift、Control等)和鼠标按键当下的状态。
 
键码如何转换成键符。

因此服务器发送键码和修饰状态,而无须尝试将其转成特定的字符,这部分的转换工作由客户端自己的协议来完成。例如,客户端可能接收到一个事件,而这个事件表示已按下“a”键,且 Shift 修饰键也已按下,客户端(不是服务器)就会把这个事件关系为“A”。

客户端完成键码至键符的转换以后,表示其关系的表就由服务器来维护,并将表集中存放在所有客户端都访问得到的地方。客户端只需请求映射,并使用它对键码和其修饰键域解码成键符。客户端也可以任意改变此一映射。

当按下修饰键时,就会改变另一个按键的解码。常见的修饰键有Shift键:平常会产生小写字母“a”的 a 键和 Shift 键一起按下时,就会产生一个大写字母“A”。其它常见的修饰键还有“Control”、“Alt”和“Meta”。

X 服务器最多可用八个修饰键,不过每个修饰键可关系一个以上的按键。例如,很多键盘有两个“Shift”键(一左一右)。按下这两颗按键时,会产生两个不同的键码,不过 X 服务器会把那两者都关系到“Shift”修饰键。

X 服务器为八个修饰键维护一份可以认出修饰键的键码清单。举个例子,如果清单中的第一个修饰键(“Shift”修饰键)包含键码 0x37,然后有某个按键会产生键码 0x37,X 服务器就认为那个按键是 Shift 键。

修饰键映射的清单由 X 服务器维护,也可以让所有的客户端修改。例如,客户端可以请求将“F1 键”加到“Shift”修饰键的清单中。从此,这颗按键的效果就如同 Shift 键一样,不过 F1 仍会产生本身的键码。结果,F1 仍做它以前所做的(例如,按下 F1 时,会开启说明视窗),不过又和 Shift 一样(在文本编辑器里,按下“a”和 F1,就会打出“A”)。

X 服务器也为鼠标按键维护并使用修饰键映射,不过只能改变顺序。其最大的用处就是为左撇子调换左右两边的按键。

xmodmap 程序可以显示并改变按键、修饰键和鼠标按键的映射。

截取

截取(grab)即所有键盘或鼠标的事件,都发送到单一客户端上。客户端可以请求键盘、鼠标或两者的截取:如果服务器履行此一请求,所有键盘和鼠标的事件,都会发送到截取中客户端,直到解除截取为止。此时,其它的客户端将接收不到这些事件。

请求截取时,客户端会指定一个截取视窗:所有事件都会发送到截取中客户端,仿佛和截取视窗相关。不过其它的客户端接收不到事件,即使是在截取视窗中进行选取。在此有两种截取:

主动式
立即进行截取。
被动式
只在按下预先指定的按键(或鼠标按键)时才会进行截取,并在放开时结束。
 
如果光标或键盘是被冻结的话,其所产生的事件将会在队列上被拦截。如果是可截取的话,其事件会转运给截取的客户端,而不是原本可接收到事件的视窗。光标事件可借由事件掩码加以排除、抛弃。

客户端可截取键盘、光标或两者。截取请求中也可包含用来冻结键盘或鼠标的请求。截取和冻截的不同处在于,截取改变事件的接收者,而冻结只是完全停止递送。当设备冻结时,它所产生的事件会存放在队列中,并在结束冻结时照常递送。

对于光标事件来说,额外的参数会影响到事件的递送:事件掩码指定要递送或抛弃哪些类型的事件。

截取请求中还包含一组字段,字段用来在还没建立截取之前,就指明发送给截取中客户端的事件将要发生什么。更精确地说,客户端可请求它们照常发送或进行截取。这两种情况和它们所表现出来的有所不同。例如,在第一个视窗上正常接收键盘事件的客户端,可能会透过第二个视窗来请求截取键盘。事件将会正常发送给第一个视窗,而未必重定向给截取视窗,这取决于截取请求里所下的参数。

客户端也可请求截取整个服务器。在这种情况下,服务器将不会处理任何请求,除了来自截取中客户端的请求以外。

其它

还有其它的请求和事件,有一种请求是有关视窗之间的亲属关系:客户端可请求改变视窗的父视窗,或请求关于父视窗的信息。其它的请求则是关于选取,这部分大多由其它的协议来管理。还有的请求是关于输入焦点光标的形状。客户端也可请求将资源(视窗、图形映射等等)的所有者杀死,这会使服务器终止和那个所有者的连接。最后,客户端还可发送空运算请求给服务器。

扩展

 
shape extension可让 oclock 程序建立圆形视窗。

X Window 核心协议被设计成可扩展。核心协议指定一个机制用来查询可用的扩展,以及如何产生扩展的请求、事件和错误数据包。

更精确地说,客户溯可以请求所有可用的扩展的清单,扩展的数据包相当于核心协议的数据包。核心协议指定请求、事件和错误数据包要包含一个指明其类型的整数(例如,建立一个新视窗的请求是号码 1)。一部分范围的整数已保留给扩展。

授权

在客户端和服务器刚开始建立连接的时候,服务器的回应可以是接受、拒绝或要求验证。验证请求包含要使用的验证方法的名称。核心协议并不规范验证程序,这部分要看所使用的验证类型,并在服务器发送接受或拒绝数据包之后结束。

在客户端和服务器之间正常交互的时候,只有在涉及基于主机的访问方式的验证才要请求。更精确地说,客户端可要求激活这个方式,并请求读入和改变主机(客户端)(经授权的连接)的清单。一般的应用程序不使用这类请求;xhost 程序使用这类请求,给用户或Shell script访问主机访问清单。基于主机的访问方式被认为是不安全的。

Xlib 和其它的客户端程序库

大部分的客户端程序借由 Xlib 客户端程序库与服务器交流。特别是客户端大多使用 Xaw、Motif、GTK+、Qt 之类使用到 Xlib 的程序库,方便和服务器交互。Xlib 有以下作用:

  1. Xlib 使客户端的回应和事件同步化:
    1. Xlib 函数会发送请求区块,直到得到合理的回应。换句话说,不使用 Xlib 的X Window客户端可发送请求给服务器,并在等待回复的期间,先做其它的事。不过使用 Xlib 的客户端只能调用 Xlib 函数来发送请求,并等待回复。借此阻断客户端额外的动作(除非客户端在调用 Xlib 函数之前,就执行另一个新线程)。
    2. 当服务器发送的事件不同步时,Xlib 会把客户端接收到的事件存放在队列里,客户端程序只能以明确调用 X11 程序库函数的方式来访问。换句话说,如果在等待事件时,会让客户端强制阻断或忙碌等待
  2. Xlib 不会立即发送请求给服务器,而是先存放在队列中,这部分称为输出缓冲;输出缓冲里的请求会在以下情况真正发送出去:
    1. 程序以程序库所提供的函数,如 XFlush,明确要求。
    2. 程序所调用的函数,涉及服务器的回应,如 XGetWindowAttributes
    3. 程序要求在事件队列中的一个事件(例如,调用 XNextEvent)和调用区块(例如,XNextEvent 区块,如果队列是空的)。

高阶程序库,如XtXawMotif所使用的),让客户端程序指定与事件关系的返回函数。程序库维护轮询事件队列,并在必要时调用适当的函数;某些事件是在 Xt 内部处理,如需要重绘的视窗。

低端程序库,如XCB,提供协议不同步访问,容许较佳的延迟隐藏。

X Window 核心协议不规定什么

X Window 核心协议并不硬性规定客户端之间的通信方法,也不指明如何用视窗作成可视化组件(图形用户界面按钮菜单等),GUI 组件则交由客户端程序库实现相关的组件工具包。客户端之间的通信方法则交由其它的标准,如ICCCMfreedesktop规格 [10]

客户端之间的通信和选取、剪切缓冲器、拖曳有关,这些方法是用来让用户从某个视窗转移资料到另一个视窗。视窗有可能由不同的程序来控制,所以一个用来交换资料的协议是必要的。客户端之间的通信和X视窗管理器同样也有关系,它是用来管理视窗的外观并统一用户界面。另一个和客户端之间的通信有某种程度上的关系的还有期间管理

用户的期间要如何开始,也是核心协议未能涵盖到的问题,这部分通常由X显示管理器自动完成。用户也可以执行xinitstartx程序,以手动的方式开始一个X会话。

参阅

参考文献

  1. ^ Robert W. Scheifler and James Gettys: X Window System: Core and extension protocols, X version 11, releases 6 and 6.1, Digital Press 1996, ISBN 1-55558-148-X
  2. ^ RFC 1013
  3. ^ Grant Edwards. X11 用户界面入门页面存档备份,存于互联网档案馆
  4. ^ Jim Gettys. 开放源始码桌面技术蓝图页面存档备份,存于互联网档案馆
  5. ^ comp.fonts FAQ: X11 訊息. [2007-04-10]. (原始内容存档于2014-04-05). 
  6. ^ X 邏輯字體描述協定. [2007-04-10]. (原始内容存档于2020-02-06). 
  7. ^ Matthieu Herrb 和 Matthias Hopf。X窗口系统的新发展页面存档备份,存于互联网档案馆
  8. ^ Ghostview: Interface with ghostscript. [2007-04-10]. (原始内容存档于2015-09-24). 
  9. ^ David Rosenthal。客户端之间的通信协议手册。MIT X 协会标准,1989
  10. ^ 10.0 10.1 Freedesktop 視窗管理器規格. [2007-04-10]. (原始内容存档于2007-02-20). 

外部链接