C - Xlib - BadWindow使用XGetWindowProperty作为窗口标题时出错

Jac*_*nor 4 c window xlib

我想在C中使用Xlib获取所有打开窗口标题的列表.我正在运行Ubuntu 12.04.我使用以下代码来完成此任务:

#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;
}
Run Code Online (Sandbox Code Playgroud)

现在我遇到的问题是,这通过大多数窗口,然后给我一个BadWindow错误:

0: DNDCollectionWindow
1: launcher 
2: Desktop
3: panel
4: Dash
5: Hud
6: Switcher
7: Update Manager
8: Terminal
9: Ask a Question - Stack Overflow - 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
Run Code Online (Sandbox Code Playgroud)

所以我想知道是否有人知道是什么导致了这个/如何解决它?

据我所知,list函数返回的是一些我无法检索名称的窗口,但我不确定.

提前致谢!

pol*_*ekt 6

根据我的评论,由于代码列在问题中,我收到编译器警告:

在函数'list'中:14:29:警告:从不兼容的指针类型[默认启用]传递'XGetWindowProperty'的参数10

                         &type, &form, &len, &remain, &list);
                         ^ 
Run Code Online (Sandbox Code Playgroud)

在文件包含...:/usr/include/X11/Xlib.h:2688:12:注意:预期'long unsigned int '但参数类型为'long unsigned int* '

通过从第10个参数中删除address-of运算符来修复,更改&lenlen,因为它被传递给list()as unsigned long *len.

注意:在name()函数中,正如它所声明的那样unsigned long len,address-of运算符是必要的.

因此,我开始使用以下代码编译而没有警告:

#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;
}
Run Code Online (Sandbox Code Playgroud)

最初我没有得到BadWindow错误,所以我sleep( 3 )在for循环之前插入了第38行,以便给我足够的时间来关闭窗口以尝试复制行为.

果然,这再现了错误:BadWindow (invalid Window parameter).


扫描它最初出现的代码if( wlist[i]==0 )应该踢出无效的窗口句柄,但事实并非如此.另外,将if( !window )测试插入到name()函数本身同样是徒劳的.

但是,函数XSetErrorHandler可能有一些用处,我已经包含你的代码,修改后,以显示用法:

#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;
}
Run Code Online (Sandbox Code Playgroud)

我只是创建了一个小函数int catcher( Display*, XErrorEvent * )来捕获错误,避免运行时终止.

如果你有更多的编码要遵循,我已经包含了第二次调用XErrorHandler(),传递NULL以恢复默认处理程序.


其他一些注释,首先通过杀死我创建的最后一个窗口来测试此代码,但这还不足以确定它是否会在收到错误后继续进行.所以我做了第二次测试,其中我杀死了列表末尾之前的窗口,并验证了成功.


最后几点说明:

显然错误处理程序过于简化了.捕获错误时,将显示该消息,程序将继续运行.但是,窗口项仍然打印,但反映为(null)......

例如:

7: neo – Dolphin
8: neo – Dolphin
Something had happened, bruh.
9: (null)
10: neo – Dolphin
Run Code Online (Sandbox Code Playgroud)

希望这可以让你开始......我将留下有趣的部分,例如检测"发生了什么错误",并调整列表的编号/显示对你来说; )

  • 非常感谢您的详细解答!仍然试图让我的头围绕Xlib!是的,这是有效的,但当它开始看起来我可能根本没有得到答案我调查了其他的替代品,并使用XQueryTree写了一个解决方案!我离开了这个问题,因为我很好奇是什么导致了这个问题,所以希望现在我可以把它作为一个学术练习.有趣的是,运行你的代码,我没有错误,也没有(null).也许只是编译器警告导致它?我真的希望不会,如果是的话我觉得很蠢......再次感谢你的帮助!! :d (2认同)