Board logo

标题: Linux 焦点模型分析(3)X 系统上焦点的管理-1 [打印本页]

作者: look_w    时间: 2018-5-23 15:28     标题: Linux 焦点模型分析(3)X 系统上焦点的管理-1

本章将具体讨论 X 系统上焦点的管理与控制方法和规范。
X Server 与窗口管理器( window manager )上一章介绍了在 Linux 上的界面系统使用的是 X 窗口系统。在这个系统中,X Server 起了很重要的作用,它管理着系统中各种资源,包括窗口、光标、字体以及所有的图形元素,它使得这些资源可以以统一的格式在各个 Client 之间通过网络共享。但是,这些资源以何种风格显示出来却是由窗口管理器( window manager )控制的。
窗口管理器是运行在 X 系统上的一种特殊的应用程序,它实际上也是一个 X Client。它为 X 系统上运行的窗口程序提供了一套统一的外观风格机制。例如,它决定了窗口的标题栏使用蓝色还是灰色;它规定了窗口的滚动条是扁还是圆;当两个窗口请求的位置重叠时,它控制着这两个窗口具体显示位置是否重叠,等等。简单的说,在 X 系统上,所有的可见的控件都是窗口,窗口管理器就负责管理这些窗口。
一般情况下,Client 需要配合窗口管理器,以使窗口达到预期的效果。ICCCM( Inter-Client Communication Conventions Manual )定义了这种配合的规范。目前流行的窗口管理器很多,比如,KWin,Metacity,FVWM,TWM,wm2等等。
虽然这是 X 系统广泛支持的规范,但是,ICCCM 对窗口管理器的实现仅仅是一个参考各窗口管理器对 ICCCM 支持的程度也不同。而对于 ICCCM 没有定义到的功能,各个窗口管理器的实现更有着很大的差别。因此当应用程序在 X 系统下请求完成某个操作后,在收到相应前永远不能假设实际结果会是怎样。
ICCCM 定义的焦点模型在 X 系统中,每个窗口都具有一些属性,被称为 property。这些属性的名称和类型都以atom 的形式存在。每个 atom 在系统中由唯一的整数标识。Client 可以自己定义的属性,也可以由 Server 创建,它们都由 X Server 统一进行维护,在各个 Client 之间共享。应用程序可以通过 XSetWindowProperty, XGetWindowProperty 等方法来访问这些属性。
ICCCM 通过对一些 property 的定义,制定了 X Client 之间通信的规范,包括 Client与 Client,Client 与窗口管理器,Client 和会话管理器,以及颜色特征的通信规范。在这里我们将主要介绍 ICCCM 就 Client 与窗口管理器关于焦点的规定。
ICCCM 规定,所有拥有顶层窗口的 Client 都必须通过设置指定的 property 来指示窗口管理器如何管理 Client。所有与窗口管理器相关的属性都以“WM_***”的形式出现,如 WM_NAME,WM_ICON_NAME 等等。其中两个属性与焦点管理相关,一个是 WM_HINTS,一个是 WM_PROTOCOLS。
WM_HINTS 为窗口管理器提供了 Client 的信息包括图标的信息和位置,初始状态,是否需要窗口管理器设置焦点。下表是 Xlib 中对 XWMHins 的声明。程序可以通过 XSetWMHints 来设置该属性值。
清单2 XWMHints 的声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* Window manager hints mask bits */
     
#define InputHint    (1L << 0)
#define StateHint    (1L << 1)
#define IconPixmapHint    (1L << 2)
#define IconWindowHint    (1L << 3)
#define IconPositionHint (1L << 4)
#define IconMaskHint      (1L << 5)
#define WindowGroupHint   (1L << 6)
#define UrgencyHint (1L << 8)
#define AllHints (InputHint|StateHint|IconPixmapHint| 
     IconWindowHint|IconPositionHint|IconMaskHint|WindowGroupHint)


/* Values */
     
typedef struct {
long flags;
Bool input;
int initial_state;
Pixmap icon_pixmap;
Window icon_window;
int icon_x, icon_y;
Pixmap icon_mask;
XID window_group;
} XWMHints;




其中的 InputHint 标识了应用程序是否依赖窗口管理器获取焦点。只有当该域被设置为True 时,窗口管理器才会在希望将其设置为焦点窗口时主动调用 XSetInputFocus 将其设置为焦点窗口。例如,在 click-focus 模式下,当用户用鼠标点击了某个窗口,如果该标志被设置为 True ,窗口管理器会将此窗口设置为焦点窗口。但是如果此标志被置为 False ,那么窗口管理器将不会主动设置其为焦点窗口。
下面这段示例程序显示了如何为窗口设置 InputHint 标志。
清单3 设置 input hint
1
2
3
4
5
6
7
8
9
10
void set_ input_hint(Display *dispay, Window w, Bool bInput)
{
XWMHints *wm_hints;

wm_hints = XGetWMHints(display, w);
wm_hints->flags |= InputHint;
wm_hints->input = bInput;
XSetWMHints(display, window, wm_hints);
XFree(wm_hints);
}




WM_PROTOCOLS 实际上是一组 Atom。每一个属性的设置实际上决定了 Client 是否要参与窗口管理器的某些管理。在 ICCCM 中定义的标准协议 Atom 包括:WM_TAKE_FOCUS、WM_SAVE_YOURSELF 和 WM_DELETE_WINDOW。不同的窗口管理器还可以定义自己的协议。Client 可以通过 XSetWMProtocols 指定需要接受协议。如果窗口设置了其中的协议 Atom,当窗口管理器要进行某些操作的时候将会以 ClientMessage 事件的形式将此协议 Atom 发送给窗口,通知 Client 做出相应的行动。其中,WM_TAKE_FOCUS 协议规定了 Client 是否要参与到设置焦点窗口的行为中。
以下程序片断显示了用户如何设置 WM_TAKE_FOCUS 协议。
清单4 设置 WM_TAKE_FOCUS
1
2
3
4
5
6
7
8
void set_wm_protocol(Display *display, Window w)
{
Atom protocols[3];

protocols[0] = XInternAtom(display, “WM_TAKE_FOCUS”, false);
….. //设置其它协议
XSetWMProtocols(display, w, protocols, 3);
}




当 WM_TAKE_FOCUS 协议 Atom 被设置表明该窗口希望参与到焦点的管理中。那么,当窗口管理器打算将该窗口设置为焦点窗口时,会给窗口发送包含了 WM_TAKE_FOCUS 的 ClientMessage 事件。一般来说,当窗口收到这个事件后会为根据需要设置焦点窗口。
如果该 Atom 没有设置,那么是否设置焦点窗口就完全由窗口管理器决定。
ICCCM 根据窗口对属性的设置不同分为四种输入焦点模型( Input Focus Model ):无输入( No Input ),被动输入( Passive Input ),局部主动输入( Locally Active Input )以及全局主动输入( Globally Active Input )。每种模型对应的 input 域和 WM_TAKE_FOCUS atom 的设置如下:
表1 四种输入模型的属性设置输入模型InputHint域WM_TAKE_FOCUS无输入False不设置被动输入True不设置局部主动输入True设置全局主动输入False设置
从前面对 InputHint 域以及 WM_TAKE_FOCUS 的介绍,我们可以大致可以推测出这些模型的工作方式。被动输入和局部主动输入的 WM_HINTS 的 InputHint 域设为 True,说明这种模型下,窗口依赖窗口管理器来获取输入焦点。而无输入和全局主动输入模型中,InputHint 域设置为 False,则表明窗口管理器不会把焦点设置到它们的顶层窗口上。而其中,局部主动和全局主动输入设置了 WM_TAKE_FOCUS,说明它们希望控制焦点的设置。





欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0