Come identificare le finestre X11 di livello superiore usando xlib?
Domanda
Sto cercando di ottenere un elenco di tutte le finestre desktop di livello superiore in una sessione X11. Fondamentalmente, voglio ottenere un elenco di tutte le finestre mostrate nell'interfaccia utente di commutazione delle applicazioni dei gestori di finestre (normalmente aperta quando l'utente preme ALT + TAB).
Non ho mai fatto alcuna programmazione X11 prima, ma finora sono riuscito a enumerare l'intero elenco di finestre, con un codice simile a questo:
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 ()
viene chiamato inizialmente con la finestra principale.
Funziona, nella misura in cui stampa informazioni su centinaia di finestre - ciò di cui ho bisogno, è capire quale proprietà posso interrogare per determinare se un dato Window
è di livello superiore Finestra dell'applicazione desktop (non so quale sia la terminologia ufficiale) oppure no.
Qualcuno può far luce su questo? Tutta la documentazione di riferimento che ho trovato per la programmazione X11 è stata terribilmente secca e difficile da capire. Forse qualcuno potrebbe indicare una risorsa migliore?
Soluzione
Ho una soluzione!
Beh, una specie di.
Se il tuo gestore di finestre utilizza i suggerimenti per il gestore di finestre estesi (EWMH), puoi eseguire una query sulla finestra di root utilizzando " _NET_CLIENT_LIST
" atomo. Questo elenco returna di finestre client che gestisce il gestore delle finestre. Per ulteriori informazioni, vedere qui .
Tuttavia, ci sono alcuni problemi con questo. Per cominciare, il gestore delle finestre in uso deve supportare l'EWMH. KDE e GNOME lo fanno, e sono sicuro che anche altri lo fanno. Tuttavia, sono sicuro che ce ne sono molti che non lo fanno. Inoltre, ho notato alcuni problemi con KDE. Fondamentalmente, alcune applicazioni non KDE non vengono incluse nell'elenco. Ad esempio, se esegui xcalc in KDE non verrà visualizzato in questo elenco.
Se qualcuno può fornire miglioramenti su questo metodo, sarei felice di ascoltarli. Per riferimento, il codice che sto usando è elencato di seguito:
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);
}
Altri suggerimenti
Per espandere la soluzione precedente, se si desidera ottenere i nomi delle finestre:
// 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);
Se non devi usare Xlib, usare GDK
e gdk_window_get_window_type ()
può aiutarti per le tue esigenze.