我想在C中使用Xlib获取所有打开窗口标题的列表.我正在运行Ubuntu 12.04.我使用以下代码来完成此任务:
#include#include #include #include 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; }
现在我遇到的问题是,这通过大多数窗口,然后给我一个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
所以我想知道是否有人知道是什么导致了这个/如何解决它?
据我所知,list函数返回的是一些我无法检索名称的窗口,但我不确定.
提前致谢!
根据我的评论,由于代码列在问题中,我收到编译器警告:
在函数'list'中:14:29:警告:从不兼容的指针类型[默认启用]传递'XGetWindowProperty'的参数10
&type, &form, &len, &remain, &list); ^在文件包含...:/usr/include/X11/Xlib.h:2688:12:注意:预期'long unsigned int '但参数类型为'long unsigned int* '
通过从第10个参数中删除address-of运算符来修复,更改&len
为len
,因为它被传递给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; }
最初我没有得到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; }
我只是创建了一个小函数int catcher( Display*, XErrorEvent * )
来捕获错误,避免运行时终止.
如果你有更多的编码要遵循,我已经包含了第二次调用XErrorHandler()
,传递NULL
以恢复默认处理程序.
其他一些注释,首先通过杀死我创建的最后一个窗口来测试此代码,但这还不足以确定它是否会在收到错误后继续进行.所以我做了第二次测试,其中我杀死了列表末尾之前的窗口,并验证了成功.
最后几点说明:
显然错误处理程序过于简化了.捕获错误时,将显示该消息,程序将继续运行.但是,窗口项仍然打印,但反映为(null)
......
例如:
7: neo – Dolphin 8: neo – Dolphin Something had happened, bruh. 9: (null) 10: neo – Dolphin
希望这可以让你开始......我将留下有趣的部分,例如检测"发生了什么错误",并调整列表的编号/显示对你来说; )