4

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?

Carlito
  • 805
  • 10
  • 20
  • @JoachimPileborg Thanks for your comment. I tried that using XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, because I read something similar in other WM's code, but I never get any XCB_MAP_REQUEST or XCB_MAP_NOTIFY events in my event loop. I updated my post with a bit more info. – Carlito Oct 16 '12 at 09:45
  • I made a very _very_ simple window manager earlier this year, in Python and with XCB. Besides `XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY` I also had `XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT` and `XCB_EVENT_MASK_STRUCTURE_NOTIFY`. – Some programmer dude Oct 16 '12 at 09:51
  • And you just added those to your mask for your parent window? I am doing that right now with no results. Perhaps I need a different way to spawn a new terminal? Any chance I can see your code? – Carlito Oct 16 '12 at 09:54
  • I had all those for the root window. – Some programmer dude Oct 16 '12 at 10:04
  • @JoachimPileborg I am having a bit more succes now with `XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY`, but I won't get expose events. It depends how I create my root window I think. I updated my post with some code. How do you create your root window? – Carlito Oct 16 '12 at 13:38

1 Answers1

4

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.

Carlito
  • 805
  • 10
  • 20