2009-07-29 10 views
12

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 IU de cambio de aplicación de administradores de ventana (comúnmente abierta cuando el usuario presiona ALT + TAB).¿Cómo identificar las ventanas de X11 de alto nivel utilizando xlib?

que nunca he hecho ningún tipo de programación X11 antes, pero hasta ahora he logrado enumerar a través de toda la lista de ventanas, con el código que se ve algo como 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); 
} 

enumerateWindows() se llama inicialmente con el 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 un determinado Window es una ventana de aplicación de escritorio de nivel superior (no estoy seguro 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 X11 ha sido terriblemente seca y difícil de entender. Tal vez alguien podría señalar a un mejor recurso?

Respuesta

11

¡Tengo una solución!

Bueno, más o menos.

Si su administrador de ventanas usa los consejos extendidos del administrador de ventanas (EWMH), puede consultar la ventana raíz usando el átomo "_NET_CLIENT_LIST". Esta retorna la lista de ventanas de cliente que administra el administrador de ventanas. Para obtener más información, consulte here.

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 de 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 gustaría escucharlos. Como referencia, el código que estoy usando se enumeran 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); 
    } 
+0

Este código no es correcto, el El formato de 32 bits se refiere a la cantidad de bits utilizados en el servidor, no al cliente. Los clientes siempre usan 'largo' para representar los valores de XID. Su matriz debe ser una matriz de 'largo' no quint32. –

1

Si no tiene que usar Xlib, puede usar el gdk_screen_get_window_stack() y el gdk_window_get_window_type() de GDK para ayudarlo con sus necesidades.

6

Para ampliar la solución anterior, si desea a continuación, 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); 
+0

Sí, gracias por la información. – Thomi

+0

Tenga en cuenta que 'XFetchName' puede tener éxito pero establezca' name = NULL'. Tu ejemplo se bloqueará en este caso. También 'char * name = '\ 0';' es engañoso, la constante debe verse como 'NULL', ya que es un puntero y no un caracter. – Ruslan

+0

Código fijo para manejar un nombre NULL. – Ben

Cuestiones relacionadas