【问题标题】:XCB: window will not unmap after being mapped onceXCB:窗口被映射一次后不会取消映射
【发布时间】:2013-10-16 21:00:45
【问题描述】:

我有一个用 C 语言编写的小示例程序,它使用 XCB API 打开一个窗口。

严格地说之后我已经创建了显示了窗口,我想(稍后)隐藏窗口。

(很明显,在这个特定示例中,我可以删除对 xcb_map_window 的调用,并且窗口将被隐藏,但我想稍后在我的较大应用程序中执行此操作,例如切换显示/隐藏窗口,注意:我不想最小化它)。

这是示例代码(注意:此代码现在可以工作,这要归功于答案):

#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include <xcb/xcb.h>

void set_window_visible(xcb_connection_t* c, xcb_window_t win, bool visible) {
    xcb_generic_event_t *event;

    if(visible) {
        // Map the window on the screen
        xcb_map_window (c, win);

        // Make sure the map window command is sent
        xcb_flush(c);

        // Wait for EXPOSE event.
        //
        // TODO: add timeout in-case X server does not ever send the expose event.
        while(event = xcb_wait_for_event(c)) {
            bool gotExpose = false;

            switch(event->response_type & ~0x80) {
            case XCB_EXPOSE:
                gotExpose = true;
                break;

            default:
                break; // We don't know the event type, then.
            }
            free(event);

            if(gotExpose) {
                break;
            }
        }

    } else {
        // Hide the window
        xcb_unmap_window(c, win);

        // Make sure the unmap window command is sent
        xcb_flush(c);
    }
}

int main() {
    xcb_connection_t *c;
    xcb_screen_t     *screen;
    xcb_window_t      win;
    xcb_generic_event_t *event;

    // Open the connection to the X server
    c = xcb_connect (NULL, NULL);

    // Get the first screen
    screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;

    // Ask for our window's Id
    win = xcb_generate_id(c);

    // Create the window
    uint32_t mask = XCB_CW_EVENT_MASK;
    uint32_t valwin[] = {XCB_EVENT_MASK_EXPOSURE | XCB_BUTTON_PRESS};
    xcb_create_window(
        c,                             // Connection
        XCB_COPY_FROM_PARENT,          // depth (same as root)
        win,                           // window Id
        screen->root,                  // parent window
        0, 0,                          // x, y
        150, 150,                      // width, height
        10,                            // border_width
        XCB_WINDOW_CLASS_INPUT_OUTPUT, // class
        screen->root_visual,           // visual
        mask, valwin                   // masks
    );

    bool visible = true;
    set_window_visible(c, win, true);

    while(1) {
        sleep(2);

        // Toggle visibility
        visible = !visible;
        set_window_visible(c, win, visible);

        printf("Window visible: ");
        if(visible) {
            printf("true.\n");
        } else {
            printf("false.\n");
        }
    }

    // pause until Ctrl-C
    pause();
    return 0;
}

我编译和运行的:

gcc xcbwindow.c -o xcbwindow -lxcb
./xcbwindow

从我在 Google 或此处可以找到的任何内容来看,我所做的一切都是正确的。因此,为了澄清起见,我使用的是 Unity 和 Ubuntu 12.04 LTS:

unity --version 报告:

unity 5.20.0

uname -a 报告:

Linux [redacted] 3.2.0-32-generic #51-Ubuntu SMP Wed Sep 26 21:33:09 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

谁能解释我在这段代码中哪里出错了?

编辑:在 xcb_unmap_window() 之后使用 flush() 更新代码;还是不行。

EDIT2:尝试使用肉桂 WM 的代码;仍然不起作用(这不是 Unity 错误)。

EDIT3:这篇文章中更新的代码现在可以工作了。

【问题讨论】:

    标签: c linux user-interface x11 xcb


    【解决方案1】:

    您的程序运行得太快了。

    它映射窗口,然后立即取消映射。窗口是顶级的,这意味着请求被重定向到窗口管理器。但是窗口管理器在窗口还没有被映射时收到了取消映射请求,所以它简单地丢弃了这个请求。在 map 和 unmap 调用之间插入 sleep(3) 并观察。

    在实际代码中,您的窗口需要在发出取消映射请求之前获得至少一个暴露事件。这保证了它实际上是由窗口管理器映射的。

    【讨论】:

    • 感谢您的提示!这确实解决了问题。我将使用正确的工作代码更新我的问题。你知道我是否会在取消映射请求时遇到任何奇怪的怪癖?例如。是与暴露相反的事件吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    相关资源
    最近更新 更多