views:

1391

answers:

3

I'm trying to get a list of all top level desktop windows in an X11 session. Basically, I want to get a list of all windows that are shown in the window managers application-switching UI (commonly opened when the user presses ALT+TAB).

I've never done any X11 programming before, but so far I've managed to enumerate through the entire window list, with code that looks something like this:

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() is called initially with the root window.

This works, in so far as it prints out information about hundreds of windows - what I need, is to work out which property I can interrogate to determine if a given Window is a top-level Desktop application window (not sure what the official terminology is), or not.

Can anyone shed some light on this? All the reference documentation I've found for X11 programming has been terribly dry and hard to understand. Perhaps someone could point be to a better resource?

A: 

I am also looking for solution. No luck so far. But if you don't have to use Xlib,using GDK's gdk_screen_get_window_stack() and gdk_window_get_window_type() or gdk_window_get_window_type() may help you out for your needs.

gc
+4  A: 

I have a solution!

Well, sort of.

If your window manager uses the extended window manager hints (EWMH), you can query the root window using the "_NET_CLIENT_LIST" atom. This returna list of client windows the window manager is managing. For more information, see here.

However, there are some issues with this. For a start, the window manager in use must support the EWMH. KDE and GNOME do, and I'm sure some others do as well. However, I'm sure there are many that don't. Also, I've noticed a few issues with KDE. Basically, some non-KDE applications don't get included in the list. For example, if you run xcalc under KDE it won't show up in this list.

If anyone can provide any improvements on this method, I'd be glad to hear them. For reference, the code I'm using is listed below:

 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);
 }
Thomi
+2  A: 

To expand on the previous solution, if you want to then get the window names:

// get window Id:
Window w = (Window) array[k];

char* name = '\0';
status = XFetchName(display, w, &name);
if (status >= Success)
{
    printf("Found: %ul  %s\n", w, name);
}
XFree(name);
Ben
Yup, thanks for the info.
Thomi