我想在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;
}
现在我遇到的问题是,这经历了大多数窗口然后给我一个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函数返回的是一些我无法检索名称的窗口,但我不确定。
提前致谢!
答案 0 :(得分:6)
根据我的评论,由于代码列在问题中,我收到编译器警告:
在函数'list'中:14:29:警告:传递参数10 'XGetWindowProperty'来自不兼容的指针类型[启用 默认]
&type, &form, &len, &remain, &list); ^
包含在文件中......: /usr/include/X11/Xlib.h:2688:12:注意:预期'long unsigned int '但参数类型为'long unsigned int * '
通过从第10个参数中删除address-of运算符来修复问题,将&len
更改为len
,因为它被传递给list()
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
错误,所以我在第38行插入了一个sleep( 3 )
,就在for循环之前,给了我足够的时间来关闭一个窗口,试图复制行为。
果然,这再现了错误: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)
...
E.G:
7: neo – Dolphin
8: neo – Dolphin
Something had happened, bruh.
9: (null)
10: neo – Dolphin
希望这可以让你开始......我会留下有趣的部分,例如检测发生的错误&#39;,以及调整列表的编号/显示方式; )