Pregunta

Estoy tratando de obtener una lista de todas las ventanas de escritorio de nivel superior en una sesión X11. Básicamente, quiero obtener una lista de todas las ventanas que se muestran en la interfaz de usuario de cambio de aplicaciones de los administradores de ventanas (que normalmente se abre cuando el usuario presiona ALT + TAB).

Nunca he hecho ninguna programación de X11 antes, pero hasta ahora he logrado enumerar toda la lista de ventanas, con un código que se parece a esto:

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);
}
Inicialmente se llama a

enumerateWindows () con la ventana raíz.

Esto funciona, en la medida en que imprime información sobre cientos de ventanas; lo que necesito es determinar qué propiedad puedo interrogar para determinar si una Window es un nivel superior. Ventana de aplicación de escritorio (no estoy seguro de cuál es la terminología oficial) o no.

¿Alguien puede arrojar algo de luz sobre esto? Toda la documentación de referencia que he encontrado para la programación de X11 ha sido terriblemente seca y difícil de entender. Quizás alguien podría apuntar a un mejor recurso?

¿Fue útil?

Solución

Tengo una solución!

Bueno, más o menos.

Si su administrador de ventanas usa las sugerencias del administrador de ventanas extendidas (EWMH), puede consultar la ventana raíz utilizando la " _NET_CLIENT_LIST " átomo. Esta lista de retorno de ventanas de clientes que el administrador de ventanas está administrando. Para obtener más información, consulte aquí .

Sin embargo, hay algunos problemas con esto. Para empezar, el administrador de ventanas en uso debe ser compatible con EWMH. KDE y GNOME lo hacen, y estoy seguro de que otros también lo hacen. Sin embargo, estoy seguro de que hay muchos que no lo hacen. Además, he notado algunos problemas con KDE. Básicamente, algunas aplicaciones que no son KDE no se incluyen en la lista. Por ejemplo, si ejecuta xcalc en KDE, no aparecerá en esta lista.

Si alguien puede proporcionar alguna mejora en este método, me encantaría escucharlos. Para referencia, el código que estoy usando se indica a continuación:

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

Otros consejos

Para expandir la solución anterior, si desea obtener los nombres de las ventanas:

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

Si no tiene que usar Xlib, usar gdk_screen_get_window_stack () y gdk_window_get_window_type () de GDK puede ayudarlo a satisfacer sus necesidades.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top