7.1.3 主要数据结构

在winman中,将为每个被管理的窗口创建一个对象,记录其相关信息,为此我们抽象了结构体Client。另外,我们抽象了结构体WinMan,其中记录了一些全局信息。在讨论具体的实现前,我们先来了解一下这两个数据结构。读者不必全部理解每一项的含义,后面具体遇到时,读者可以再回到这里,前后结合进行理解。

1.结构体Client

结构体Client中主要包含窗口属性信息以及与窗口操作相关的函数,定义如下:

7.1.3 主要数据结构 - 图1

我们结合图7-6来解释其中相关数据项。

7.1.3 主要数据结构 - 图2

图 7-6 窗口相关参数

❑每个窗口作为X服务器的一个资源,都有一个ID来唯一标识。这里的数据项window就是被管理的窗口的ID。

❑wm指向全局的结构体WinMan的对象。

❑frame是Frame窗口的ID;titlebar是标题栏窗口的ID;minimize_btn是最小化按钮对应的窗口的ID;maximize_restore_btn是最大化/恢复按钮对应的窗口的ID;close_btn是关闭按钮对应的窗口的ID。acting_btn是一个为了编程方便定义的辅助变量,用来记录用户点击了最大化、最小化以及关闭按钮中的哪一个。

❑以"rsz_"(resize的简写)开头的8个窗口,是在Frame窗口上创建的8个不可见窗口,它们分别位于Frame窗口的4个边和4个角,目的是为了便于判断鼠标是否落在调整窗口尺寸的区域。也就是说,一旦用户的鼠标落入这个窗口区域,程序的鼠标将使用特定的指针,提示用户可以进行改变窗口的尺寸了。resizing_area也是一个辅助变量,用来记录鼠标落在了调整窗口尺寸的8个区域的哪个区域,也就是哪个窗口上。

❑变量moving用来标识用户是否正在移动窗口,anchor_x、anchor_y记录用户在标题栏上按下鼠标左键、准备开始移动时的位置,目的是为了计算鼠标按下位置与当前位置的距离。

❑x、y、width、height记录窗口的位置及大小。min_width、min_height表示允许用户改变窗口尺寸时允许的最小值,主要目的是避免用户不小心将窗口缩小的太小,导致窗口“丢失”了。

❑state记录窗口的状态,winman只处理最大化及其标准状态。restore_x、restore_y、restore_w、restore_h分别记录窗口在最大化之前的位置和尺寸,以便从最大化恢复为标准尺寸时使用。

❑trans_for的目的是为了记录某个窗口是否是临时窗口,如果是临时窗口,那么它是谁的临时窗口。在讨论窗口切换时,我们将看到这个数据项的意义。

❑变量ignore_unmap涉及的内容有点复杂,将在7.1.12节详细讨论。

❑每个窗口通过指针above和below链接到窗口栈中。

与窗口操作相关的一些函数的实现,后面章节中我们会讨论。

2.结构体WinMan

结构体WinMan中包含了全局需要使用的变量,定义如下:

7.1.3 主要数据结构 - 图3

上述代码中各个参数含义如下:

❑第一个数据项dpy无需多说了,它是代表应用到X服务器的连接。一个X服务器可以支持多屏,每个屏上都会有一个根窗口。虽然我们不考虑多屏的情况,但是某些函数使用屏幕号和根窗口作为参数,为了避免每次使用时都要从X服务器获取,winman在结构体中保留了一份副本,即数据项screen和root,分别代表屏幕号和根窗口ID。

❑数组atoms中记录的是用于窗口间通信的Atom,winman也不希望应用反复的从X服务器获取这些Atom,所以将它们保存在winman的本地。

❑winman使用栈的方式记录窗口对象(即为每个窗口创建的结构体Client的实例),stack_top和stack_bottom分别指向这个窗口栈的栈顶和栈底。距离用户最远的窗口记录在栈底,距离用户最近的窗口记录在栈顶。stack_items记录栈中窗口对象的数量。

❑active、desktop以及taskbar分别指向当前活动的窗口、构成桌面环境的桌面组件以及任务条组件。