C - Xlib - BadWindow error using XGetWindowProperty for window title

I want to get a list of all open windows using Xlib in C. I am running Ubuntu 12.04. I use the following code for this:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>

Window *list(Display *disp, unsigned long *len)
{
    Atom prop = XInternAtom(disp, "_NET_CLIENT_LIST", False), type;
    int form;
    unsigned long remain;
    unsigned char *list;

    XGetWindowProperty(disp, XDefaultRootWindow(disp), prop, 0, 1024, False, XA_WINDOW,
                            &type, &form, &len, &remain, &list);
    return (Window *)list;
}
char *name(Display *disp, Window window)
{
    Atom prop = XInternAtom(disp, "WM_NAME", False), type;
    int form;
    unsigned long remain, len;
    unsigned char *list;

    XGetWindowProperty(disp, window, prop, 0, 1024, False, AnyPropertyType,
                            &type, &form, &len, &remain, &list);
    return (char*)list;
}
int main(int argc, char *argv[])
{
    Display *disp;
    Window *wlist;
    unsigned long len;
    char *wname;

    disp = XOpenDisplay(NULL);

    wlist = (Window*)list(disp, &len);

    int i;
    for(i = 0; i < (int)len; i++){
            if(wlist[i] != 0){
                    wname = name(disp, wlist[i]);
                    printf("%d: %s\n", i, wname);
                    free(wname);
            }
    }
return 0;
}

      

Now the problem I'm running into is that this goes through most windows and then gives a BadWindow error:

0: DNDCollectionWindow
1: launcher 
2: Desktop
3: panel
4: Dash
5: Hud
6: Switcher
7: Update Manager
8: Terminal
9: Ask a Question - Qaru - Mozilla Firefox
X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  20 (X_GetProperty)
  Resource id in failed request:  0x41
  Serial number of failed request:  22
  Current serial number in output stream:  22

      

So I'm wondering if anyone knows what is causing this / how to fix it?

As far as I can tell, the list function returns some windows from which I can't get the name, but I'm not sure.

Thanks in advance!

+3


source to share


1 answer


As per my comments, since the code is listed in the question, I get a compiler warning:

In function list: 14:29: warning: passing argument 10 from 'XGetWindowProperty from incompatible pointer type [enabled by default]

                         &type, &form, &len, &remain, &list);
                         ^ 

      

Included in the file ...: / usr / include / X 11 / Xlib.h: 2688: 12: note: expected 'long unsigned int, but the argument is of type' long unsigned int *

This was fixed by removing the operator-address from the 10th parameter, changing &len

to len

as it is passed in list()

as unsigned long *len

.

NOTE: in a function name()

, since it is declared as unsigned long len

, an operator address is required.

So I started with the following code, which compiled with no warnings:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>

Window *list(Display *disp, unsigned long *len)
{
    Atom prop = XInternAtom(disp, "_NET_CLIENT_LIST", False), type;
    int form;
    unsigned long remain;
    unsigned char *list;

    XGetWindowProperty(disp, XDefaultRootWindow(disp), prop, 0, 1024, False, XA_WINDOW,
                            &type, &form, len, &remain, &list);
    return (Window *)list;
}
char *name(Display *disp, Window window)
{
    Atom prop = XInternAtom(disp, "WM_NAME", False), type;
    int form;
    unsigned long remain, len;
    unsigned char *list;

    XGetWindowProperty(disp, window, prop, 0, 1024, False, AnyPropertyType,
                            &type, &form, &len, &remain, &list);
    return (char*)list;
}
int main(int argc, char *argv[])
{
    Display *disp;
    Window *wlist;
    unsigned long len;
    char *wname;

    disp = XOpenDisplay(NULL);

    wlist = (Window*)list(disp, &len);

    int i;
    for(i = 0; i < (int)len; i++){
            if(wlist[i] != 0){
                    wname = name(disp, wlist[i]);
                    printf("%d: %s\n", i, wname);
                    free(wname);
            }
    }
return 0;
}

      


Initially I didn't get the error BadWindow

, so I pasted sleep( 3 )

on line 38, just before the for loop, to give me enough time to close the window in an attempt to replicate the behavior.

Of course, this resulted in an error: BadWindow (invalid Window parameter)

.


Scanning for code that originally came up that if( wlist[i]==0 )

should call invalid window handles, but it really isn't. Also, injecting a test if( !window )

into a function name()

was useless by itself.

However, the XSetErrorHandler function might be useful and I've included your revised code to show usage:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>

int catcher( Display *disp, XErrorEvent *xe )
{
        printf( "Something had happened, bruh.\n" );
        return 0;
}

Window *list(Display *disp, unsigned long *len)
{
    Atom prop = XInternAtom(disp, "_NET_CLIENT_LIST", False), type;
    int form;
    unsigned long remain;
    unsigned char *list;

    XGetWindowProperty(disp, XDefaultRootWindow(disp), prop, 0, 1024, False, XA_WINDOW,
                            &type, &form, len, &remain, &list);
    return (Window *)list;
}
char *name(Display *disp, Window window)
{
    Atom prop = XInternAtom(disp, "WM_NAME", False), type;
    int form;
    unsigned long remain, len;
    unsigned char *list;

    XGetWindowProperty(disp, window, prop, 0, 1024, False, AnyPropertyType,
                            &type, &form, &len, &remain, &list);
    return (char*)list;
}
int main(int argc, char *argv[])
{
    Display *disp;
    Window *wlist;
    unsigned long len;
    char *wname;

    disp = XOpenDisplay(NULL);

    wlist = (Window*)list(disp, &len);

    sleep( 3 ); // <-- inserted to give me time to close an open window

    XSetErrorHandler( catcher ); // <-- inserted to set error handler

    int i;
    for(i = 0; i < (int)len; i++){
    //        if(wlist[i] != 0){    // <-- apparently futile?
                    wname = name(disp, wlist[i]);
                    printf("%d: %s\n", i, wname);
                    free(wname);
    //        }
    }

    XSetErrorHandler( NULL ); // <-- restore the default error handler
    return 0;
}

      




I just created a small function int catcher( Display*, XErrorEvent * )

to catch errors while avoiding execution termination.

If you have more codes, then I included a second call XErrorHandler()

, passing NULL

in to restore the default handler.


Several other notes, tested this code first by killing the last window I created, but it was not enough to determine if it would act after receiving an error. So I did a second test in which I killed the windows that came to the end of the list and confirmed success.


A few final notes:

Obviously, the error handler is oversimplified. When an error is caught, a message is displayed and the program continues to run. However, the window element still prints, but displays as (null)

...

eg:.

7: neo – Dolphin
8: neo – Dolphin
Something had happened, bruh.
9: (null)
10: neo – Dolphin

      


Hopefully this helps you get started ... I'll leave the fun parts like finding the "happened" error and adjusting the numbering / display of the list up to you; )

+6


source







All Articles