我正在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 和 Rust 代码片段之间的不同行为

当它们都是字符时,为什么我不能使用 strcat 组合这两个字符?

为什么将输出写入正在缓冲的管道

在 C 中使用 AVX 实现矩阵运算

预处理器算法是否应该与编译所针对的体系结构相匹配?

libcurl 放置数据流而不是文件

为什么我不能将动态函数指针传递给 atexit()?

是否有更高性能的 powf(10,floorf(log10f(x))) 实现

找到一种在 C 中调用具有不同参数的函数的方法

套接字编程中shutdown()函数中SHUT_RDWR的用途

C printf中的'I'(大写i)标志是什么?

复制具有“memcpy”技术上未定义行为的二维数组?

如何制作一个不会被优化的无限空循环?

在 C/C++ 中获得正模的最快方法

防止控制台窗口在 Visual Studio C/C++ 控制台应用程序上关闭

为什么 (A+B) 的 FFT 与 FFT(A) + FFT(B) 不同?

将输出重定向到文件时 printf() 和 system() 的结果顺序错误

“保留用于任何用途”是什么意思?

使用无符号而不是有符号的 int 是否更有可能导致错误?为什么?

什么是 C17,语言做了哪些改变?