X Window系统的协议和架构

<image>

在电脑中，X Window系统（常称作 X11、X）是一种以位图显示的网络透明化视窗系统。本条目详述 X11 的协议及其技术架构。

## X 主从式模型和网络透明性

X 基于主从式模型。运作在电脑上的X 服务器程式以图形显示，并以各种客户端程式进行通讯。X 服务器接受图形输出（视窗画面）方面的请求，并回传使用者的输入（键盘、鼠标）。

在 X Window 中，服务器可以在使用者的电脑上执行，而在其他的机器上执行客户端。也可以反过来，客户端在使用者的电脑上执行，而伺服端在远端电脑上执行。X Window 使用的术语是以程式为基准，而不是使用者或硬件。远端的程式连接到本地的 X 服务器，那些远端的程式就视为客户端；本地的 X 接受所传入的讯息，这部分就视为伺服端。

<image>

主从间通讯协定的网络透明：服务器和客户端可以执行在同一机器或不同机器上，那些机器更可以是不同的硬件架构或操作系统。主从之间的通讯安全，可以加密连线的方式加强。

## 设计原则

Bob Scheifler 和 Jim Gettys 陈述的早期 X 的基本原则如下（Scheifler/Gettys 于 1996 所列）：

- 不要加入新的功能，除非没有它就不能完成实际所需的应用程序。
- 决定一个系统不是什么和决定系统是什么同样重要。不要满足全部的需求；而是使系统具有可扩充性，额外的需求可以向上相容的方式来满足。
- 只有完全没实例，才会比只有一个实例来的更糟。
- 如果没把问题弄清楚，不解决它也许会是最好的。
- 如果预期要用 90% 的努力去完成 10% 的工作，就用更简单的方法解决。（参见更糟就是更好。）
- 尽量避免复杂性。
- 提供机制而不是提供方针，使用者界面的方针由实际应用者自主。

后来在设计 X11 时，将第一项原则修改为：“不要加入新的功能，除非你知道某些实际的应用程序会需要它”。X 基本上一直遵循这些原则，参考实现的扩充及改进也是以此原则来着手，也因为奉行上述原则，使至今的最新版 X 仍能与最初（1987年）发布的协定标准几乎完全相容。

## X Window 核心协议

服务器和客户端之间的通讯，是由网络通道上的交换封包所完成。由客户端建立连线，并发送第一个封包。服务器以回传封包来答复，封包中陈述接受或拒绝连线，或要求进一步的验证。如果接受连线，接受封包内会包含客户端接下来和服务器互动所需的资料。

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

- 请求：客户端请求服务器的资讯，或者请求服务器进行一个动作。
- 回应：服务器回应请求。并非所有的请求都会产生回复。
- 事件：服务器传送事件给客户端，例如，键盘或鼠标的输入，或移动、调整、显示视窗。
- 错误：如果请求无效时，服务器会传送一个错误封包。因为请求是以排队方式处理，所以经由请求所产生的错误封包，并不会立即传送。

X 服务器提供一系统基本的服务。客户端程式可以和服务器互动，以实现更复杂的功能。

### 视窗

<image>

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

任何视窗都只能是父视窗之下的子视窗，使视窗以树状的阶层结构组织起来，阶层结构最根部的视窗便称为根视窗，而根视窗是由服务器自动建立的。顶层视窗即直接隶属于根视窗的子视窗。根视窗即整个萤幕画面，且其他视窗都在根视窗之下。

### 识别子

所有关于视窗的资料、字体等等，皆存放在服务器上。客户端知道那些物件的识别子，和服务器互动时，物件以整数为名称。例如，当客户端希望建立一个视窗时，便指定一个识别子，并请求服务器建立一个视窗。服务器会建立一个视窗，并与指定的识别子关联。稍后客户端可使用这个识别子进行请求，例如在视窗上画上一个字串。

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

### 属性

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

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

属性大多用于客户端之间的通讯。例如，名称为 `WM_NAME` 的属性，用来存放视窗的名称；视窗管理器通常会读取这个属性，并在视窗顶部显示名称。

视窗的属性可以 `xprop` 程式显示。`xprop -root` 更可显示根视窗的属性，包括 X资源（程式参数）。

### 事件

事件是由服务器传送到客户端用以通讯的封包，传送一些客户端可能感兴趣的事物。客户端可以请求服务器传送事件给另一个客户端；这部分用于客户端之间的通讯。例如，当客户端请求目前所选取的文字，就会传送事件给客户端，以处理目前所持有的选取内容。

在某些情况下，视窗的内容可能会被销毁（例如当视窗隐蔽时）。当再度观看被销毁的区域时，服务器会产生一个 `Expose`（显露）事件，用以通知客户端重绘视窗已消失的部分。

其他事件是用来通知键盘或鼠标输入的客户端、建立新视窗等等。

某些类型的事件会不断传送给客户端，但大多数的事件只在客户端预先表示关心时才会传送。因为客户端可能只需要关心某类型的事件。例如，客户端可能会关心关于键盘的事件，但却不关心关于鼠标的事件。

### 色彩模式

对于 X Window 系统处理色彩的方式，有时使用者会感到迷惑，且 X Window 支援有史以来各种不同的模式。现今大多数的应用程序皆使用真实色（TrueColor）（24 位元色彩，红、绿、蓝各有 8 位元），不过比较旧或特殊的应用程序，可能会要求使用其他的色彩模式。许多商业用的专业应用程序使用伪彩色（PseudoColor）。

目前的 X11 协议在大多数的图形运算中，是使用一个 32 位元无负号整数来表示一个颜色，称为像素值。当转移到原色的饱和度时，对每一个色彩元素使用 16 位元整数。便有如下的色彩表示，但实际装置未必能全部支援。

- 直接色（DirectColor）：像素值分为红、绿、蓝子域，每一个子域索引一份独立的色彩映射，可改变色彩映射的内容。
- 真实色（TrueColor）：与直接色大致相同，但色彩映射的内容是由硬件预先定义，不可改变。通常每个红、绿、蓝色彩映射提供一个（接近）线性斜度的饱和度。
- 灰阶（GrayScale）：像素值索引一份色彩映射，且无色彩饱和度（黑白）。可改变色彩映射的内容。
- 静态灰阶（StaticGray）：与灰阶大致相同，但色彩映射的内容是由硬件预先定义，不可改变。
- 伪彩色（PseudoColor）：像素值索引一份色彩饱和度方面的色彩映射。可改变色彩映射的内容。
- 静态色（StaticColor）：与伪彩色大致相同，但色彩映射的内容是由硬件预先定义，不可改变。

## Xlib 和其他的客户端程式库

大部分的客户端程式借由 Xlib 客户端程式库与服务器交流。特别是客户端大多使用 Xaw、Motif、GTK+、Qt 之类使用到 Xlib 的程式库，以便与服务器互动。

## 客户端之间的通讯

X Window 核心协议提供了客户端之间通讯的机制：视窗属性和事件，特别是客户端对客户端的讯息事件。不过这部分并未指明任何协议，协议部分由客户端之间的通讯协定单独管理。

客户端之间的通讯协定手册指明借由选取和应用程序的视窗管理器互动，以交换资料。但这个规格被认为过于困难和混乱；应用程序的品质和通讯的一贯性，通常是由指定的桌面环境所提供。

客户端之间的交换协议（ICE）指定了用以建立客户端间互相通讯的框架，因此，特定的协议可建立在其上。特别是 X 期间管理器协议（XSMP）便是建基于 ICE 的协议，以期间管理器托管应用程序间的互动。这个程式是在互动期间结束时，用来维护存放的桌面状态，并在同一使用者再次开始另一个期间时恢复。

较新的协定包含在 freedesktop 规范，包括拖曳协定 Xdnd，用以选取要转移的资料，然后拖曳到另一个视窗上。还有嵌入式应用程序协定 Xembed，详述应用程序如何在另一个应用程序的子视窗之中执行。

### 选取、剪下缓冲区和拖曳

选取、剪下缓冲区和拖曳机制在 X Window 系统中，是给使用者从某个视窗传递资料给另一个视窗。选取、剪下缓冲区通常用于，使用者在视窗中选取文字和其他资料，并在另一个视窗中贴上。拖曳用于，使用者在视窗中选取某些东西，然后对选取区按住按钮，并拖曳到另一个视窗。

由于两个视窗可能由两个不同的应用程序所持有，资料传递需要两个不同的客户端连接相同的 X 服务器才能互动。X Window 核心协议包含明确选择交换的请求和事件类型，不过传递的完成，主要是由一般的客户端对客户端事件传送，和未指明选择传送的视窗属性。

客户端之间传送的资料可以是不同的类型：通常是文字，不过也可以是图形、数字、物件的列表等等。

选取和拖曳是主动机制：在视窗中选取文字以后，客户端所处理的视窗必须主动支援相关的协定，才能传送资料到需要它的应用程序。相反的，剪下缓冲区则是被动机制：当使用者选取文字时，其内容会传送到剪下缓冲区，即使应用程序所处理的视窗已结束并销毁视窗，缓冲区的内容仍会保留下来。

### 视窗管理器

视窗管理器是用来控管视窗整体的外观，以及其他图形化使用者界面的要素。在不同的安装中，X Window 系统会有不同的外观，主要是因为使用不同的视窗管理器，或是不同的视窗管理器配置。

视窗管理器维护视窗的位置、周围加上装饰性的边框、处理图示、处理鼠标对视窗外表的点击（在“幕后”）、处理按键（例如按下 ALT-F4 时，将视窗缩小成图示）等等。

从 X 服务器的角度来看，视窗管理器和其他的客户端并没有什么不同。起始位置和视窗周围的装饰性边框，是由视窗管理器使用如下请求处理的：

- 应用程序可以请求服务器不要满足特定视窗的子视窗映射（显示）要求，并把事件传送过来。
- 应用程序可以请求改变视窗的亲属关系。

视窗管理器使用第一个请求，拦截所有映射顶层视窗（根视窗的子视窗）的请求。每当另一个应用程序请求映射顶层视窗，服务器不会去做，反而传送事件给视窗管理器。大部分的视窗管理器会改变视窗的亲属关系：建立更大的顶层视窗（称作框架视窗），并改变原视窗的亲属关系为自己的子视窗；相当于在框架视窗内部放置原视窗。框架视窗（而不是在原视窗上）多出来的空间，是用来装饰视窗周围的框架（“边框”和“标题列”）。

视窗管理器管理鼠标在框架视窗上的点击。例如，当使用者在边框或标题列上点击并按住时，便允许改变大小或移动视窗。

视窗管理器也负责处理图示和图形元件的显示关系。图示并不存在于 X Window 核心协议的层次上，那些是由视窗管理器实作的。例如，当视窗“图示化”时，视窗管理器 FVWM 取消映射那个视窗，使其不可见，并建立一个图示名称的视窗，且图示的图像可能和那个视窗有关。图示的意义和处理完全由视窗管理器来决定：某些视窗管理器，如 wm2，根本不实现图示功能。

### 期间管理器

概略地说，在一个特定时间中，期间的状态就是“桌面的状态”：一组视窗及其当下的内容。更精确地说，就是一系列应用程序管理的这些视窗和资讯，其允许应用程序在需要时还原所管理视窗的情况。X 期间管理器便是一个保存并还原期间状态的程式。

使用期间管理器最明显的作用，便是从一个互动期间登出，当再次登入时，有可能在相同的状态下恰好发现相同的视窗。关于这部分的运作，在登出时，期间管理器程式储存执行中应用程序的名称，并在登入时再次启动它们。并按照应用程序状态的次序来还原（需要还原视窗的内容），应用程序必须能够保存这些执行状态，并在再次启动时，能够根据期间管理器的请求来读回这些状态。

X Window 系统含有一个预设的期间管理器，称作 `xsm`。特定的桌面系统中也已开发了其他的期间管理器：例如，`ksmserver` 是 KDE 预设的期间管理器。

## X 显示管理器

X显示管理器在 X Window 系统中，是一个用来显示图形化登入提示的程式。更广泛的说，显示管理器在本机电脑上执行一个或多个 X 服务器，并接受来自远端电脑上执行的 X 服务器的新连线。本机服务器借由显示管理器来启动，然后显示管理器连线到服务器，以呈现出使用者登入画面。远端服务器从显示管理器独立启动并且与之连线。在这个情况下，显示管理器的运作就如同图形化的 telnet 服务器：X 服务器可连接到显示管理器，并启动一个期间；期间之中的程式执行在显示管理器的同一部电脑上，不过在电脑上的输出和输入是由 X 服务器执行（使用者面前的那部电脑）。

XDM 是 X Window 系统所提供最基本的显示管理器。其他的显示管理器还有 GDM（GNOME）、KDM（KDE）、WDM（使用 Window Maker 的 WING 组件集），以及 entrance（使用 Enlightenment v.17 的架构）。

## 使用者界面元件

X 早期的组件工具包有 Xaw（雅典娜工程组件集）、OLIT（OPEN LOOK 内部工具包）、XView、Motif、Tk。OLIT 和 XView 为 AT&T 和昇阳的 OPEN LOOK GUI 起基础工具包的作用。

Motif 为 Common Desktop Environment（CDE）提供基础工具包，即用于商业化 Unix 系统的标准桌面环境，如 Solaris 和 HP-UX。（GNOME 也用于 Solaris 9，且即将成为未来版本的标准。）

更多最新的工具包还包括 Qt（用于 KDE）、GTK+（用于 GNOME）、wxWidgets、FLTK、FOX。

## 扩充

X 服务器被设计成简单而可扩充。如此一来，许多功能就存在于扩充协议之中。

在协议层次上，每个扩充都可以指定新的请求／事件／错误的封包类型。客户端应用程序使用客户端程式库，以促进存取由扩充所提供的功能。据说为目前的 X 服务器编写扩充是相当困难的，这归咎于 X 服务器缺乏模组化的设计。XCB 专案是一个长期的目标，朝向根据 XML 协议描述，自动化产生客户端和伺服端的扩充。

以下是一部分已开发的扩充列表，以引入的时间排列：

扩充｜描述和注解

AIGLX｜支援间接 GLX 绘图。

Composite｜整个视窗阶层之外的幕外绘制，允许应用程序和组件管理器能在任何情况下作用。某些情况需要此功能，如用于视窗和阴影的 Alpha 半透明。

Damage｜追踪视窗的修改范围，并在维持必要的显示下，将带宽消耗降到最低。

XFixes｜若干协议的修改。

Extended-Visual-Information (EvIE)

Distributed Multihead (DMX)

XvMC｜支援卸载视讯对 GPU 的动态补偿。

GLX｜支援视窗内部的 OpenGL 绘图。

XRender｜硬件加速的 Alpha 影像混合。

Resize and Rotate (RANDR)｜即时调整桌面的大小，以及侧向旋转或上下翻转。

Xinerama｜将桌面拆解，以对应多萤幕。

Display Power Management Signaling (DPMS)｜允许控制萤幕的电源节能模式。

XPRINT

X keyboard extension｜改善键盘布局的处理。

DOUBLE-BUFFER RECORD

MIT-SHM｜增进共享内存的使用效能。

SYNC XTEST

XInputExtension｜支援绘图板之类的输入装置。

BIG-REQUESTS XC-MISC

X video extension｜支援硬件视讯重叠，以及播放时的硬件视讯缩放。亦称 Xv（不要和 xv 程式混淆）。

Shape｜支援非矩形和部分透明（二进制，非 alpha 半透明）的视窗。

DEC-XTRAP MIT-SCREEN-SAVER MIT-SUNDRY-NONSTANDARD SECURITY TOG-CUP X-Resource XC-APPGROUP XFree86-Bigfont XFree86-DGA XFree86-Misc XFree86-VidModeExtension

### 废弃的扩充

扩充｜描述和注解

Low Bandwidth Extension (LBX)｜以安全壳层连线的 X tunneled 取代，且证明比 LBX 快速。

PEX｜“PHIGS 扩充到 X 上”，以支援 PHIGS 3D 场景图形 API。已被运用 OpenGL 的 GLX 所取代。

XImage Extension｜以 MIT-SHM 取代。

## 参阅

- Xlib
- Intrinsics
- X Window核心协议

## 参考文献

- 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
- X Windows 入门
- 开放源始码桌面技术蓝图 (Jim Gettys, 09 Dec 2003)

## 外部链接

- X.Org Foundation （官方首页）
- X.Org Foundation wiki
- Kenton Lee's pages on X Window and Motif