Skip to content

Instantly share code, notes, and snippets.

@sardemff7
Last active July 5, 2019 08:57
Show Gist options
  • Save sardemff7/92700069ef8ec36fc8f801b68568a7d9 to your computer and use it in GitHub Desktop.
Save sardemff7/92700069ef8ec36fc8f801b68568a7d9 to your computer and use it in GitHub Desktop.
Wayland tiny examples

About naming: in specification and code, I will use the z<name>_v<unstable-version> unstable naming convention, while I will just use <name> in explanations.

First, our protocol:

<?xml version="1.0" encoding="UTF-8"?>
<protocol name="rainbow">
    <copyright>
    </copyright>

    <interface name="zex_rainbow_v1" version="1">
	<description summary="singleton for colour enjoying">
	    The object is a singleton global.

	    It will let you know which rainbow colour matches your
	    RGB values.
	</description>

	<request name="destroy" type="destructor" />

	<enum name="error">
	    <description summary="ww_background error values">
		These errors can be emitted in response to ex_rainbow requests.
	    </description>
	    <entry name="out_of_bounds" value="0" summary="RGB values are out of bounds"/>
	</enum>

	<request name="find_colour">
	    <description summary="queries a rainbow colour">
		This queries the rainbow colour for the provided RGB values.

		The values must be between 0 and 255 or a protocol error (out-of-bounds) is raised.
	    </description>
	    <arg name="id" type="new_id" interface="zex_rainbow_colour_v1" summary="the corresponding colour"/>
	    <arg name="red" type="uint" summary="the 0-255 red value" />
	    <arg name="green" type="uint" summary="the 0-255 green value" />
	    <arg name="blue" type="uint" summary="the 0-255 blue value" />
	</request>
    </interface>

    <interface name="zex_rainbow_colour_v1" version="1">
	<description summary="a colour of the rainbow">
	    An ex_rainbow_colour represents the rainbow colour for specified RGB values.
	</description>

	<request name="destroy" type="destructor" />

	<event name="name">
	    <description summary="gives the colour name">
		If the name is null, that means the rainbow has no such colour.
	    </description>
	    <arg name="name" type="string" allow-null="true" summary="the colour name" />
	</event>
    </interface>
</protocol>

We have two types of interfaces here: one global interface ex_rainbow, and one non-global interface ex_rainbow_colour. We can see that we “create” a ex_rainbow_colour object from a request in ex_rainbow, thus ex_rainbow is what we call a “factory”. Except for a few legacy exceptions, we want to stick to the “single factory” principle, so an ex_rainbow_colour will always come from ex_rainbow.

Now let’s implement the global:

#include <wayland-server.h>
#include "rainbow-unstable-v1-server-protocol.h"

static void
ex_rainbow_request_destroy(struct wl_client *client, struct wl_resource *resource)
{
        wl_resource_destroy(resource);
}

static const struct zex_rainbow_colour_v1_interface ex_rainbow_colour_implementation = {
        .destroy = ex_rainbow_request_destroy, /* You can safely re-use your destroy request handler */
};

static void
ex_rainbow_find_colour(struct wl_client *client, struct wl_resource *resource, uint32_t id, uint32_t red, uint32_t green, uint32_t blue)
{
        struct wl_resource *colour_resource;
        char *name;

        /*
         * Here, "id" is the resource ID the client created for this resource.
         * Remember that in Wayland, there is no “return value” for requests, thus
         * creating an object can never fail.
         * Raising a protocol error means disconnecting the client, it is reserved for
         * bad behaving clients (e.g. wrong argument values) or exceptionnal cases (e.g. out of memory).
         */

        if ( red > 255 || green > 255 || blue > 255 )
        {
                wl_resource_post_error(resource, ZEX_RAINBOW_V1_ERROR_OUT_OF_BOUNDS, "RGB values must be between 0 and 255");
                return;
        }

        colour_resource = wl_resource_create(client, &zex_rainbow_colour_v1, wl_resource_get_version(resource), id);
        if ( colour_resource == NULL )
        {
                wl_client_post_no_memory(client);
                return;
        }

        name = get_rainbow_name(reg, green, blue);
        zex_rainbow_colour_v1_send_name(colour_resource, name);
        free(name);
        
        /* You can also pass NULL to the destructor if you have no memory to clean */
        wl_resource_set_implementation(colour_resource, &ex_rainbow_colour_implementation, NULL, NULL);
}

static const struct zex_rainbow_v1_interface ex_rainbow_implementation = {
        .destroy = ex_rainbow_request_destroy,
        .find_colour = ex_rainbow_find_colour,
};

static void
ex_rainbow_unbind(struct wl_resource *resource)
{
        /* We have no memory to clean (we passed NULL to user_data) */
}

static void
ex_rainbow_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
        struct wl_resource *resource;

        resource = wl_resource_create(client, &zex_rainbow_v1_interface, version, id);
        wl_resource_set_implementation(resource, &ex_rainbow_implementation, NULL, ex_rainbow_unbind);
}

int
main()
{
        /* Do stuff, get your wl_display */
        struct wl_display *display = get_display();

        
        if ( wl_global_create(display, &zex_rainbow_v1_interface, 1, NULL, ex_rainbow_bind) == NULL )
                return 1;

        /* Put your main loop here */
        
        return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment