【问题标题】:How to identify top-level X11 windows using xlib?如何使用 xlib 识别顶级 X11 窗口?
【发布时间】:2010-11-15 03:07:01
【问题描述】:

我正在尝试获取 X11 会话中所有顶级桌面窗口的列表。基本上,我想获取在窗口管理器应用程序切换 UI 中显示的所有窗口的列表(通常在用户按下 ALT+TAB 时打开)。

我以前从未做过任何 X11 编程,但到目前为止,我已经设法枚举了整个窗口列表,代码如下所示:

void CSoftwareInfoLinux::enumerateWindows(Display *display, Window rootWindow)
{
    Window parent;
    Window *children;
    Window *child;
    quint32 nNumChildren;

    XTextProperty wmName;
    XTextProperty wmCommand;

    int status = XGetWMName(display, rootWindow, &wmName);
    if (status && wmName.value && wmName.nitems)
    {
        int i;
        char **list;
        status = XmbTextPropertyToTextList(display, &wmName, &list, &i);
        if (status >= Success && i && *list)
        {
            qDebug() << "Found window with name:" << (char*) *list;
        }

        status = XGetCommand(display, rootWindow, &list, &i);
        if (status >= Success && i && *list)
        {
            qDebug() << "... and Command:" << i << (char*) *list;
        }

        Window tf;
        status = XGetTransientForHint(display, rootWindow, &tf);
        if (status >= Success && tf)
        {
            qDebug() << "TF set!";
        }

        XWMHints *pHints = XGetWMHints(display, rootWindow);
        if (pHints)
        {
            qDebug() << "Flags:" << pHints->flags
                    << "Window group:" << pHints->window_group;
        }
    }

    status = XQueryTree(display, rootWindow, &rootWindow, &parent, &children, &nNumChildren);
    if (status == 0)
    {
        // Could not query window tree further, aborting
        return;
    }

    if (nNumChildren == 0)
    {
        // No more children found. Aborting
        return;
    }

    for (int i = 0; i < nNumChildren; i++)
    {
        enumerateWindows(display, children[i]);
    }

    XFree((char*) children);
}

enumerateWindows() 最初是用根窗口调用的。

这很有效,因为它打印出数百个窗口的信息 - 我需要的是计算出我可以询问哪个属性以确定给定的 Window 是否是顶级桌面应用程序窗口(不是确定官方术语是什么),或者不是。

任何人都可以对此有所了解吗?我为 X11 编程找到的所有参考文档都非常枯燥且难以理解。也许有人可以指出更好的资源?

【问题讨论】:

    标签: c++ x11 xlib icccm ewmh


    【解决方案1】:

    我有办法!

    嗯,有点。

    如果您的窗口管理器使用扩展窗口管理器提示 (EWMH),您可以使用“_NET_CLIENT_LIST”原子查询根窗口。这将返回窗口管理器正在管理的客户端窗口列表。如需更多信息,请参阅here

    但是,这样做存在一些问题。首先,使用的窗口管理器必须支持 EWMH。 KDE 和 GNOME 可以,我相信其他一些也可以。但是,我敢肯定有很多人不这样做。此外,我注意到 KDE 存在一些问题。基本上,一些非 KDE 应用程序不会包含在列表中。例如,如果您在 KDE 下运行 xcalc,它将不会显示在此列表中。

    如果有人可以对此方法提供任何改进,我会很高兴听到他们的声音。作为参考,下面列出了我正在使用的代码:

        Atom a = XInternAtom(m_pDisplay, "_NET_CLIENT_LIST" , true);
        Atom actualType;
        int format;
        unsigned long numItems, bytesAfter;
        unsigned char *data =0;
        int status = XGetWindowProperty(m_pDisplay,
                                    rootWindow,
                                    a,
                                    0L,
                                    (~0L),
                                    false,
                                    AnyPropertyType,
                                    &actualType,
                                    &format,
                                    &numItems,
                                    &bytesAfter,
                                    &data);
    
        if (status >= Success && numItems)
        {
            // success - we have data: Format should always be 32:
            Q_ASSERT(format == 32);
            // cast to proper format, and iterate through values:
            quint32 *array = (quint32*) data;
            for (quint32 k = 0; k < numItems; k++)
            {
                // get window Id:
                Window w = (Window) array[k];
    
                qDebug() << "Scanned client window:" << w;
            }
            XFree(data);
        }
    

    【讨论】:

    • 这段代码不正确,32位格式是指服务器上使用的位数,而不是客户端。客户端总是使用“long”来表示 XID 值。您的数组必须是 'long' 而不是 quint32 的数组。
    • 很好,但在这里对我没有帮助,因为我仍在使用 CDE(因此 dtwm)。对于大多数用户来说,这应该是有效的,但请记住,如果您正在阅读本文,它并非无处不在!
    【解决方案2】:

    要扩展之前的解决方案,如果您想获取窗口名称:

    // get window Id:
    Window w = (Window) array[k];
    
    char* name = '\0';
    status = XFetchName(display, w, &name);
    if (status >= Success)
    {
        if (name == NULL)
            printf("Found: %ul  NULL\n", w);
        else
            printf("Found: %ul  %s\n", w, name);
    }
    XFree(name);
    

    【讨论】:

    • 请注意XFetchName 可能会成功但设置name=NULL。在这种情况下,您的示例将崩溃。 char* name='\0'; 也具有误导性,常量应该看起来像 NULL,因为它是一个指针而不是一个字符。
    【解决方案3】:

    如果您不必使用 Xlib,使用 GDK 的 gdk_screen_get_window_stack()gdk_window_get_window_type() 可能会帮助您满足您的需求。

    【讨论】:

      猜你喜欢
      • 2011-05-19
      • 1970-01-01
      • 2022-11-13
      • 2018-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多