【发布时间】:2009-06-19 13:47:43
【问题描述】:
我想监控 X11 下所有打开的窗口。目前,我这样做如下:
- 通过从根窗口递归调用 XQueryTree 来初步遍历整个树
- 监听整个桌面的子结构变化:
XSelectInput( display, root_window, SubstructureNotifyMask | PropertyChangeMask ) - 处理所有 MapNotify、UnmapNotify 和 DestroyNotify 事件,在此过程中更新我自己的窗口列表
我主要担心第1点。在递归过程中,XQueryTree会被多次调用。有什么办法可以确保树在此期间不会改变?换句话说,要在某个时间点获取整棵树的“快照”?
另外,我注意到在某些 X11 系统下,并非所有事件都正确到达。例如,当在桌面上打开一个新窗口时,该窗口的 MapNotify 可能永远不会到达我的监控应用程序。怎么会这样?有没有可能还没到就扔掉了?
更新:
我编写了一个小程序,它将监视根窗口上的 X 事件(见下文)。现在,当我运行这个程序并启动和退出 xcalc 时,我得到以下输出:
Reparented: 0x4a0005b to 0x1001e40
Mapped : 0x1001e40
Destroyed : 0x1001e40
就是这样。 我从来没有收到关于真实窗口 (0x4a0005b) 被破坏的通知。甚至没有被映射!谁能告诉我为什么不呢? SubStructureNotifyMask 是否仅导致发送直接子窗口的事件而不是整个子树?
顺便说一句,这显然不会在 Compiz 运行时发生。然后不进行任何重养:
Mapped : 0x4a0005b
Mapped : 0x4e00233
Destroyed : 0x4a0005b
Destroyed : 0x4e00233
监控程序来源:
#include <X11/Xlib.h>
#include <cstdio>
int main()
{
Display *display;
Window rootwin;
display = XOpenDisplay( NULL );
rootwin = DefaultRootWindow( display );
XSelectInput( display, rootwin, SubstructureNotifyMask );
XEvent event;
while ( 1 ) {
XNextEvent( display, &event );
if ( event.type == MapNotify ) {
XMapEvent *mapevent = (XMapEvent *)&event;
printf( "Mapped : 0x%x\n", (unsigned int)(mapevent->window) );
}
if ( event.type == DestroyNotify ) {
XDestroyWindowEvent *destroywindowevent = (XDestroyWindowEvent *)&event;
printf( "Destroyed : 0x%x\n", (unsigned int)(destroywindowevent->window) );
}
if ( event.type == ReparentNotify ) {
XReparentEvent *reparentevent = (XReparentEvent *)&event;
printf( "Reparented: 0x%x to 0x%x\n", (unsigned int)(reparentevent->window), (unsigned int)(reparentevent->parent) );
}
}
return 0;
}
【问题讨论】:
标签: c linux x11 race-condition xorg