2009-06-19 7 views
13

Je veux surveiller toutes les fenêtres ouvertes sous X11. À l'heure actuelle, je fais cela comme suit:Comment obtenir et synchroniser une liste complète de toutes les fenêtres X11?

  1. marchant Dans un premier temps l'arbre tout en appelant récursive XQueryTree de la fenêtre racine
  2. l'écoute des changements de sous-structure sur l'ensemble de bureau: XSelectInput(display, root_window, SubstructureNotifyMask | PropertyChangeMask)
  3. manutention Tous les MapNotify, UnmapNotify et DestroyNotify événements, mise à jour de ma propre liste de fenêtres dans le processus

Je suis principalement préoccupé par le point 1. Pendant la récursivité, XQueryTree sera appelé plusieurs fois. Y a-t-il un moyen de s'assurer que l'arbre ne change pas entre-temps? En d'autres termes, obtenir un «instantané» de l'ensemble de l'arbre à un moment donné?

En outre, j'ai remarqué que sous certains systèmes X11, tous les événements n'arrivent pas correctement. Par exemple, lors de l'ouverture d'une nouvelle fenêtre sur le bureau, MapNotify pour cette fenêtre peut ne jamais arriver à mon application de surveillance. Comment se peut-il? Est-il possible qu'il soit jeté avant d'arriver?

Mise à jour:

J'ai écrit un petit programme qui contrôlera les événements X sur la fenêtre racine (voir ci-dessous). Maintenant, quand je cours ce programme et commence et quitte xcalc, j'obtiens la sortie suivante:

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

C'est tout. Je ne suis jamais averti que la fenêtre réelle (0x4a0005b) est détruite. Pas même d'être cartographié! Quelqu'un peut-il me dire pourquoi pas? Est-ce que SubStructureNotifyMask ne cause que les événements directs sous-fenêtres à envoyer à la place du sous-arbre entier? D'ailleurs, cela ne se produit apparemment pas lorsque Compiz est en cours d'exécution. Alors pas reparentage est fait:

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

source de programme de surveillance:

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

Répondre

16

Jetez un oeil à xwininfo.

Vous pourriez également aimer xprop et xspy pour obtenir plus d'informations.

Mise à jour: Yep. Essayez d'utiliser xwininfo et -root avec -tree ou -children pour obtenir toutes les fenêtres concernées.

Et les modifications peuvent être suivies avec xprop -spy.

+1

Merci! J'ai regardé le code source pour xwininfo et il semble faire la traversée de l'arbre de la même manière que je le fais: sans protéger les constructions autour. Donc, s'il y a la possibilité que l'arbre change entre les appels XQueryTree, xwininfo sera également affecté et ne donnera pas les bons résultats je suppose ... – Marten

+1

@Marten, oui. xwininfo est un instantané, mais il vous donnera la hiérarchie. Ensuite, vous pouvez ouvrir plusieurs fenêtres et les utiliser pour lancer xprop -spy pour vérifier les mises à jour. Il y a quelques uns de ces outils. Jetez un oeil à la liste des pages de man http://www.x.org/archive/X11R6.9.0/doc/html/manindex1.html –

3

Je crois que saisir le serveur X (XGrabServer (3)) empêchera des changements à la hiérarchie de fenêtre. C'est un peu lourd mais vous ne devriez probablement le faire que si vous en avez vraiment besoin. Pour un exemple de code qui parcourt la hiérarchie des fenêtres, construit un arbre, utilise des événements de fenêtre pour le maintenir à jour et ignore les erreurs de protocole X qui sont inévitables en raison des races, voir le fichier src/VBox/Additions/x11/VBoxClient/seamless-x11.cpp dans le code source pour VirtualBox.

+1

XGrabServer vous donnera une attention complète, mais il déconnecte également tous les autres clients qui le rend inutile pour cela –

+0

XGrabServer ne ferme pas les connexions des autres clients, il arrête simplement le serveur X de traiter toutes les demandes sur eux, les gèlent tous jusqu'à ce que vous relâchiez le grappin. Si votre code se bloque pendant la saisie, vous avez gelé la session des utilisateurs, les laissant très en colère contre vous. – alanc

0

X11 est un protocole distant. Cela signifie que lorsque vous interrogez le serveur X pour obtenir des informations, vous obtenez toujours votre propre copie. Votre copie ne change jamais lorsque le serveur X met à jour ses structures de données internes. Cela signifie que l'arborescence ne changera pas brusquement pendant que vous la parcourez, mais lorsque vous utilisez les informations (comme l'examen d'une fenêtre), cette information peut être périmée (quelqu'un a peut-être fermé la fenêtre). C'est pourquoi vous devez effectuer une gestion correcte des erreurs.

Questions connexes