X Window 系统介绍 X Window 系统是一个基于网络的图形界面系统,它于 1984 年在麻省理工学院开发,有将近 20 年的应用历史。X Window 系统广泛的应用于桌面 Linux(如 Fedora、Debian、Ubuntu 等),嵌入式 Linux(如 Nokia 的 Maemo、Intel 的 Moblin 等)。随着 Nokia 和 Intel 高调的将 Maemo 和 Moblin 合并为 Meego,X Window 系统的应用将被推向一个新的高潮。 X Window 是 C/S 架构,涵盖 X Server、X 协议、X Client 三部分内容。其 X Client 有三种开发模式:基于 XLib、基于 GTK、基于 Qt。 本文将以一个基于 XLib 的应用来介绍 X Window 的窗口显示原理。
回页首 示例及运行结果 示例代码将显示一个 200X200 的白色背景窗口,并在窗口的中间绘制一个 100 个点,连接成一条横线。按任意按键可以退出该程序。 清单 1. hello.c
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#define WINDOW_SIZE 200
int main (int argc, char *argv[])
{
Display *dpy;
XSetWindowAttributes attributes;
Window win;
GC gc;
XKeyEvent event;
int i;
// 连接到 X Server,创建到 X Server 的套接字连接
dpy = XOpenDisplay(NULL);
// 创建 200X200 的白色背景窗口
attributes.background_pixel = XWhitePixel(dpy, 0);
win = XCreateWindow(dpy, XRootWindow(dpy, 0),
0, 0, WINDOW_SIZE, WINDOW_SIZE, 0, DefaultDepth(dpy, 0),
InputOutput, DefaultVisual(dpy, 0),
CWBackPixel,&attributes);
// 选择输入事件。
XSelectInput(dpy, win, ExposureMask | KeyPressMask );
// 创建绘图上下文
gc = XCreateGC(dpy, win, 0, NULL);
//Map 窗口
XMapWindow(dpy, win);
// 事件主循环。主要处理 Expose 事件和 KeyPress 事件
while(1)
{
XNextEvent(dpy,(XEvent *)&event);
switch(event.type)
{
// 处理 Expose 事件
case Expose:
{
// 绘制 100 个点
for (i=0;i<WINDOW_SIZE/2;i++)
XDrawPoint(dpy, win, gc, WINDOW_SIZE/4+i, WINDOW_SIZE/2);
}break;
// 处理按键事件
case KeyPress:
{
XFreeGC(dpy, gc);
XCloseDisplay(dpy);
exit(0);
}break;
default:
{
}break;
}
}
return(0);
}
| 编译:gcc -o hello hello.c -lX11 图 1. Ubuntu 9.10 运行结果 图 2. Maemo Fremantle 模拟器运行结果 在示例代码 hello.c 中,和窗口显示相关的接口主要有:XCreateWindow,XMapWindow,XDrawPoint。在示例代码之外,X Server 和窗口管理器同时在发挥着各自的关键作用。本文将结合 X Server、窗口管理器、示例 hello.c 代码来解释窗口显示的原理。
回页首 创建窗口:XCreateWindow 在 X Window 系统中,客户端申请的 GC、Pixmap、Window 等资源位于服务器 X Server 端。而客户端创建的另一些资源如 XImage,不由 X Server 管理,而是由客户端自行管理。 在客户端调用 XCreateWindow 创建一个窗口时,X Server 会为它建立一个 Window 类型的数据结构。该结构中描述了窗口的大小、坐标等信息。窗口实际上是屏幕的一块区域,子窗口是父窗口的一部分,所有的窗口有一个共同的根即根窗口。 客户端调用 XCreateWindow 接口时,对应的 X Server 实现是 CreateWindow 函数: 清单 2. CreateWindow 实现
WindowPtr
CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w,
unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist,
int depth, ClientPtr client, VisualID visual, int *error)
{
/* 省略非关键代码部分 */
pScreen = pParent->drawable.pScreen;
pWin->drawable = pParent->drawable;/* 子窗口是父窗口的一部分 */
pWin->devPrivates = NULL;
pWin->drawable.depth = depth;
/* 省略非关键代码部分 */
pWin->origin.x = x + (int)bw;
pWin->origin.y = y + (int)bw;
pWin->drawable.width = w;/* 窗口管理信息 */
pWin->drawable.height = h;
pWin->drawable.x = pParent->drawable.x + x + (int)bw;
pWin->drawable.y = pParent->drawable.y + y + (int)bw;
…
}
| 在 GTK 中,调用 gdk_window_new 会创建一个 X 窗口。GTK 提供了三种类型的顶层窗口:GDK_WINDOW_TOPLEVEL、GDK_WINDOW_DIALOG、GDK_WINDOW_TEMP。这些顶层窗口的父亲是 GDK_SCREEN_XROOTWIN,即根窗口。而 GDK_WINDOW_CHILD 类型的窗口其父亲由用户创建窗口时指定。GDK_WINDOW_CHILD 类型的窗口对应的是 GTK 的控件,如 GtkButton、GtkEntry 等。 如前述,所有的窗口都是父窗口的一部分。所有窗口的根是根窗口。根窗口由 X Server 在启动时创建,对应整个屏幕区域。 以 GTK 为例子,GTK 窗口层级视图是下图 3 的样子: 图 3. GTK 窗口层级视图 对单个应用而言,部分窗口管理器如 Matchbox Window Manager 只支持一个应用级顶层窗口,譬如 Maemo Fremantle 使用的就是该类型的窗口管理器。这就是为什么 Maemo Fremantle 模拟器运行 hello.c 的显示结果 ( 图 2) 不是设定的尺寸 200X200,而是延伸到整个屏幕宽度。在 Maemo Fremantle 模拟器顶部显示的状态条其实是主界面显示的,该部分是 Dock 类型的窗口,和 hello.c 无关。 CreateWindow 调用结束的时候给客户端发送 CreateNotify 事件。但是 GTK 没有处理该事件。
回页首 映射窗口:XMapWindow XMapWindow 对应的 X Server 实现是 MapWindow 函数。该代码较长,而且涉及到 X Client、X Server、窗口管理器的多次交互。 MapWindow 的工作原理是:
- 客户端调用 MapWindow 请求映射 Client 窗口。如果该窗口的 overrideRedirect 为假,表示该 MapWindow 调用为普通客户端发起。则发送 MapRequest 到窗口管理器。请求窗口管理器进一步处理。
- 窗口管理器收到 MapRequest,创建一个 Frame 窗口,并通过 XReparentWindow 调用,将客户端的窗口设置为 Frame 窗口的子窗口。Frame 窗口的 overrideRedirect 为真。
- 窗口管理器调用 XMapSubwindows,第二个参数为 Frame 窗口。由于 Frame 窗口的 overrideRedirect 为真,MapSubwindows 会对该 Frame 窗口的子窗口做映射。并发送 MapNotify 事件、Expose 事件给客户端。客户端在 Expose 事件中绘制客户端窗口内容。
- 窗口管理器调用 XMapWindow,第二个参数为 Frame 窗口。同样由于 Frame 窗口的 overrideRedirect 为真,这次 MapWindow 也不发射 MapRequest 事件了,从而映射了 Frame 窗口。
- X Server 在映射 Frame 窗口之后,发送 Expose 事件给窗口管理器,以通知窗口管理器绘制窗口的边框等。
至此,客户端窗口的内容,窗口的边框都被显示在屏幕上了。 下图 4 是 X Client、X Server、窗口管理器的交互序列图: 图 4. X Client、X Server、窗口管理器交互序列图
回页首 结束语 X Window 是一个功能非常强大的 C/S 图形显示系统,具有很好的跨网络性能,也易于进行扩展。了解其窗口显示原理对程序员进行 GTK/QT 编程是有帮助的。 参考资料
关于作者
徐星,武汉大学电子系硕士。毕业后一直从事手机 GUI 研发 , 对 Qt、GTK、X Window 系统有较深入的理解。在国内外期刊发表论文三篇,有发明专利两项。主要研究方向是 X Window 系统、OpenGL 等。
原文链接: http://www.ibm.com/developerwork... |