Question

I have a small example program written in C that opens a window using the XCB API.

Strictly AFTER I have created and shown the window, I would (at a later time) like to hide the window.

(Obviously in this specific example, I could remove the call to xcb_map_window, and the window would be hidden, but I want to do it at a later point in my larger application, like a toggle to show/hide the window, NOTE: I do NOT want to minimize it).

Here is the sample code (NOTE: this code now works thanks to the answer):

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

Which I compile and run with:

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

From anything I can find on Google or here, I am doing everything correctly. So for clarification I am using Unity and Ubuntu 12.04 LTS:

unity --version reports:

unity 5.20.0

uname -a reports:

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

Can anyone explain where I've gone wrong in this code?

EDIT: updated code with a flush() at the end after xcb_unmap_window(); still doesn't work.

EDIT2: Tried code with cinnamon WM; still doesn't work (It's not a Unity bug).

EDIT3: Code updated in this post now works.

Was it helpful?

Solution

Your program simply goes too fast.

It maps the window and then immediately unmaps it. The window is top level, which means the requests are redirected to the window manager. But the window manager receives the unmap request when the window is not mapped yet, so it simply discards the request. Insert sleep(3) between the map and unmap calls and observe.

In real code, your window needs to get at least one expose event before sending out the unmap request. This guarantees it's actually mapped by the window manager.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top