wayland-rs is not a single crate — it is a carefully layered workspace of crates, each with a precisely scoped responsibility. Understanding how those layers fit together helps you choose the right crates for your project, reason about compile-time features, and perform FFI integration confidently. This page walks through every layer from the raw C bindings at the bottom to the typed, ergonomic protocol objects at the top.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/smithay/wayland-rs/llms.txt
Use this file to discover all available pages before exploring further.
Three-layer architecture
Layer 1 — FFI: wayland-sys
wayland-sys is the lowest crate in the stack. It contains raw, unsafe Rust FFI declarations generated from the C headers of:
libwayland-client.solibwayland-server.solibwayland-cursor.solibwayland-egl.so
client, server, cursor, egl), so you only link what you use. The crate is not intended for direct use in application code — its sole purpose is to give wayland-backend’s sys module a well-typed surface to call into.
The optional dlopen feature changes the linking strategy from static linkage (.so baked into the ELF NEEDED entries at link time) to runtime dynamic loading (dlopen(3)). This means the binary starts successfully even when libwayland-*.so is absent, enabling graceful fallback to X11 or other display servers.
Layer 2 — Backend: wayland-backend and wayland-scanner
wayland-backend — the protocol engine
wayland-backend is the heart of the entire workspace. It implements the Wayland wire protocol — object lifecycle, message serialization, file-descriptor passing, and event dispatch — and exposes a stable Rust API that the high-level crates build on. It ships two protocol engines behind a common API surface:
- rs module — pure Rust
- sys module — C bindings
wayland_backend::rs is a complete, dependency-free Rust reimplementation of the Wayland protocol. It is always compiled regardless of Cargo features. The rs backend is the default: if no *_system feature is enabled, the top-level re-exports (wayland_backend::client and wayland_backend::server) resolve to this module.rs carries no native library dependency, binaries built against it are fully self-contained and portable.Transparent backend selection via re-exports
Thewayland_backend::client and wayland_backend::server top-level modules are conditional re-exports that automatically resolve to whichever backend is active:
wayland_backend::client (rather than wayland_backend::rs::client or wayland_backend::sys::client), a library automatically inherits whatever backend the application’s final dependency graph selects. If any crate in the build enables client_system, every crate transparently switches to the sys backend with no code changes.
wayland-scanner — XML → Rust code generation
The Wayland protocol and all its extensions are formally described in XML files. wayland-scanner is a procedural-macro crate that reads those XML files at compile time and generates the corresponding Rust types, trait implementations, and interface metadata.
It provides three macros:
| Macro | Purpose |
|---|---|
generate_interfaces! | Generates low-level wl_interface structs needed by the backend |
generate_client_code! | Generates typed client-side proxy types and event enums |
generate_server_code! | Generates typed server-side resource types and request enums |
generate_client_code! with generate_server_code!. The path argument is relative to the crate root (CARGO_MANIFEST_DIR).
Before writing your own XML bindings, check whether the protocol you need is already available in
wayland-protocols, wayland-protocols-wlr, wayland-protocols-plasma, or wayland-protocols-misc. Those crates use wayland-scanner internally and are kept up to date with the upstream repositories.Layer 3 — High-level: client, server, and protocol crates
These are the crates that applications and compositors interact with directly.wayland-client
wayland-client wraps wayland-backend::client and adds:
- A strongly-typed
ConnectionandEventQueuefor driving the Wayland event loop. Proxytrait implementations for every core Wayland object (wl_surface,wl_seat,wl_output, …).- The
Dispatchtrait, which you implement on your state type to receive events.
system feature on wayland-client propagates client_system to wayland-backend, switching the whole stack to the C-library backend:
wayland-server
wayland-server mirrors wayland-client for the compositor side:
DisplayandListeningSocketfor accepting client connections.Resourcetrait implementations for every core server-side Wayland object.- The
Dispatchtrait for handling incoming requests from clients.
wayland-protocols and the extension crates
wayland-protocols runs wayland-scanner over the entire upstream wayland-protocols repository at build time and exposes the results under a clean module hierarchy. Features control which sets are compiled:
client/server— generate client-side or server-side bindings (at least one is required).staging— include protocols in the staging pipeline.unstable— include not-yet-stabilised protocol drafts.
wayland-cursor and wayland-egl
These two auxiliary crates expose safe Rust APIs for cursor loading and EGL surface creation:
wayland-cursor: a pure-Rust reimplementation oflibwayland-cursorfunctionality. It uses thexcursorcrate to load cursor images from XCursor themes, uploads pixel data intoWlBuffers viawayland-client, and retrieves frame timing for animated cursors. It does not depend onwayland-sysor linklibwayland-cursor.so.wayland-egl: wrapslibwayland-egl.soviawayland-sysand exposesWlEglSurface, which creates an EGL window surface from awl_surfaceobject ID for OpenGL rendering.
Crate dependency table
The table below captures the direct dependency relationships across the workspace.| Crate | Depends on |
|---|---|
wayland-sys | (system libraries only — no Rust crate deps) |
wayland-scanner | (proc-macro only — no runtime deps) |
wayland-backend | wayland-sys (optional, via *_system features) |
wayland-client | wayland-backend, wayland-scanner |
wayland-server | wayland-backend, wayland-scanner |
wayland-protocols | wayland-client and/or wayland-server, wayland-scanner |
wayland-protocols-wlr | wayland-client and/or wayland-server, wayland-scanner |
wayland-protocols-plasma | wayland-client and/or wayland-server, wayland-scanner |
wayland-cursor | wayland-client, xcursor |
wayland-egl | wayland-backend, wayland-sys |
Feature propagation in practice
Because Cargo unifies features across the entire dependency graph, enabling a single feature in any crate can propagate backend selection throughout the whole build. Here is a concrete example:Application enables system backend
Your application adds
wayland-client = { features = ["system"] } to its Cargo.toml.Feature flag propagates to wayland-backend
wayland-client’s system feature enables wayland-backend/client_system.wayland-backend activates wayland-sys
client_system pulls in wayland-sys with the client feature, which links libwayland-client.so.Re-export switches to sys backend
wayland_backend::client now resolves to wayland_backend::sys::client instead of wayland_backend::rs::client.wayland_backend::client / wayland_backend::server rather than from rs:: or sys:: directly, so that applications retain full control over backend selection.