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

时间:2009-06-19 13:47:43

标签: c linux x11 race-condition xorg

我想要监控X11下所有打开的窗口。目前,我这样做如下:

  1. 最初通过从根窗口递归调用XQueryTree来遍历整个树
  2. 在整个桌面上收听子结构更改:XSelectInput( display, root_window, SubstructureNotifyMask | PropertyChangeMask )
  3. 处理所有MapNotify,UnmapNotify和DestroyNotify事件,在此过程中更新我自己的窗口列表
  4. 我主要担心的是第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;
    }
    

3 个答案:

答案 0 :(得分:16)

查看xwininfo

您可能还希望xpropxspy获取更多信息。

更新:是的。尝试将xwininfo-root-tree-children一起使用以获取所有窗口。

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

答案 1 :(得分:3)

我认为抓取X服务器(XGrabServer(3))将阻止更改窗口层次结构。虽然它有点沉重,所以你应该只在真正需要时才这样做。

有关遍历窗口层次结构的代码示例,构建树,使用窗口事件使其保持最新,并忽略由于比赛而不可避免的X协议错误,请参阅文件src/VBox/Additions/x11/VBoxClient/seamless-x11.cpp in VirtualBox的源代码。

答案 2 :(得分:0)

X11是一种远程协议。这意味着当您向X服务器查询任何信息时,您始终可以获得自己的副本。当X服务器更新其内部数据结构时,您的副本永远不会更改。

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