如何使用xlib识别顶级X11窗口?

发布于 2024-07-29 08:29:02 字数 2186 浏览 12 评论 0原文

我正在尝试获取 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 编程的参考文档都非常枯燥且难以理解。 也许有人可以指出更好的资源?

I'm trying to get a list of all top level desktop windows in an X11 session. Basically, I want to get a list of all windows that are shown in the window managers application-switching UI (commonly opened when the user presses ALT+TAB).

I've never done any X11 programming before, but so far I've managed to enumerate through the entire window list, with code that looks something like this:

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() is called initially with the root window.

This works, in so far as it prints out information about hundreds of windows - what I need, is to work out which property I can interrogate to determine if a given Window is a top-level Desktop application window (not sure what the official terminology is), or not.

Can anyone shed some light on this? All the reference documentation I've found for X11 programming has been terribly dry and hard to understand. Perhaps someone could point be to a better resource?

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

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

发布评论

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

评论(3

柠檬色的秋千 2024-08-05 08:29:02

我有办法!

嗯,有点像。

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

然而,这存在一些问题。 首先,使用的窗口管理器必须支持 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);
    }

I have a solution!

Well, sort of.

If your window manager uses the extended window manager hints (EWMH), you can query the root window using the "_NET_CLIENT_LIST" atom. This returna list of client windows the window manager is managing. For more information, see here.

However, there are some issues with this. For a start, the window manager in use must support the EWMH. KDE and GNOME do, and I'm sure some others do as well. However, I'm sure there are many that don't. Also, I've noticed a few issues with KDE. Basically, some non-KDE applications don't get included in the list. For example, if you run xcalc under KDE it won't show up in this list.

If anyone can provide any improvements on this method, I'd be glad to hear them. For reference, the code I'm using is listed below:

    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);
    }
所谓喜欢 2024-08-05 08:29:02

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

// 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);

To expand on the previous solution, if you want to then get the window names:

// 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);
哆兒滾 2024-08-05 08:29:02

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

If you don't have to use Xlib, using GDK's gdk_screen_get_window_stack() and gdk_window_get_window_type() may help you out for your needs.

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