代码之家  ›  专栏  ›  技术社区  ›  Thomi

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

  •  12
  • Thomi  · 技术社区  · 15 年前

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

    3 回复  |  直到 7 年前
        1
  •  11
  •   Thomi    15 年前

    我有解决办法!

    嗯,有点像。

    如果窗口管理器使用扩展窗口管理器提示(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);
        }
    
        2
  •  6
  •   Ben    7 年前

    若要展开上一个解决方案,请先获取窗口名称:

    // 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);
    
        3
  •  1
  •   Melebius    7 年前

    如果你不需要使用xlib,使用gdk gdk_screen_get_window_stack() gdk_window_get_window_type() 可以帮助你满足你的需要。