2009-06-19 15 views
13

Quiero controlar todas las ventanas abiertas bajo X11. Actualmente, estoy haciendo esto de la siguiente manera:¿Cómo obtengo y sincronizo una lista completa de todas las ventanas X11?

  1. Inicialmente caminar todo el árbol mediante la llamada recursiva XQueryTree de la ventana raíz
  2. Para escuchar a la subestructura cambios en todo el escritorio: XSelectInput(display, root_window, SubstructureNotifyMask | PropertyChangeMask)
  3. el manejo de todo MapNotify, UnmapNotify y eventos DestroyNotify, actualizando mi propia lista de ventanas en el proceso

Me preocupa principalmente el punto 1. Durante la recursión, se llamará a XQueryTree varias veces. ¿Hay alguna manera de asegurar que el árbol no cambie mientras tanto? En otras palabras, ¿para obtener una "instantánea" de todo el árbol en un punto en el tiempo?

Además, he notado que en algunos sistemas X11, no todos los eventos llegan correctamente. Por ejemplo, al abrir una nueva ventana en el escritorio, MapNotify para esa ventana puede que nunca llegue a mi aplicación de monitoreo. ¿Cómo puede ser esto? ¿Es posible que se tire antes de llegar?

Actualización:

He escrito un pequeño programa que va a supervisar los eventos de X en la ventana raíz (véase más adelante). Ahora, cuando ejecuto este programa y comienzo y salgo de xcalc, obtengo la siguiente salida:

Reparented: 0x4a0005b to 0x1001e40 
Mapped : 0x1001e40 
Destroyed : 0x1001e40 

Eso es todo. Nunca me notifican que se está destruyendo la ventana real (0x4a0005b). ¡Ni siquiera de ser mapeado! ¿Alguien puede decirme por qué no? ¿SubStructureNotifyMask solo causa que se envíen eventos de las subventanas directas en lugar de todo el subárbol?

Por cierto, esto aparentemente no ocurre cuando se ejecuta Compiz. Entonces no se realiza reparentalización:

Mapped : 0x4a0005b 
Mapped : 0x4e00233 
Destroyed : 0x4a0005b 
Destroyed : 0x4e00233 

Monitoreo fuente del programa:

#include <X11/Xlib.h> 
#include <cstdio> 

int main() 
{ 
    Display *display; 
    Window rootwin; 

    display = XOpenDisplay(NULL); 
    rootwin = DefaultRootWindow(display); 
    XSelectInput(display, rootwin, SubstructureNotifyMask); 

    XEvent event; 

    while (1) { 
     XNextEvent(display, &event); 
     if (event.type == MapNotify) { 
      XMapEvent *mapevent = (XMapEvent *)&event; 
      printf("Mapped : 0x%x\n", (unsigned int)(mapevent->window)); 
     } 
     if (event.type == DestroyNotify) { 
      XDestroyWindowEvent *destroywindowevent = (XDestroyWindowEvent *)&event; 
      printf("Destroyed : 0x%x\n", (unsigned int)(destroywindowevent->window)); 
     } 
     if (event.type == ReparentNotify) { 
      XReparentEvent *reparentevent = (XReparentEvent *)&event; 
      printf("Reparented: 0x%x to 0x%x\n", (unsigned int)(reparentevent->window), (unsigned int)(reparentevent->parent)); 
     } 
    } 

    return 0; 
} 

Respuesta

16

Tenga una mirada en xwininfo.

También te recomendamos xprop y xspy para obtener más información.

Actualización: Yep. Intente utilizar xwininfo y -root con -tree o -children para obtener todas las ventanas involucradas.

Y los cambios se pueden rastrear con xprop -spy.

+1

Gracias! Eché un vistazo al código fuente de xwininfo y parece hacer el recorrido del árbol de la misma manera que lo hago: sin proteger las construcciones a su alrededor. Entonces, si existe la posibilidad de que el árbol cambie entre las llamadas a XQueryTree, xwininfo también se verá afectado y no dará los resultados correctos, supongo ... – Marten

+1

@Marten, sí. xwininfo es una instantánea, pero te dará la jerarquía. Luego puede abrir varias ventanas y usarlas para ejecutar xprop -spy para buscar actualizaciones. Hay bastantes de estas herramientas. Eche un vistazo a la lista de la página man en http://www.x.org/archive/X11R6.9.0/doc/html/manindex1.html –

3

Creo que agarrar el servidor X (XGrabServer (3)) evitará cambios en la jerarquía de la ventana. Sin embargo, es un poco pesado, por lo que probablemente solo deberías hacerlo si realmente lo necesitas.

Para ver un ejemplo de código que recorre la jerarquía de ventanas, crea un árbol, usa eventos de ventana para mantenerlo actualizado e ignora los errores de protocolo X que son inevitables debido a las carreras, consulte el archivo src/VBox/Additions/x11/VBoxClient/seamless-x11.cpp en el código fuente para VirtualBox.

+1

XGrabServer le brindará toda su atención, pero también desconecta a todos los otros clientes, lo que lo hace inútil para esto –

+0

XGrabServer no cierra las conexiones de los otros clientes, solo detiene el servidor X para que no procese ninguna solicitud sobre ellos, inmovilizándolos hasta que suelte el botón. Sin embargo, si su código se cuelga durante la captura, básicamente ha congelado la sesión de los usuarios, dejándolos bastante molestos con usted. – alanc

0

X11 es un protocolo remoto. Esto significa que cuando consulta el servidor X para obtener información, siempre obtiene su propia copia. Su copia nunca cambia cuando el servidor X actualiza sus estructuras de datos internas.

Esto significa que el árbol no cambiará repentinamente mientras lo recorre, pero cuando usa la información en él (como examinar una ventana), esa información podría estar obsoleta (alguien podría haber cerrado la ventana). Es por eso que necesita hacer el manejo correcto de errores.

Cuestiones relacionadas