The complete code
That's all we need to display a black square on screen! Here's our complete code again:
#include <stdio.h>
#include <string.h>
#include <syscall.h>
#include <unistd.h>
#include <sys/mman.h>
#include <wayland-client.h>
struct wl_compositor *compositor;
struct wl_shm *shm;
struct wl_shell *shell;
void registry_global_handler
(
void *data,
struct wl_registry *registry,
uint32_t name,
const char *interface,
uint32_t version
) {
if (strcmp(interface, "wl_compositor") == 0) {
compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 3);
} else if (strcmp(interface, "wl_shm") == 0) {
shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
} else if (strcmp(interface, "wl_shell") == 0) {
shell = wl_registry_bind(registry, name,
&wl_shell_interface, 1);
}
}
void registry_global_remove_handler
(
void *data,
struct wl_registry *registry,
uint32_t name
) {}
const struct wl_registry_listener registry_listener = {
.global = registry_global_handler,
.global_remove = registry_global_remove_handler
};
int main(void)
{
struct wl_display *display = wl_display_connect(NULL);
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, ®istry_listener, NULL);
// wait for the "initial" set of globals to appear
wl_display_roundtrip(display);
struct wl_surface *surface = wl_compositor_create_surface(compositor);
struct wl_shell_surface *shell_surface = wl_shell_get_shell_surface(shell, surface);
wl_shell_surface_set_toplevel(shell_surface);
int width = 200;
int height = 200;
int stride = width * 4;
int size = stride * height; // bytes
// open an anonymous file and write some zero bytes to it
int fd = syscall(SYS_memfd_create, "buffer", 0);
ftruncate(fd, size);
// map it to the memory
unsigned char *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// turn it into a shared memory pool
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
// allocate the buffer in that pool
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool,
0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_commit(surface);
while (1) {
wl_display_dispatch(display);
}
}
Now, if you compile and run it as usual:
$ gcc main.c -l wayland-client -o runme
$ ./runme
You'll see a black square pop up on your screen:
It has no window frame, so you have nothing to drag it by, though your Wayland compositor may provide additional ways to manage windows that don't want to be managed, for example, GNOME allows you to drag any window while you hold the Super key. It should otherwise behave like a normal window, for example, it should show up in app switchers such as GNOME Shell Overview and the one invoked by pressing Alt-Tab.
We haven't implemented closing the window either, nor does our program respond to ping events, so your compositor may deem the window unresponsive after some time and offer you to "force quit" (i.e. kill) the process. Alternatively, you can kill the process yourself with Ctrl-C.