如何获取和同步所有X11窗口的完整列表?

我想监视X11下所有打开的窗口。 目前,我正在做这个如下:

  1. 最初通过从根窗口recursion调用XQueryTree来遍历整个树
  2. 在整个桌面上监听子结构更改: XSelectInput( display, root_window, SubstructureNotifyMask | PropertyChangeMask )
  3. 处理所有的MapNotify,UnmapNotify和DestroyNotify事件,更新我自己的窗口列表

我主要担心第1点。在recursion过程中,XQueryTree会被多次调用。 有什么方法可以确保树在此期间不会改变? 换句话说,要在一个时间点获得整个树的“快照”?

另外,我注意到在一些X11系统下,并不是所有的事件都能正确地到达。 例如,在桌面上打开新窗口时,该窗口的MapNotify可能永远不会到达我的监视应用程序。 怎么会这样? 在抵达之前是否有可能被扔掉?

更新:

我写了一个小程序来监视根窗口上的X事件(见下文)。 现在,当我运行这个程序,并启动并退出xcalc,我得到以下输出:

 Reparented: 0x4a0005b to 0x1001e40 Mapped : 0x1001e40 Destroyed : 0x1001e40 

而已。 我从来没有被通知被销毁的真正的窗口(0x4a0005b)。 甚至没有被映射! 谁能告诉我为什么不呢? SubStructureNotifyMask只会导致直接子窗口的事件被发送而不是整个子树?

顺便说一下,Compiz运行时,这显然不会发生。 然后没有重新完成:

 Mapped : 0x4a0005b Mapped : 0x4e00233 Destroyed : 0x4a0005b Destroyed : 0x4e00233 

监测scheme来源:

 #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; } 

看看xwininfo

您可能也喜欢xpropxspy获取更多信息。

更新:是的 。 尝试使用xwininfo-root-tree-children来获取所有涉及的窗口。

可以使用xprop -spy跟踪更改。

我相信抓住X服务器(XGrabserver(3))将阻止对窗口层次结构的更改。 虽然这有点过分,但是如果你真的需要的话,也许你应该这样做。

对于遍历窗口层次结构的代码示例,构建树,使用窗口事件保持最新状态,并忽略由于种族而不可避免的X协议错误,请参见src / VBox / Additions / x11 / VBoxClient VirtualBox源代码中的/seamless-x11.cpp 。

X11是一个远程协议。 这意味着,当您查询X服务器的任何信息,你总是得到自己的副本。 当X服务器更新其内部数据结构时,您的副本不会改变。

这意味着树在遍历时不会突然改变,但是当您使用树中的信息(例如检查窗口)时,该信息可能是陈旧的(有人可能已经关闭了窗口)。 这就是为什么你需要做适当的错误处理。