Frage

I am trying to make a very simple window manager for learning purposes. I am using C and the xcb library. I am trying to get an event raised if a new application is launched.

For now, I create a root window where I can receive mouse and keyboard events. I also draw a colored bar on the top of the window. When I press enter, xterm will launch using fork and execvp. This all works great.

When xterm (or any application I think) launches, it gets drawn on top of the bar (x = 0, y = 0). I would like to move it a bit lower (x = 0, y = 16). I think I know how to move the window, using xcb_configure_window. But I don't know how to get an event for the newly launched application.

Edit:
After some messing around I came to the following conclusions:
If I create my parent window like this:

xcb_window_t window_root = screen->root;
uint32_t mask = 0;    
uint32_t values[2];
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(connection, window_root, mask, values);
xcb_flush(connection);

i will receive a XCB_CREATE_NOTIFY when I spawn a new terminal. However, I am not able to draw anything on the screen, because I am not "subscribed" to the XCB_EVENT_MASK_EXPOSE event. If I change the values[0] line to this:

values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE;

i will still receive creation events, but the expose event does not get called as soon as the program starts, so my bar will not get drawn. It will get an expose event as soon as I launch a new terminal though, but my initial drawing won't happen.

My old method of creating a parent window was:

xcb_window_t window = xcb_generate_id(connection);
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t values[2] = {screen->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY };
xcb_create_window(connection, 0, window, screen->root, 0, 0, screen->width_in_pixels, screen->height_in_pixels, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values);
xcb_map_window(connection, window);

This will draw a white background and draw my colored bar, because it immediately gets an XCB_EVENT_MASK_EXPOSURE event. But it won't get an XCB_CREATE_NOTIFY event.

So what is the correct way to get both the XCB_CREATE_NOTIFY events and the XCB_EVENT_MASK_EXPOSURE events?

War es hilfreich?

Lösung

I was being silly and I fixed it!

I thought I only got expose events after I launched a new terminal. But I never even drew my bar and background before entering the event loop, I only drew them in my XCB_EXPOSE loop. So when a new terminal got launched, the expose event would get called, and my bar and background appeared.

Now I placed the drawing functions before my event loop as well, and everything works like it should. I don't know if this is the right/best way to go, but for future reference, use the following to create your root screen:

xcb_window_t window_root = screen->root;
uint32_t mask = 0;    
uint32_t values[2];
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(connection, window_root, mask, values);
xcb_flush(connection);

You will get expose events, and newly launched programs will appear in the XCB_CREATE_NOTIFY event.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top