Drawing

In Wayland, drawing is done entirely on the client side. You render some content in a buffer and then attach the buffer to a surface. No drawing operations are sent over the socket. Wayland itself, therefore, has no rendering functionality or API.

This gives you the ultimate freedom in how you implement rendering. Most of the time, you're going to end up using a dedicated graphics library such as Cairo (and that's what we're going to do in the next section), but in order not to complicate things, we're going to do some manual drawing here.

With that said, let's go paint!

First of all, change the format in wl_shm_pool::create_buffer call from WL_SHM_FORMAT_XRGB8888 to WL_SHM_FORMAT_ARGB8888 (notice the A in place of X):

// allocate the buffer in that pool
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool,
    0, width, height, stride, WL_SHM_FORMAT_ARGB8888);

This isn't really necessary, because we're not using transparency just yet, but GNOME Shell seems to render color incorrectly if XRGB is used.

Now we can just fill the buffer with some color:

for (int x = 0; x < width; x++) {
    for (int y = 0; y < height; y++) {

        struct pixel {
            // little-endian ARGB
            unsigned char blue;
            unsigned char green;
            unsigned char red;
            unsigned char alpha;
        } *px = (struct pixel *) (data + y * stride + x * 4);

        // yellow
        px->alpha = 255;
        px->red = 255;
        px->green = 255;
        px->blue = 0;
    }
}

That's all we need. Compile and run it:

$ make
$ ./runme

Cool! Now, let's add a pattern, more colors and some transparency.

// draw a stripes pattern
if ((x + y) % 30 < 10) {
    // transparent
    px->alpha = 0;
} else if ((x + y) % 30 < 20) {
    // yellow
    px->alpha = 255;
    px->red = 255;
    px->green = 255;
    px->blue = 0;
} else {
    // semitransparent red
    px->alpha = 128;
    px->red = 255;
    px->green = 0;
    px->blue = 0;
}

For the last example, let's draw a cross:

// draw a cross
if ((80 < x && x < 120) || (80 < y && y < 120)) {
    // gradient from blue at the top to white at the bottom
    px->alpha = 255;
    px->red = (double) y / height * 255;
    px->green = px->red;
    px->blue = 255;
} else {
    // transparent
    px->alpha = 0;
}

results matching ""

    No results matching ""