2009-07-29 8 views
12

Ich versuche, eine Liste aller Top-Level-Desktop-Windows in einer X11-Sitzung zu bekommen. Im Grunde möchte ich eine Liste aller Fenster erhalten, die in der Benutzerschnittstelle der Fenstermanager-Anwendung angezeigt werden (häufig geöffnet, wenn der Benutzer ALT + TAB drückt).Wie identifiziere ich Top-Level X11-Fenster mit xlib?

Ich habe noch nie eine beliebige X11 Programmierung getan, aber bisher habe ich es geschafft, durch die gesamte Fensterliste aufzuzählen, mit Code, der etwa wie folgt aussieht:

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() heißt zunächst mit der Root-Fenster.

Das funktioniert, insofern es Informationen über hunderte von Fenstern ausgibt - was ich brauche, ist herauszufinden, welche Eigenschaft ich abfragen kann, um festzustellen, ob ein gegebenes Window ein Top-Level-Desktop-Anwendungsfenster ist (nicht sicher was die offizielle Terminologie ist) oder nicht.

Kann jemand etwas Licht darauf werfen? Die gesamte Referenzdokumentation, die ich für X11-Programmierung gefunden habe, war schrecklich trocken und schwer zu verstehen. Vielleicht könnte jemand auf eine bessere Ressource hinweisen?

Antwort

11

Ich habe eine Lösung!

Nun, irgendwie.

Wenn Ihr Fenstermanager die erweiterten Fenstermanagerhinweise (EWMH) verwendet, können Sie das Stammfenster mit dem Atom "_NET_CLIENT_LIST" abfragen. Diese Rückgabe-Liste von Client-Fenstern, die der Fenstermanager verwaltet. Weitere Informationen finden Sie unter here.

Allerdings gibt es einige Probleme mit diesem. Zunächst muss der verwendete Fenstermanager den EWMH unterstützen. KDE und GNOME tun es, und ich bin sicher, dass es auch andere tun. Ich bin mir jedoch sicher, dass es viele gibt, die das nicht tun. Außerdem habe ich ein paar Probleme mit KDE bemerkt. Grundsätzlich werden einige Nicht-KDE-Anwendungen nicht in die Liste aufgenommen. Wenn Sie beispielsweise xcalc unter KDE ausführen, wird es in dieser Liste nicht angezeigt.

Wenn jemand diese Methode verbessern kann, würde ich mich freuen, sie zu hören. Als Referenz wird der Code verwende ich unten aufgeführt:

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

Dieser Code nicht korrekt ist, die 32-Bit-Format bezieht sich auf die Anzahl der Bits, die auf dem Server und nicht auf dem Client verwendet werden. Clients verwenden immer "long", um XID-Werte darzustellen. Ihr Array muss ein Array von 'long' nicht quint32 sein. –

1

Wenn Sie Xlib nicht verwenden müssen, kann die Verwendung von GDKs gdk_screen_get_window_stack() und gdk_window_get_window_type() Ihnen für Ihre Bedürfnisse helfen.

6

auf der vorherigen Lösung zu erweitern, wenn Sie wollen, um dann die Fensternamen zu erhalten:

// 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

Yup, danke für die Info. – Thomi

+0

Beachten Sie, dass 'XFetchName' erfolgreich sein kann, aber setzen Sie' name = NULL'. Ihr Beispiel stürzt in diesem Fall ab. Auch 'char * name = '\ 0';' ist irreführend, die Konstante sollte wie 'NULL' aussehen, da es sich um einen Zeiger und kein Zeichen handelt. – Ruslan

+0

Korrigierter Code zur Behandlung eines NULL-Namens. – Ben

Verwandte Themen