大家都知道linux的菜单窗口在任务栏中是没有显示的,而诸如firefox的主窗口这类的窗口,在任务栏中又是可以显示的。这是为什么呢?这篇短文将尝试回答这个问题。首先,讨论3个问题。
在X window系统中,窗口的类型有如下几种(这是1.3版本,1.4版本的窗口类型不止这些。请看http://standards.freedesktop.org/wm-spec/1.4/ar01s05.html#id2568975):
DESKTOP
DOCK
TOOLBAR
MENU
UTILITY
SPLASH
DIALOG
NORMAL
可以通过_NET_WM_WINDOW_TYPE得到窗口的类型值,再将这个类型值与下例各值比较来得到窗口的类型。
_NET_WM_WINDOW_TYPE_DESKTOP, ATOM
_NET_WM_WINDOW_TYPE_DOCK, ATOM
_NET_WM_WINDOW_TYPE_TOOLBAR, ATOM
_NET_WM_WINDOW_TYPE_MENU, ATOM
_NET_WM_WINDOW_TYPE_UTILITY, ATOM
_NET_WM_WINDOW_TYPE_SPLASH, ATOM
_NET_WM_WINDOW_TYPE_DIALOG, ATOM
_NET_WM_WINDOW_TYPE_NORMAL, ATOM
WM_TRANSIENT_FOR属性说明了窗口是否为瞬时窗口。它的值是一个窗口的id号。例如,窗口a的WM_TRANSIENT_FOR值为0x12345678,就表明了窗口a是窗口id号为0x12345678窗口的瞬时窗口。
我们可以通过xprop –id wid WM_TRANSIENT_FOR来查看窗口是否具有瞬时属性。若有,返回如
WM_TRANSIENT_FOR(WINDOW): window id # 0x42250ec
若没有,结果是:
WM_TRANSIENT_FOR: not found.
是否具有瞬时属性是窗口在任务栏中能否显示的重要依据。根椐metacity窗口管理器的参考文档在所述:
"Dialogs which have no transient parent or root window being their tranisent parent are the ones which will be visible in the tasklist. "这句话翻译出来就是:那些没有瞬时父窗口或者根窗口为它的瞬时父窗口的对话框可以在任务栏中显示。所谓“瞬时父窗口”,应该就是WM_TRANSIENT_FOR属性的值了。
overrideRedirect的意思就是“忽略重定向”。我们可以用xwininfo查看窗口的overrideRedirect状态。
hq@hq-desktop:~$ xwininfo -id 0x680033c
xwininfo: Window id: 0x680033c "关于 GNOME 终端"
Absolute upper-left X: 189
Absolute upper-left Y: 420
Relative upper-left X: 1
Relative upper-left Y: 27
Width: 336
Height: 247
Depth: 24
Visual: 0x22
Visual Class: TrueColor
Border width: 0
Class: InputOutput
Colormap: 0x21 (installed)
Bit Gravity State: NorthWestGravity
Window Gravity State: NorthWestGravity
Backing Store State: NotUseful
Save Under State: no
Map State: IsViewable
Override Redirect State: no
Corners: +189+420 -499+420 -499-101 +189-101
-geometry 336x247+188-96
“重定向”的作用是让窗口管理器能够控制窗口的位置或对窗口进行装饰。事实上是把窗口的map或configure请求重定向到窗口管理器,窗口管理器再对这些请求进行处理。举个例子,菜单的overrideRedirect是ture的,就是“忽略窗口重定向”,所以菜单窗口一般都没有经过装饰的。而对话框窗口的overrideRedirect是false,就是说“不忽略窗口重定向”,所以我们看到的对话框窗口通常是有边框和标题栏的。
所谓对窗口进行装饰,就是在窗口外面加上一个“大一点”的窗口。请看下面的执行记录:
xwininfo: Window id: 0x2c003c3 (has no name)
Absolute upper-left X: 188
Absolute upper-left Y: 393
Relative upper-left X: 188
Relative upper-left Y: 393
Width: 338
Height: 279
Depth: 24
Visual: 0x22
Visual Class: TrueColor
Border width: 0
Class: InputOutput
Colormap: 0x21 (installed)
Bit Gravity State: NorthWestGravity
Window Gravity State: NorthWestGravity
Backing Store State: NotUseful
Save Under State: no
Map State: IsViewable
Override Redirect State: no
Corners: +188+393 -498+393 -498-96 +188-96
-geometry 338x279+188-96
hq@hq-desktop:~$ xwininfo -id 0x680033c
xwininfo: Window id: 0x680033c "关于 GNOME 终端"
Absolute upper-left X: 189
Absolute upper-left Y: 420
Relative upper-left X: 1
Relative upper-left Y: 27
Width: 336
Height: 247
Depth: 24
Visual: 0x22
Visual Class: TrueColor
Border width: 0
Class: InputOutput
Colormap: 0x21 (installed)
Bit Gravity State: NorthWestGravity
Window Gravity State: NorthWestGravity
Backing Store State: NotUseful
Save Under State: no
Map State: IsViewable
Override Redirect State: no
Corners: +189+420 -499+420 -499-101 +189-101
-geometry 336x247+188-96
窗口0x2c003c3就是由窗口管理器所创建的窗口。大家留意一下坐标和大小就可以看出来它们之间的关系了。
现在可以总结一下,决定一个窗口在任务栏中是否可以显示,与窗口的类型和窗口是否是瞬时窗口有关系,但是与窗口的overrideRedirect属性无关。经过窗口管理器装饰过的窗口,不一定就可以在任务栏中显示,如程序的“关于”窗口,一般是不在任务栏中出现的。反之亦然。但是,如果一个窗口是瞬时窗口,并且WM_TRANSIENT_FOR的值不等于root窗口,那它就不应该在任务栏中出现了,如菜单窗口。如果一个窗口不是瞬时窗口,那它出不出现在任务栏中就取决于窗口的类型了。例如,如果窗口类型是normal,它又不是瞬时窗口,那它就可以在任务栏中显示。
http://standards.freedesktop.org/wm-spec/1.3/ar01s05.html
http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.6
http://tronche.com/gui/x/xlib/window/attributes/override-redirect.html