Comment identifier les fenêtres X11 de premier niveau avec xlib?

J’essaie d’obtenir une liste de toutes les fenêtres de bureau de niveau supérieur dans une session X11. En gros, je souhaite obtenir une liste de toutes les fenêtres affichées dans l’interface utilisateur de commutation d’applications du gestionnaire de fenêtres (généralement ouverte lorsque l’utilisateur appuie sur ALT + TAB).

Je n’ai jamais fait de programmation X11 auparavant, mais jusqu’à présent, j’ai réussi à énumérer toute la liste des fenêtres, avec un code qui ressemble à ceci:

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:" <= Success && i && *list) { qDebug() << "... and Command:" << i <= Success && tf) { qDebug() << "TF set!"; } XWMHints *pHints = XGetWMHints(display, rootWindow); if (pHints) { qDebug() << "Flags:" <flags << "Window group:" <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() est appelé initialement avec la fenêtre racine.

Cela fonctionne, dans la mesure où il imprime des informations sur des centaines de fenêtres – ce dont j’ai besoin, c’est de déterminer quelle propriété je peux interroger pour déterminer si une Window donnée est une fenêtre d’application de bureau de niveau supérieur (vous ne savez pas exactement quelle est la terminologie officielle est) ou non.

Quelqu’un peut-il nous éclairer? Toute la documentation de référence que j’ai trouvée pour la programmation X11 a été terriblement sèche et difficile à comprendre. Peut-être que quelqu’un pourrait indiquer une meilleure ressource?

J’ai une solution!

Eh bien, en quelque sorte.

Si votre gestionnaire de fenêtres utilise les indications du gestionnaire de fenêtres étendu (EWMH), vous pouvez interroger la fenêtre racine à l’aide de l’atome ” _NET_CLIENT_LIST “. Cette liste retourne les fenêtres clientes gérées par le gestionnaire de fenêtres. Pour plus d’informations, cliquez ici .

Cependant, cela pose quelques problèmes. Pour commencer, le gestionnaire de fenêtres utilisé doit prendre en charge l’EWMH. KDE et GNOME le font, et je suis sûr que d’autres le font aussi. Cependant, je suis sûr que beaucoup ne le font pas. De plus, j’ai remarqué quelques problèmes avec KDE. Fondamentalement, certaines applications non-KDE ne sont pas incluses dans la liste. Par exemple, si vous exécutez xcalc sous KDE, il n’apparaîtra pas dans cette liste.

Si quelqu’un peut apporter des améliorations à cette méthode, je serais heureux de les entendre. Pour référence, le code que j’utilise est listé ci-dessous:

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

Pour développer la solution précédente, si vous souhaitez ensuite obtenir les noms de fenêtre:

 // 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 vous n’êtes pas obligé d’utiliser Xlib, utiliser gdk_screen_get_window_stack() et gdk_window_get_window_type() peut vous aider à répondre à vos besoins.