Xlib和Firefox的行为

我试图创build一个小窗口pipe理器(只是为了好玩),但我在处理由Firefox创build的窗口时遇到问题(只有使用该应用程序,其他应用程序工作正常)

问题是,我启动Firefox后,添加我的装饰,似乎工作正常,但如果例如我尝试点击菜单button,(子)窗口不会出现。

什么似乎发生的是,点击后,ClientMessage事件触发与以下值:

Data: (null) Data: _NET_WM_STATE_HIDDEN Data: (null) Data: (null) Data: (null) 

现在的问题是,我不知道如何显示窗口,哪个窗口。 我试着用:

  • XRaiseWindow
  • XMapWindow
  • 我试图得到瞬态窗口,并显示它

但没有成功。 我不明白的是,如果这个客户端消息是由菜单子窗口生成或不。

我应该如何显示一个窗口在_NET_WM_STATE_HIDDEN?

另一个奇怪的问题是,收到ClientMessage后,我总是收到2个UnMapNotify事件。

我还有另一个问题,如果我想显示“文件,编辑”菜单(在Firefox中,如果我没有记错的话,当你按下Alt键时。

也许Firefox创build一个窗口树?

这是我处理事件的循环:

 while(1){ XNextEvent(display, &local_event); switch(local_event.type){ case ConfigureNotify: configure_notify_handler(local_event, display); break; case MotionNotify: motion_handler(local_event, display); break; case CreateNotify: cur_win = local_event.xcreatewindow.window; char *window_name; XFetchName(display, cur_win, &window_name); printf("Window name: %s\n", window_name); if(window_name!=NULL){ if(!strcmp(window_name, "Parent")){ printf("Adding borders\n"); XSetWindowBorderWidth(display, cur_win, BORDER_WIDTH); } XFree(window_name); } break; case MapNotify: map_notify_handler(local_event,display, infos); break; case UnmapNotify: printf("UnMapNotify\n"); break; case DestroyNotify: printf("Destroy Event\n"); destroy_notify_handler(local_event,display); break; case ButtonPress: printf("Event button pressed\n"); button_handler(local_event, display, infos); break; case KeyPress: printf("Keyboard key pressed\n"); keyboard_handler(local_event, display); break; case ClientMessage: printf("------------ClientMessage\n"); printf("\tMessage: %s\n", XGetAtomName(display,local_event.xclient.message_type)); printf("\tFormat: %d\n", local_event.xclient.format); Atom *atoms = (Atom *)local_event.xclient.data.l; int i =0; for(i=0; i<=5; i++){ printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i])); } int nchild; Window *child_windows; Window parent_window; Window root_window; XQueryTree(display, local_event.xclient.window, &root_window, &parent_window, &child_windows, &nchild); printf("\tNumber of childs: %d\n", nchild); break; } 

现在在客户端消息中,我只是试图收集一些信息来了解发生了什么。 从上面的代码中我可以看到,引发事件的窗口包含了一个孩子(又是:是不是菜单?)

MapNotify事件的代码,我添加装饰是:

 void map_notify_handler(XEvent local_event, Display* display, ScreenInfos infos){ printf("----------Map Notify\n"); XWindowAttributes win_attr; char *child_name; XGetWindowAttributes(display, local_event.xmap.window, &win_attr); XFetchName(display, local_event.xmap.window, &child_name); printf("\tAttributes: W: %d - H: %d - Name: %s - ID %lu\n", win_attr.width, win_attr.height, child_name, local_event.xmap.window); Window trans = None; XGetTransientForHint(display, local_event.xmap.window, &trans); printf("\tIs transient: %ld\n", trans); if(child_name!=NULL){ if(strcmp(child_name, "Parent") && local_event.xmap.override_redirect == False){ Window new_win = draw_window_with_name(display, RootWindow(display, infos.screen_num), "Parent", infos.screen_num, win_attr.x, win_attr.y, win_attr.width, win_attr.height+DECORATION_HEIGHT, 0, BlackPixel(display, infos.screen_num)); XMapWindow(display, new_win); XReparentWindow(display,local_event.xmap.window, new_win,0, DECORATION_HEIGHT); set_window_item(local_event.xmap.window, new_win); XSelectInput(display, local_event.xmap.window, StructureNotifyMask); printf("\tParent window id: %lu\n", new_win); put_text(display, new_win, child_name, "9x15", 10, 10, BlackPixel(display,infos.screen_num), WhitePixel(display, infos.screen_num)); } } XFree(child_name); } 

现在有人可以帮我解决这些问题吗? 不幸的是,我已经search了很多次,但没有成功。

总之,我的问题是两个:1.如何显示Firefox的子窗口2.如何显示文件,编辑菜单。

UPDATE

我注意到一些奇怪的testingFirefox与XIV了解什么事件被解雇,以显示一个应用程序。 我看到,统一使用Firefox,并在另一个窗口pipe理器中使用Firefox,所发生的事件是完全不同的。 在Unity中,我只有:

  1. ClientMessage
  2. UnmapNotify

比如使用Firefox,例如xfce4,生成的xevents更多:

  1. VisiblityNotify(多个)
  2. 暴露事件(多个)

但是,如果我尝试在我的WM启用VisibilityChangeMask,我收到以下事件:

  • ConfigureNotify
  • ClientMessage
  • MapNotify
  • 2 UnMapNotify

更新2

我试图读取ClientMessage窗口中的XWMhints属性(可能是菜单窗口),值是:

  • 对于标志67 = InputHint,StateHint,WIndowGroupHint

  • 初始状态为NormalState

更新3

我试图看看另一个窗口pipe理器是如何工作的,而我正在查看冷静的源代码。 我的理解是,当ClientMessage事件到达时,使用_NET_WM_STATE消息来更新这些属性,而在_NET_WM_STATE_HIDDEN的情况下它将清除此属性,结果将是该属性将被删除。 所以我试图更新我的代码来删除该属性,但它仍然无法正常工作。 无论如何,client_message_handler中的相关更新代码现在看起来像这样:

 Atom *atoms = (Atom *)local_event.xclient.data.l; int i =0; for(i=0; i<=5; i++){ printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i])); if(i==1){ printf("\t Deleting Property: _NET_WM_STATE_HIDDEN \n"); XDeleteProperty(display, cur_window, atoms[i]); } } 

这只是一个testing,我敢肯定,在我的情况下,我= 1是_NET_WM_STATE_HIDDEN属性。

这里有一个冷静源代码的链接: https : //github.com/chneukirchen/cwm/blob/linux/xevents.c

所以我仍然坚持在这一点上。

更新4

真的我不知道是否有帮助,但我试图读取MapNotify事件中的窗口属性,并且窗口map_state是IsViewable(2)。

更新5

我在这里发现了一个类似的问题,使用xlib与python: Xlib python:无法映射Firefox的菜单

解决schemebuild议使用XSetInputFocus,我试图在我的XMapNotify处理程序:

 XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime); 

但它仍然没有帮助,Firefox的菜单仍然没有出现! 而我有同样的问题,右键单击。

更新6

使用xconfigurenotify事件和unmap事件我发现:Xconfigure请求有2个窗口字段:窗口和以上,并且当xconfigurerequest.window值是相同的xunmap.window值。

而且xconfigurerequest.above总是在变化,但是xconfigurerequest.window在所有的事件中都是一样的。

看来xconfigurerequest.above与我试图打开的菜单有关。 例如:

  • 如果用鼠标右键单击一个页面,我会得到一个id(随后的每次点击总是一样的)
  • 如果我右键点击一个标签,上面的值是另一个
  • 如果我左键单击Firefox主菜单也会发生同样的情况

仍然不知道这是否有帮助。

真的不知道有人有什么想法吗?

使用xtruss一个简单易用的X协议跟踪程序


概观

任何习惯于在Linux或System V类Unix上编写程序的程序员都会遇到不同程度的strace或truss程序,这些程序会监视另一个程序,并产生程序所做的每个系统调用的详细日志 – 换句话说,所有的程序与OS内核的交互。 这通常是一个非常宝贵的debugging工具,几乎和教育一样好。

然而,当你想要了解或debugging一个GUI程序(更确切地说是与程序的GUI相关的行为)时,与OS内核的交互级别很less是最有用的。 更有帮助的是,人们希望以同样的方式logging所有程序与X服务器的交互。

程序已经存在,将做到这一点。 我知道Xmon和Xtrace。 但他们往往需要付出很大的努力才能build立起来:你必须运行程序来build立一个监听服务器,然后手动安排目标程序来联系,而不是真正的服务器 – 包括一些在xauth上的工作。 理想情况下,您想要跟踪程序的X操作就像跟踪其内核系统调用一样简单:您想要input一个像strace程序名参数一样简单的命令,并为您自动处理所有内容。

而且,这些程序的输出比我所喜欢的更不容易阅读 – 我基本上认为它不像我想要的那么紧张。 strace具有将每个系统调用和返回值放在同一行输出上的好处,以便您一眼就能看出每个响应是什么响应。 然而,X协议监视器倾向于忠实地遵循X协议的结构,这意味着每个请求和响应都用一个序列号来打印,而且你必须一个一个的来匹配两个协议。

所以这个页面展示了xtruss,我自己对X协议logging器领域的贡献。 它有一个类似于strace的命令行语法 – 在默认模式下,您只需将“xtruss”前缀添加到您将要运行的同一命令行中,而且其输出格式也更像strace,将请求和响应放在相同的位置在合理可能的情况下输出。

strace还支持附加到一个已经运行的进程的function,并且在一个长时间运行的进程出现问题时,可以从运行的中间进行跟踪 – 这在你事先不知道的情况下是需要跟踪的。 xtruss支持这个相同的function,通过X RECORD扩展(只要你的X服务器支持它,现代的X.Org是这样做的)。 所以在这种模式下,你可以用鼠标标识一个窗口(类似于xwininfo和xkill这样的标准程序),并且xtruss将附加到拥有你指定的窗口的X客户端程序,并开始跟踪它。


描述

xtruss是一个实用工具,logging在X服务器和一个或多个X客户端程序之间传递的所有内容。 在这里它与xmon(1)类似,但是打算将xmon的基本function与更接近strace(1)的界面结合起来。

像xmon一样,xtruss在默认模式下的工作方式是设置一个代理X服务器,等待连接,并将它们转发到真正的X服务器。 然而,与xmon不同的是,你不需要手工处理任何事情:不需要在一个terminal上启动跟踪实用程序,并手动从另一个terminal附加进程,除非你真的想(在这种情况下 – P选项将做到这一点)。 主要的使用方式是只键入xtruss,然后是X程序的命令行; xtruss会自动调整新程序的环境来指向它的代理服务器,并且(也不像xmon)它也会自动处理X授权。

作为另一种使用模式,如果您没有意识到要在已经启动之前追踪它,那么还可以将xtruss附加到已经运行的X应用程序。 这种模式需要X服务器的合作 – 具体来说,除非服务器支持RECORD协议扩展,否则它不能工作 – 但是由于现代的X.Org服务器确实提供了这种服务,所以它通常是有用的。