简体   繁体   English

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

[英]C - Xlib - BadWindow Error using XGetWindowProperty for window title

I want to get a list of all open windows' titles using Xlib in C. I am running Ubuntu 12.04. 我想在C中使用Xlib获取所有打开窗口标题的列表。我正在运行Ubuntu 12.04。 I am using the following code to accomplish 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 that I'm having is that this goes through most windows and then gives me a BadWindow error: 现在我遇到的问题是,这通过大多数窗口,然后给我一个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

So I'm wondering if anyone knows what is causing this/how to fix it? 所以我想知道是否有人知道是什么导致了这个/如何解决它?

As far as I can tell the list function is returning some windows that I can't retrieve the name of, but I'm not sure. 据我所知,list函数返回的是一些我无法检索名称的窗口,但我不确定。

Thanks in advance! 提前致谢!

As per my comments, as the code is listed in the question, I get the compiler warning: 根据我的评论,由于代码列在问题中,我收到编译器警告:

In function 'list': 14:29: warning: passing argument 10 of 'XGetWindowProperty' from incompatible pointer type [enabled by default] 在函数'list'中:14:29:警告:从不兼容的指针类型[默认启用]传递'XGetWindowProperty'的参数10

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

In file included ...: /usr/include/X11/Xlib.h:2688:12: note: expected 'long unsigned int ' but argument is of type 'long unsigned int * ' 在包含的文件中...:/usr/include/X11/Xlib.h:2688:12:注意:预期'long unsigned int '但参数类型为'long unsigned int * '

Which was fixed by removing the address-of operator from the 10th parameter, changing &len to len , as it's being passed to list() as unsigned long *len . 通过从第10个参数中删除address-of运算符来修复,将&len更改为len ,因为它作为unsigned long *len传递给list()

NOTE: in the name() function, as it's declared as unsigned long len , the address-of operator is necessary. 注意:在name()函数中,因为它被声明为unsigned long len ,所以需要address-of运算符。

Therefore, I've started with the following code which compiled without 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 was not getting the BadWindow error, so I inserted a sleep( 3 ) on line 38, just prior to the for loop to give me enough time to close a window in an attempt to replicate the behaviour. 最初我没有得到BadWindow错误,所以我在第38行插入了sleep( 3 ) ,就在for循环之前,给了我足够的时间关闭窗口以试图复制行为。

Sure enough, this reproduced the error: BadWindow (invalid Window parameter) . 果然,这再现了错误: BadWindow (invalid Window parameter)


Scanning the code it originally appeared that the if( wlist[i]==0 ) should kick out invalid window handles, but this is not actually the case. 扫描它最初出现的代码if( wlist[i]==0 )应该踢出无效的窗口句柄,但事实并非如此。 Additionally, inserting a if( !window ) test into the name() function itself was equally futile. 另外,在name()函数本身插入if( !window )测试同样是徒劳的。

However, the function XSetErrorHandler may be of some use, and I've included your code, revised, to show usage: 但是,函数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;
}

I've simply created a small function int catcher( Display*, XErrorEvent * ) to catch the errors, avoiding runtime termination. 我只是创建了一个小函数int catcher( Display*, XErrorEvent * )来捕获错误,避免运行时终止。

In case you have more coding to follow, I've included a second call to XErrorHandler() , passing NULL to restore the default handler. 如果你有更多的编码要遵循,我已经包含了对XErrorHandler()的第二次调用,传递NULL以恢复默认处理程序。


A few other notes, first tested this code by killing the last window I created, but that wasn't quite enough to determine if it would proceed after receiving the error. 其他一些注释,首先通过杀死我创建的最后一个窗口来测试此代码,但这还不足以确定它是否会在收到错误后继续进行。 So I did a second test wherein I killed windows that came before the end of the list, and have verified success. 所以我做了第二次测试,其中我杀死了列表末尾之前的窗口,并验证了成功。


A few final notes: 最后几点说明:

Obviously the error handler is over-simplified. 显然错误处理程序过于简化了。 When the error is caught, the message is displayed, and the program continues to run. 捕获错误时,将显示该消息,程序将继续运行。 However, the window item is still printed, but is reflected as (null) ... 但是,窗口项仍然打印,但反映为(null) ...

EG: 例如:

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

Hopefully this can get you started... I'll leave the fun parts, such as detecting which error 'had happened', and adjusting the numbering/display of the list up to you ; 希望这可以让你开始......我将留下有趣的部分,例如检测“发生了什么错误”,并调整列表的编号/显示对你来说; )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM