Pergunta

Eu estou tentando obter uma lista de todas as janelas da área de trabalho de alto nível em uma sessão X11. Basicamente, eu quero obter uma lista de todas as janelas que são mostrados nos gerenciadores de janelas de aplicação de comutação de UI (normalmente aberta quando o usuário pressiona ALT + TAB).

Eu nunca fiz qualquer X11 programação antes, mas até agora eu consegui enumerar toda a lista de janela, com o código que é algo como isto:

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() é chamado inicialmente com janela de raiz.

Isso funciona, na medida em que ele imprime informações sobre centenas de janelas - o que eu preciso, é trabalhar para fora que a propriedade que posso interrogar para determinar se uma determinada Window é uma janela de aplicação de nível superior área de trabalho (não sei o a terminologia oficial é), ou não.

Alguém pode lançar alguma luz sobre isso? Toda a documentação de referência que eu encontrei para programação X11 tem sido terrivelmente seco e difícil de entender. Talvez alguém poderia apontar se a um recurso melhor?

Foi útil?

Solução

Eu tenho uma solução!

Bem, mais ou menos.

Se o seu gerenciador de janelas usa as dicas gerenciador de janelas estendidos (EWMH), você pode consultar a janela de raiz usando o átomo "_NET_CLIENT_LIST". Esta lista returna de Windows Client o gerenciador de janelas está a gerir. Para mais informações, consulte aqui .

No entanto, existem alguns problemas com isso. Para começar, o gerenciador de janelas em uso deve apoiar o EWMH. KDE e GNOME fazer, e eu tenho certeza que alguns outros fazem bem. No entanto, eu tenho certeza que existem muitos que não o fazem. Além disso, tenho notado alguns problemas com o KDE. Basicamente, algumas aplicações não-KDE não são incluídos na lista. Por exemplo, se você executar Xcalc no KDE não vai aparecer nesta lista.

Se alguém pode fornecer quaisquer melhorias sobre este método, eu ficaria feliz em ouvi-los. Para referência, o código que estou usando é listado abaixo:

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

Outras dicas

Para expandir a solução anterior, se você quiser, em seguida, obter os nomes das janelas:

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

Se você não tem que usar Xlib, usando gdk_screen_get_window_stack() e gdk_window_get_window_type() da GDK pode ajudá-lo para as suas necessidades.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top