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

问题是,在我启动Firefox并添加我的装饰之后,它似乎工作得很好,但例如,如果我试图单击菜单按钮,(子)窗口就不会出现.

似乎发生的情况是,在单击之后,将使用以下值激发客户信息事件:

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

现在的问题是,我不知道如何显示窗口,哪个窗口.

  • XRaiseWindow
  • XMapWindow
  • 我试图获取临时窗口并将其显示出来

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

我应该如何显示处于网络状态的窗口?

另一个奇怪的问题是,在收到客户信息后,我总是收到两个未通知的事件.

我还有另一个问题,如果我想显示"File,Edit"menù(在Firefox中,如果我没记错的话,当你按下Alt按钮时,它会出现).

也许Firefox会创建一个windows树?

这是我处理事件的循环:

while(1){
    XNextEvent(display, &local_event);
    switch(local_event.type){
        case 配置通知:
            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  map 通知:
            map_notify_handler(local_event,display, infos);
        break;
        case 取消映射通知: 
            printf("Un map 通知\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 客户信息:
            printf("------------客户信息\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;
    }

现在在clientmessage中,实际上我只是想看看,收集一些信息来了解发生了什么.从上面的代码中我可以看到,引发事件的窗口包含一个子窗口(同样:这是菜单吗?还是不是?)

我添加装饰的 map 通知事件的代码如下:

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);
}

有人能帮我解决这些问题吗?不幸的是,我已经在谷歌上搜索了很多次,但都没有成功.

总而言之,我的问题有两个:

UPDATE

我注意到在使用xev测试Firefox时出现了一些奇怪的情况,以了解为了显示应用程序而触发了哪些事件.我看到在unity中使用Firefox,在另一个窗口管理器中使用Firefox,触发的事件完全不同.在团结中,我只有:

  1. 客户信息
  2. 取消映射通知

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

  1. VisiblityNotify(多个)
  2. expose 事件(多个)

但如果我try 在wm中启用VisibilityChangeMask,我会收到以下事件:

  • 配置通知
  • 客户信息
  • map 通知
  • 2 Un map 通知

UPDATE 2

我试图在客户信息窗口(可能是menù窗口)中读取XWMhints属性,其值如下:

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

  • 对于初始状态NormalState

UPDATE 3

我试着看看另一个窗口管理器是如何工作的,我在看calmwm的源代码.我的理解是,当客户信息事件到达时,带有_NET_WM_STATE消息,它会更新这些属性,在_NET_WM_STATE_HIDDEN的情况下,它会清除该属性,结果是该属性将被删除.所以我试图更新我的代码来删除那个属性,但它仍然不起作用.无论如何,客户端消息处理程序中的相关更新代码现在如下所示:

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_HIDDED属性.

这里有指向calmwm源代码的链接:https://github.com/chneukirchen/cwm/blob/linux/xevents.c

所以我仍然停留在这一点上.

UPDATE 4

我真的不知道这是否有帮助,但我try 在 map 通知事件中读取窗口属性,窗口映射_状态是可见的(2).

UPDATE 5

我在SO中发现了类似的问题,使用xlib和python:Xlib python: cannot map firefox menus

解决方案建议使用XSetInputFocus,我在我的X map 通知处理程序上进行了try :

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

但它仍然没有帮助,firefox菜单仍然没有出现!!

UPDATE 6

在使用xconfigurenotify事件和unmap事件时,我发现:

此外,上面的xconfiguration erequest.window总是在变化,但是在所有事件中xconfiguration erequest.window始终是相同的.

上面的xconfiguration erequest.似乎与我试图打开的菜单有关.例如:

  • 如果右键单击某个页面,我会得到一个ID(每次后续单击总是相同的)
  • 如果我在选项卡上单击鼠标右键,则上面的值是另一个值
  • 如果我左键单击Firefox主菜单,也会发生同样的情况

还是不知道这是否有帮助.

真的不知道 有谁知道吗?

推荐答案

这是一个古老的问题,但对于那些偶然发现这个问题并寻找答案的人来说,这里有一个经过编辑(切碎)的示例,说明我是如何根据上面的提示解决这个问题的:

while (event = xcb_poll_for_event(connection)) {
    uint8_t actual_event = event->response_type & 127;
    switch (actual_event) {
        case XCB_MAP_NOTIFY: ;
            xcb_map_notify_event_t *map_evt = (xcb_map_notify_event_t *)event;
            if (map_evt->override_redirect) {
                xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_transient_for(connection, map_evt->window);
                xcb_window_t transient_for = 0;
                xcb_icccm_get_wm_transient_for_reply(connection, cookie, &transient_for, NULL);
                if (transient_for) {
                    xcb_set_input_focus(connection, XCB_INPUT_FOCUS_POINTER_ROOT, transient_for, XCB_CURRENT_TIME);
                }
                xcb_flush(connection);
            }
            break;
        case XCB_CLIENT_MESSAGE: ;
            xcb_client_message_event_t *message_evt = (xcb_client_message_event_t *)event;
            xcb_get_atom_name_cookie_t name_cookie = xcb_get_atom_name(connection, message_evt->type);
            xcb_get_atom_name_reply_t *name_reply = xcb_get_atom_name_reply(connection, name_cookie, NULL);
            int length = xcb_get_atom_name_name_length(name_reply);
            char *atom_name = malloc(length + 1);
            strncpy(atom_name, xcb_get_atom_name_name(name_reply), length);
            atom_name[length] = '\0';
            free(atom_name);
            free(name_reply);

            if (message_evt->type == ewmh->_NET_WM_STATE) {
                xcb_atom_t atom = message_evt->data.data32[1];
                unsigned int action = message_evt->data.data32[0];
                xcb_get_atom_name_cookie_t name_cookie = xcb_get_atom_name(connection, atom);
                xcb_get_atom_name_reply_t *name_reply = xcb_get_atom_name_reply(connection, name_cookie, NULL);
                int length = xcb_get_atom_name_name_length(name_reply);
                char *atom_name = malloc(length + 1);
                strncpy(atom_name, xcb_get_atom_name_name(name_reply), length);
                atom_name[length] = '\0';
                if (action == XCB_EWMH_WM_STATE_REMOVE) {
                    if (atom == ewmh->_NET_WM_STATE_HIDDEN) {
                        xcb_delete_property(connection, message_evt->window, ewmh->_NET_WM_STATE_HIDDEN);
                    }
                }
                free(atom_name);
                free(name_reply);
            }
            break;
    }
}

作为解释,需要处理的重要事件是MapNotify和ClientMessage,因为有两件主要事情需要处理:窗口必须在请求 timeshift 除其隐藏状态(xcb_delete_property调用),并且瞬态的父窗口必须获得输入焦点(xcb_set_input_ocus调用;请注意,瞬态是用于获得焦点的瞬态窗口,而不是瞬态本身),或者Firefox将立即再次隐藏瞬态.

瞬态叠加在其父级之上也很重要,因此WM应尊重ConfigureRequest事件.

PS Even if this is the accepted answer, the code of it is for xcb, if you need the code for xlib check my answer below, with the code adapted for xlib, it does cover only the MapNotify event

C++相关问答推荐

找出文件是否包含给定的文件签名

C:二进制搜索和二进制插入

为什么删除CAP_DAC_OVERRIDE后创建文件失败?

在我的代码中,我需要在哪里编写输出函数?

实现简单字典时C语言中的段错误

解决S随机内存分配问题,实现跨进程高效数据共享

Kdb:仅升级指定的列

tick.q中的Kdb+键控表语法

为 struct 中的数组动态分配内存时出错

将数组插入数组

将回调/基于事件的C API转换为非回调API

Printf()在C中打印终止字符之后的字符,我该如何解决这个问题?

如何在VSCode中创建和使用我自己的C库?

为什么WcrTomb只支持ASCII?

我编写这段代码是为了判断一个数字是质数、阿姆斯特朗还是完全数,但由于某种原因,当我使用大数时,它不会打印出来

我错误地修复了一个错误,想了解原因

将char*铸造为空**

如何在Rust中处理C的longjmp情况?

将数组中的所有元素初始化为 struct 中的相同值

C/C++编译器可以在编译过程中通过按引用传递来优化按值传递吗?