When can I draw?

This chapter looks at when a request to redraw a surface can be made

Resources

Frame listener

A Wayland server will render buffers. This will take some time. If an attempt is made by a client to ask for a buffer to be rendered prematurely, it won't happen: the request will be ignored. The server must be able to tell a client when it is ready to handle another surface commit request.

The client needs to register a listener for the server's information. This is done by first getting a wl_callback by wl_surface_frame and then adding a listener by wl_callback_add_listener as in

	
    frame_callback = wl_surface_frame(surface);
    wl_callback_add_listener(frame_callback, &frame_listener, NULL);
	
      

The wl_callback_listener is a struct with only one function member such as

	
static const struct wl_callback_listener frame_listener = {
    redraw
};
	
      

The function (here redraw) could do a variety of things: for example it could set a flag for a thread to later render something, or it could wake up a sleeping thread to render. Here we just draw again into shared memory and call to render that by committing the surface. The drawing is deliberately simple: fill the drawing area with a single colour, starting with black and each time lightening it to white, at the end of which we go back to black:

	
uint32_t pixel_value = 0x0; // black

static void
paint_pixels() {
    int n;
    uint32_t *pixel = shm_data;

    for (n =0; n < WIDTH*HEIGHT; n++) {
	*pixel++ = pixel_value;
    }

    // increase each RGB component by one
    pixel_value += 0x10101;

    // if it's reached 0xffffff (white) reset to zero
    if (pixel_value > 0xffffff) {
	pixel_value = 0x0;
    }
}
	
      

The complete code is surface.c:


      

How much should I draw?

Content written to a surface's buffer will stay unchanged until overwritten by the client. The compositor is responsible for manipulating and displaying this content, so if, say, a portion of the client's window is obscured and then uncovered, the compositor will look after redrawing it without the client needing to do anything. This is different to the X Window model, where the client has to redraw areas 'damaged' by the windows of other clients.

On the other had, if the client redraws content in an area, then it has to inform the compositor of which part to redraw. The wl_surface_commit tells the compositor to redraw, while the wl_surface_damage tells the compositor which areas to redraw.

In the previous example we redrew the entire window surface and consequently damaged the entire window surface as well. We can get an interesting effect by damaging a smaller rectangle each time, so that the undamaged area is not redrawn by the compositor. The result looks like

Damage
while the code is damage.c