Wayland language bindings guide

Disclaimer:

This guide is written based on a set of language binding support patches that are not yet in libwayland. A patched version of libwayland is available on my libwayland fork on github.

Introduction

I first got into the Wayland project because I had the crazy idea to make a Wayland compositor that ran as an Android app. As I started digging into this project I discovered that Android, in spit of having native code support, was not very friendly to C and that Wayland was not very friendly to Java. After much deliberation, I decided that the best place to tie the Java and C together was at the libwayland level and I set out to write Java bindings for Wayland. I am writing this guide in the hopes of helping other developers who wish to write language bindings for libwayland or who simply want to know why I submitted those patches to the project.

Why Bind to libwayland?

One of the questions that constantly comes up on IRC is, “Why bother binding to libwayland? Can’t you just implement the wire protocol yourself?” Yes, technically Wayland is a protocol and, as long as you implement the wire protocol correctly, you can implement it all in your language of choice. However, this is a bad idea for a number of reasons:

  1. Many languages such as Java don’t have full support for UNIX domain sockets. Even if you use a library that provides support for UNIX domain sockets like junixsocket, it will likely not have support for sending and receiving file descriptors via the sendmsg system call.

  2. As libraries get developed around Wayland, most of them will require users to pass in actual pointers to libwayland objects. You can’t do that if you’re not using libwayland

  3. As a more specific version of the above point, EGL Wayland support requires libwayland on both the client and compositor sides.

So, yes, if you’re ok with only having SHM available for passing buffers and never using any libraries, you can bang the wire protocol yourself. However, if you want any of these nicer features, you have to bind to libwayland.

What You Actually Have to Bind

When you start looking at libwayland, binding it can look like a massive project. Fortunately, writing language bindings is not as difficult as it seems at first. For each side (compositor or client), there are less than half a dozen core objects that need to be wrapped. The rest is done by writing a program to parse a protocol XML file and dump out thin wrapper code for each of the protocol interfaces.

Server Side

On the server side, you have to bind the following:

While this looks like a lot, the last two are more-or-less opaque types that simply get passed into other things.

Client Side

On the client side, you have to bind the following:

It is worth noting here that server-side wl_display is different from client-side wl_display and they will need separate bindings.

Auto-generated Code

In the case of my Java bindings, I wrote an ant plugin that reads the XML file and produces a set of classes, one for each interface, that have nothing but static methods and a couple of static variables. Each class has (rather, will have when I’m finished with it) the following:

Exactly what form you make the auto-generated protocol code take is up to you. Within the context of Java, this seemed to make the most sense to me. If binding to a different language, I might do it differently. Regardless of the language, however, it will still need those 3 basic components.

Event/Request Dispatching

Probably the hardest thing to get right when binding to libwayland is event and request dispatching.

Events and Requests in C libwayland

First, it helps to know how it is done for C in libwayland. The core of wayland’s event and resource dispatching system is the following three structures defined in wayland-util.h:

struct wl_message {
    const char *name;
    const char *signature;
    const struct wl_interface **types;
};

struct wl_interface {
    const char *name;
    int version;
    int method_count;
    const struct wl_message *methods;
    int event_count;
    const struct wl_message *events;
};

struct wl_object {
    const struct wl_interface *interface;
    const void *implementation;
    uint32_t id;
};

The wl_message and wl_interface structures describe, in a binary computer-readable way, what is contained in the protocol XML file. The wl_interface structure tells libwayland the name of the interface, the expected version, and what requests (it calls them methods) or events it has. Each request or event is encoded into a wl_message structure which contains a name, a signature (description of its arguments), and an array of types. If one or more of the arguments described in the signature is of the object type, the types array specifies the interface corresponding to that argument.

The signature is simply a string with the event/request arguments encoded as follows:

So how does the whole event/request process work? As an example, let’s say the client calls wl_surface.attach. In XML, the attach request is specified as follows:

<request name="attach">
  <arg name="buffer" type="object" interface="wl_buffer" allow-null="true"/>
  <arg name="x" type="int"/>
  <arg name="y" type="int"/>
</request>

As you can see, the attach request has three arguments: one object and two integers. From this XML, the scanner generates the following wl_message structure that looks something like this:

struct wl_message attach_request = {
    "attach",
    "?oii",
    {&wl_surface_interface, NULL, NULL}
};

The scanner also generates the following inline function:

static inline void
wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer,
                  int32_t x, int32_t y)
{
    wl_proxy_marshal((struct wl_proxy *) wl_surface,
             WL_SURFACE_ATTACH, buffer, x, y);
}

These auto-generated inline functions provide an easy-to-read and typesafe means of calling requests. When a client calls wl_surface_attach with a surface, the following things happen:

  1. The client calls wl_surface_attach

  2. wl_surface_attach calls the variadic function wl_proxy_marshal to make the actual request call.

  3. wl_proxy_marshal converts the request to the wayland wire format and sends it to the server

  4. The server recieves the requests and looks up the wl_resource that is supposed to recieve the request.

  5. The server uses libffi to dynamically call the function pointer provided by the compositor to handle the “attach” request.

While a bit simplistic, that is how requests are handled in C. For events, it is basically the same only with the roles of client and server reversed.

Event and Request Dispatching

The biggest problem with interacting from libwayland in a language other than C is the large number of function pointers it requires. Fore every single request (on the compositor side) or event (on the client side) your program must provide a function pointer. For a language like C++ this isn’t a terrible requirement; you can simply write static wrapper functions for everything pass pointers to them into libwayland. However, even for C++ this makes for a lot of boilerplate code.

How about a dynamic language such as Java or Python? In that case, you have two options. One is that libffi does have the capability to dynamically generate function pointers. However this can be tricky and is not supported on all platforms. The other option is to auto-generate a wrapper function for each possible event/request. Then, not only do you have auto-generated code for the language you’re binding to, you also have auto-generated C code that has to be kept in sync with it.

This is where the concept of dispatchers comes into play. In libwayland, a dispatcher is a special function that takes the place of the call to libffi in the event/request sending and receiving process. A dispatcher is responsible for converting all of the C arguments into the corresponding language’s types and for calling the appropriate function. A dispatcher has the following prototype:

int
resource_dispatcher(const void * data, void *target, uint32_t opcode,
                    const struct wl_message *message,
                    union wl_argument *args);

The data parameter is a piece of dispatcher-specific data to help in calling the appropriate function or method. This piece of data serves a similar function to the implementation only more general. In the case of my Java wrappers, the dispatcher data is an array of Java method id’s. The target parameter specifies is the object (either wl_proxy or wl_resource). The opcode parameter specifies which event/request is being called. The events and requests are zero-indexed and in the order in which they appear in the XML file. The args parameter is an array of arguments packed into a union.

Dispatchers have an integer return type for error handling. On success, dispatchers should return 0. On an error, they should set errno to something reasonable and return a non-zero value. This will cause an immediate exit from the event loop or event queue. If you ever return non-zero from a dispatcher, you must check for errors and do something sensible when the event loop or queue returns.

Event and Request Marshalling

Along with the dispatching code, you will also have to write some of your own marshalling code. On the calling side, the auto-generated C stubs code calls a variadic function wl_proxy_marshal or wl_resource_post_event. When writing language bindings, you simply have to provide your language’s version of a variadic function that performs this same task. In order to accommodate language bindings, newer versions of libwayland provide versions of these functions that take their arguments as an array of the union type wl_argument just like dispatchers receive them. This way all of the argument conversion can be done dynamically and you don’t have to worry about dynamically calling a variadic function.

Memory Management

I will not presume to write a complete guide to memory management for language bindings here. Instead, I will simply describe how I am handling it from the Java side and what facilities are built into libwayland to help with it.

One of the struggles with memory management is that most languages other than C and C++ are garbage collected. In order to make libwayland act the way the programmer expects, we need to have a good concept of ownership built into the way we write our bindings. There are a number of ownership relationships. On the server side, the display owns the clients, the resources, and its own event loop. Also, anything that has a signal associated with it owns the listeners to those signals.

The way I am handling memory management in Java is to store a global reference to a Java object whenever it is “owned” by something inside libwayland. Then, a listener is attached to the destroy signal of the owning object that deletes the global reference when the owning object is destroyed. This way, the garbage collector can clean up Java object. As a quick example, I am using the following structure to correspond to a wl_listener:

struct wl_jni_listener {
    struct wl_listener listener;
    struct wl_listener destroy_listener;
    jobject self_ref;
};

The first of these two listeners is the actual listener connected to the signal. The second listener is connected to the destroy signal of the object containing the signal to which the first is connected. The self_ref field contains a global reference to the Java Listener object associated with it. When the destroy_listener is notified, it removes this reference. A little care must be taken wit this method when connecting to destroy signals. In that case, you must connect listener first and then destroy_listener. This ensures that the listener is not destroyed before it is by the destroy signal.

On the client side, memory management is a lot little easier. This is because every client-side entity must be explicitly destroyed by the client. If the client code does not hang on to the wrapper object and it gets garbage collected, it won’t hurt anything because it never would have been able to call destroy anyway.