问题在于,启动Firefox并添加我的装饰后,它似乎工作正常,但是如果我尝试单击菜单按钮,(子)窗口不会出现。
看起来发生的情况是,在单击后,会触发一个具有以下值的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创建了一个窗口树?
这是我处理事件的循环:
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);
}
现在有人能帮我解决这些问题吗?不幸的是,我已经搜索了很多次,但没有成功。
总之,我的问题有两个: 1. 如何显示来自Firefox的子窗口 2. 如何显示文件、编辑菜单。
更新
我用xev测试Firefox时发现了一些奇怪的事情,以了解显示应用程序所触发的事件。我发现在Unity中使用Firefox和在另一个窗口管理器中使用Firefox时,触发的事件完全不同。在Unity中,我只有:
- ClientMessage
- UnmapNotify
而在其他窗口管理器中使用Firefox(例如xfce4),生成的xevents更多:
- VisiblityNotify(不止一个)
- Expose事件(不止一个)
但是,如果我尝试在我的wm中启用VisibilityChangeMask,我会收到以下事件:
- ConfigureNotify
- ClientMessage
- MapNotify
- 2 UnMapNotify
更新2
我尝试读取ClientMessage窗口(可能是菜单窗口)中的XWMhints属性,其值为:
对于标志67 = InputHint、StateHint、WIndowGroupHint
对于初始状态NormalState
更新3
我尝试查看另一个窗口管理器的工作原理,正在查看calmwm的源代码。我的理解是,当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]);
}
}
这只是一个测试,我确定在我的情况下i=1是_NET_WM_STATE_HIDDEN属性。这里有一个链接指向calmwm源代码:https://github.com/chneukirchen/cwm/blob/linux/xevents.c。所以我还卡在那个点上。 更新4 我真的不知道它是否有帮助,但我尝试在MapNotify事件中读取窗口属性,窗口map_state为IsViewable(2)。 更新5 我在SO中找到了一个类似的问题,使用xlib和python:Xlib python: cannot map firefox menus。解决方案建议使用XSetInputFocus,我在我的XMapNotify处理程序中尝试了一下。
XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime);
但这仍然没有帮助,火狐菜单仍然不会出现!!我右键也有同样的问题。
更新6
通过玩xconfigurenotify事件和unmap事件,我发现: Xconfigure请求有2个窗口字段:窗口和above,当 xconfigurerequest.window值与xunmap.window值相同时。
而且xconfigurerequest.above总是在变化,但在所有事件中,xconfigurerequest.window始终相同。
似乎xconfigurerequest.above与我试图打开的菜单有关。例如:
如果右键单击页面,我会得到一个ID(对于每个后续单击始终相同) 如果我右键单击选项卡,则上面的值就是另一个值 如果我左键单击Firefox主菜单,情况也是如此
还不知道这是否有帮助。
真的不知道 有人有任何想法吗?
XFlush
对于动作的执行非常关键,如果未执行XFlush
,则不会前台显示,至少在我们的经验中是这样,所以使用XFlush
可能是您的解决方案,请告诉我结果如何。 - yatg