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

发布于 2024-07-24 16:13:09 字数 2112 浏览 15 评论 0原文

我想监控X11下所有打开的窗口。 目前,我按如下方式执行此操作:

  1. 通过从根窗口递归调用 XQueryTree 来遍历整个树
  2. 侦听整个桌面上的子结构更改: XSelectInput( display, root_window, SubstructorNotifyMask | PropertyChangeMask )
  3. 最初 所有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;
}

I want to monitor all the open windows under X11. Currently, I'm doing this as follows:

  1. Initially walking the whole tree by recursively calling XQueryTree from the root window
  2. Listening for substructure changes on the whole desktop: XSelectInput( display, root_window, SubstructureNotifyMask | PropertyChangeMask )
  3. Handling all MapNotify, UnmapNotify and DestroyNotify events, updating my own list of windows in the process

I'm mainly worried about point 1. During the recursion, XQueryTree will be called multiple times. Is there any way to ensure that the tree does not change in the meantime? In other words, to get a 'snapshot' of the whole tree at one point in time?

Also, I've noticed that under some X11 systems, not all events arrive correctly. For example, when opening a new window on the desktop, MapNotify for that window may never arrive at my monitoring application. How can this be? Is it possible that it is thrown away before arriving?

Update:

I've written a small program that will monitor X events on the root window (see below). Now, when I run this program and start and quit xcalc, I get the following output:

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

That's it. I'm never notified of the real window (0x4a0005b) being destroyed. Not even of it being mapped! Can anyone tell me why not? Does SubStructureNotifyMask only cause events of direct subwindows to be sent instead of the whole subtree?

By the way, this apparently does not happen when Compiz is running. Then no reparenting is done:

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

Monitoring program source:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

水水月牙 2024-07-31 16:13:09

看看xwininfo

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

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

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

Have a look at xwininfo.

You might also like xprop and xspy for getting more info.

Update: Yep. Try using xwininfo and -root with either -tree or -children to get all windows involved.

And changes can be tracked with xprop -spy.

救星 2024-07-31 16:13:09

我相信抓取 X 服务器 (XGrabServer(3)) 将阻止窗口层次结构的更改。 不过,这有点繁琐,所以你应该只在确实需要时才这样做。

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

I believe that grabbing the X server (XGrabServer(3)) will prevent changes to the window hierarchy. It is a bit heavy handed though, so you should probably only do it if you really need it.

For an example of code that walks the window hierarchy, builds up a tree, uses window events to keep it up to date, and ignores X protocol errors which are unavoidable due to races, see the file src/VBox/Additions/x11/VBoxClient/seamless-x11.cpp in the source code for VirtualBox.

独夜无伴 2024-07-31 16:13:09

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

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

X11 is a remote protocol. This means when you query the X server for any information, you always get your own copy. Your copy never changes when the X server updates its internal data structures.

This means the tree won't suddenly change while you traverse it but when you use the information in it (like examining a window), that information might be stale (someone might have closed the window). That is why you need to do proper error handling.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文