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

Thumb
X Window 系统的标志

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

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

概观

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

Thumb
客户端和伺服器之间的互动范例。

建立连线之后,在客户端和伺服器的通道上,会有四种交换封包的类型:

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

请求和回应封包可以有各种长度,事件和错误封包的长度则固定是32位元组

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

视窗

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

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

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

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

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

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

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

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

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

图形映射和可绘区

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

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

图形脉络和字体

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

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

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

Thumb
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 事件,以通知客户端重绘视窗已消失的部分。

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

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

客户端可以设置视窗的属性值(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 则可输出根视窗每一个属性的名称、类型和值。

映射

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

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

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

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

因此伺服器传送键码和修饰状态,而无须尝试将其转成特定的字元,这部份的转换工作由客户端自己的协定来完成。例如,客户端可能接收到一个事件,而这个事件表示已按下“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)即所有键盘或滑鼠的事件,都传送到单一客户端上。客户端可以请求键盘、滑鼠或两者的截取:如果伺服器履行此一请求,所有键盘和滑鼠的事件,都会传送到截取中客户端,直到解除截取为止。此时,其他的客户端将接收不到这些事件。

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

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

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

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

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

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

其他

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

扩充

Thumb
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会话。

参阅

参考文献

外部链接

Wikiwand in your browser!

Seamless Wikipedia browsing. On steroids.

Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.

Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.