How to subscribe to different events and debug them in an xcb demo application?

87 Views Asked by At

I'm trying to create a simple application that interacts with the xcb library functions. My objective is to emulate the behavior of a simple window manager. From what I understood, I need to setup Substructure Redirection on the root window, then listen to specific events on that window in order to organize its top level windows the way I want. The problem is, I just cannot figure out how to test the solution I came up with.

This is the code responsible for doing what I explained:

#include <stdlib.h>
#include <stdio.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>

int main() {
    xcb_connection_t *connection = xcb_connect(NULL, NULL);
    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;

    /* Subscribing to the desired events */
    uint32_t mask = XCB_CW_EVENT_MASK | 
                    XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | 
                    XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
    uint32_t values[3] = { XCB_KEY_PRESS, 1, 1 };

    /* This applies the values and mask to the root window I think */
    xcb_change_window_attributes(connection, screen->root, mask, values);

    xcb_flush(connection);

    xcb_generic_event_t *ev;
    while( (ev = xcb_wait_for_event(connection)) ) {
        switch(ev->response_type & ~0x80) {
            case XCB_KEY_PRESS: {
                xcb_key_press_event_t *ev = (xcb_key_press_event_t *)ev;

                if(ev->state & XCB_MOD_MASK_1) {
                    printf("Pressed the Alt key modifier\n");
                }
                printf("Key pressed: Keycode %d\n", ev->detail);

                break;
            }
            case XCB_CREATE_NOTIFY: {
                printf("CREATE NOTIFY\n");
                break;
            }
            case XCB_MAP_NOTIFY: {
                printf("MAP NOTIFY\n");
                break;
            }
        }

        free(ev);
    }

    xcb_disconnect(connection);
}

As you can see, the code is pretty simple, and I plan to expand it if I can find a solution to the problem at hand.

I'm using Xephyr to run the program. I just ran Xephyr -br -ac -noreset -screen 500x500 :1 to create a new window, and then DISPLAY=:1 ./myprogram to test it. Obviously nothing happens in the screen, but I wonder how can I get the outputs of the printf calls.

EDIT: The XCB_CREATE_NOTIFY and XCB_MAP_NOTIFY events are there because I'm expecting that when I init a new application inside this window, the X server would send that request to the window manager, which has the substructure redirection toggled. That way I could correctly alter the desired properties of the window. Please correct me if I'm wrong.

1

There are 1 best solutions below

2
Uli Schlachter On

Call xcb_flush() before you while-loop.

By default, sent requests end up in the output buffer. You need to explicitly call xcb_flush() to have the requests actually sent.

but I wonder how can I get the outputs of the printf calls.

There is no output since no printf calls run yet, because your ChangeWindowAttributes request was not yet actually sent.


Actually, when doing that and running your program under x11trace shows:

000:<:0001: 16: Request(2): ChangeWindowAttributes window=0x0000051e value-list={event-mask=KeyRelease}
000:>:0001:Error 16=Length: major=2, minor=0, bad=0x0000051e, seq=0001

Your request fails. And does not send what you expect it to send.

You want:

uint32_t mask = XCB_CW_EVENT_MASK;
uint32_t values[3] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT };

This still produces no output. I see events of type ConfigureRequest and MapRequest being generated, but none of these events are being printed.

I added the following to the switch to actually get some output:

default: printf("%d\n", ev->response_type);

(Also, your printf calls are missing a trailing \n.)