Releases: Smithay/wayland-rs
Version 0.24.0
This new version of wayland-rs
brings several changes to the library API, in order to improve general ergonomics in writing Wayland clients and server programs. The main change is the introduction of the Filters API.
Filters instead of Implementations
Until now wayland-rs
had followed the design of the C libwayland in that each Wayland object must be given an implementation, under the form of some kind of callback that is invoked every time this object receives a message (an event client-side or a request server-side).
Right from the start this posed the question of state sharing, as Rust's constraints on this are much stronger than C on this subject. So sharing state between the callbacks of different objects requires using Rc
and RefCell
to wrap the state. But sharing state between objects is actually something very common for Wayland projects, and having to explicitly manage it like that is not ergonomic at all.
This is why this new version discontinues the "one-implementation-per-object" setup and rather introduces the concept of Filter. A Filter is again a wrapper around a callback, however more than one object can be assigned to a given filter, allowing much easier state sharing.
Creating a Filter requires you to provide a closure of type FnMut(E, Filter<E>)
. E
is the event type your Filter processes and it can be used for any object whose messages implement Into<E>
. wayland-server
and wayland-client
provide macros automating the creation of enums and their appropriate From
implementations.
As the second argument, your closure is given an handle to the Filter itself, allowing you to assign newly created object to the same filer from within the closure.
This way, you can assign all objects that need sharing state into the same Filter, removing any need for Rc
or RefCell
everywhere.
Wayland objects thus gain two methods: assign
, which assigns them to a Filter, and assign_mono
, which allows you to just assign a closure to an object, when you don't need to share state.
// Create an enum joining pointer and keyboard events, so that all input events are
// handled by a single filter
event_enum!(
InputEvents |
Pointer => WlPointer,
Keyboard => WlKeyboard,
);
// Create a filter with the input processing logic
let input_filter = Filter::<InputEvents>::new(|event, _| { /* process the input event */ });
// Once created, assign the objects to this filter
keyboard.assign(input_filter.clone());
pointer.assign(input_filter.clone());
Moreover, objects can be assigned to an other filter several times if necessary, as opposed to the implementation that could only be set one time.
Main & Attached handles
Two new kind of proxy handle are introduced client side, Main<I>
and Attached<I>
, splitting the capability of managing filters & event queue into new types.
To change the filter assignation of an object, you need a Main<I>
handle to it. However these handles cannot be send across threads.
To send it somewhere else, you first need to retrieve the I
itself (by dereferencing the Main<I>
and cloning) which is threadsafe, but cannot be used to change the filter assignation.
A bare I
can be used to send requests to the server, but not requests that create new objects. For these, you need to use the Main<I>
or attach the I
to an event queue (via Proxy::attach
). Once this is done, the newly created objects will be managed by this event queue. An Attached<I>
is not threadsafe either, as event queues are not.
Server-side also introduces the Main<I>
wrapper, but not Attached<I>
, as there are no event queues.
User-Data mechanism
The user-data mechanism, which allows you to attach an arbitrary value to a Wayland object and retrieve it from any handle to it, has been redesigned. It now revolves around an UserData
type which acts as an anonymous container.
Its contents can be sent only once, and then accessed back as long as you know the expected type. It also is thread-aware, and will prevent a non-threadsafe payload from being accessed from an other thread than the one that set it.
No more event loop integration
calloop
is no longer a dependency of wayland-rs
, and instead the structures of the library provide basic methods (get_fd()
and dispatch()
) allowing you to proceed with the integration into an other event loop as you prefer.
Feature rename
The native_lib
feature has been renamed into use_system_lib
, to be more explicit about what it does: disable the rust implementation of the protocol and use the system libwayland
instead (which is required if you need any kind of wayland-ffi interaction, such as using OpenGL).
Reducing allocations
The internal representation of messages no longer allocates for messages with less than 4 arguments, which notably covers the quite spammy events that wl_pointer.motion
and wl_touch.motion
are. This drastically reduce the number of allocations done by the library when using the use_system_lib
feature.
Wayland-rs version 0.23.0
This version brings one single major change in the way the cargo feature native_lib
is organized.
This feature now no longer affects the contents of the code generated by wayland-scanner
, which is thus now always compatible with both the C lib implementation and the rust one. As a consequence, the native_lib
cargo feature is now only present on wayland-client
and wayland-server
, and no longer on wayland-protocols
. Meaning that there is not going to be any more issues with synchronizing these features correctly between the crates (not doing so could lead to hard-to-understand build errors).
So now, if your project requires native_lib
, put it on wayland-client
/ wayland-server
as required, and interaction with other projects in your dependency tree (for example if using SCTK) will just work, no question asked.
An other consequence of this refactor is that now the implementations of the protocols can be cross-tested against each other. Meaning that the project's CI now runs rust-based wayland-client
and C-based wayland-client
against both rust-based and C-based wayland-server
.
Wayland-rs version 0.22.0
This release brings yet another large redesign of the wayland-rs, many thanks to @YaLTeR for their help redesigning the API.
The most notable changes are as follow.
Objects have been transformed
The main objects that are manipulated are no longer Proxy<WlFoo>
, but WlFoo
objects directly (with access to the underlying Proxy
via the AsRef
trait and From
/Into
conversions (and similarly server-side with the Resource
s).
Associated with this RequestTrait
s are no longer, being replaced by inherent method on the WlFoo
objects directly, for improved ergonomy, as you don't need to import all those traits any longer. Server-side objects now also have these methods.
Diversification of implementations
It is now possible to implement an object using a closure (as previously) or a struct implementing the associated EventHandler
trait, depending on which is more practical for you.
It is also no longer unsafe to use a non-threadsafe implementation for objects, and it is now the default, as most use-case don't need the thread-safety anyway. It is still possible to opt-in into the safety though, if you need it.
If your workflow is more geared towards processing events in an iterator-like fashion rather than via callbacks, you can now use sinks. These are mpsc queues that can be used to implement any object. All objects implemented with a given sink will feed their event in a MsgIterator
, that implements the Iterator
trait. The BlockingMsgIter
variant will additionally block on the wayland socket waiting for other events to arrive, allowing you to reduce your main event loop to a simple for
loop, if you don't need to handle other sources of events.
Future-proofing the protocols
The enums generated from the protocol definitions are now explicitly nonexhaustive, as adding variants to them (enums, events and requests) is considered semver-compatible in Wayland land. This means that updating the protocol files is no longer a potential breaking change as it used to be.
General robustification
The pure rust implementation of the protocol is now much more strict about its state-keeping. Several issues about race conditions at the protocol level have been identified, fixed, and are now tested against. This process even managed to find a bug in the reference implementation (although a bug that is quite unlikely to trigger in practice).
For more details, you can check the full changelog.