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;
}