首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux 焦点模型分析(3)X 系统上焦点的管理-1

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中的Input Hint
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  中的 WM_TAKE_FOCUS
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,说明它们希望控制焦点的设置。
  • 无输入:使用此种模型的 client 永远不会希望得到键盘输入。这是我们在平时开发中很少使用的一种模型。
  • 被动输入:这种模型的 client 希望能够得到键盘输入,但是它不会主动设置输入焦点,而是完全依赖窗口管理器的控制。这种模型比较适合没有子窗口简单窗口。在 focus-follow-mouse 模式下这样的设置可以使它可以接受键盘输入,同样,在 click-focus 模式下,窗口管理器会在鼠标点击使将该窗口设置为焦点窗口。
  • 局部主动输入:这样的 client 既希望得到输入,也会显式的设置焦点,但是它只会在本 client 的其中一个窗口已经获得焦点的情况下设置焦点。这样的模型一般用于有很多子窗口或者子控件可以接受键盘输入的情况。这样的模型可以方便的实现用户使用 Tab 键,或者方向键在各个控件间切换焦点的功能。
  • 全局主动输入:这样的 client 完全依靠自己的逻辑控制焦点,窗口管理器仅仅是在合适的时候发出 WM_TAKE_FOCUS 的客户消息通知 client。比如,有的复杂应用程序会希望在用户在点击滚动条的时候不设置焦点,而点击客户区域的时候才设置焦点。再比如 X 本身不支持模态对话框,但是应用程序可以使用全局主动输入的模态实现模式对话框,使得当有模式对话框弹出的情况,主窗口不能接收键盘输入。
返回列表