Every Wayland protocol is defined in an XML file. The standard toolchain converts that XML into C glue code; wayland-rs replaces that step with a set of procedural macros in theDocumentation 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.
wayland-scanner crate that generate idiomatic Rust code at compile time. If the protocol you need is not already covered by wayland-protocols, wayland-protocols-wlr, or wayland-protocols-plasma, you can point these macros at your own XML file and get the same type-safe bindings that the official crates provide.
When to use custom bindings
Usewayland-scanner directly when:
- You are implementing a private or proprietary compositor protocol not available in any published crate.
- You need a protocol that exists upstream but has not yet been packaged (e.g. a very new or experimental spec).
- You are embedding a third-party
.xmlspecification that is not suitable for upstreaming.
wayland-protocols, wayland-protocols-wlr, or wayland-protocols-plasma, prefer those crates — they are kept in sync with upstream and require no build-time XML parsing in your crate.
Adding the dependency
wayland-scanner is a proc-macro crate. Add it alongside wayland-client or wayland-server:
The three proc-macros
wayland-scanner exposes three proc-macros. All three accept a single string literal — the path to the XML file relative to CARGO_MANIFEST_DIR (the directory containing your Cargo.toml).
| Macro | Purpose |
|---|---|
generate_interfaces! | Generates the low-level wl_interface C-compatible structures used internally by the wayland-backend dispatch machinery |
generate_client_code! | Generates client-side Rust types — proxy structs, request methods, event enums, and Dispatch plumbing |
generate_server_code! | Generates server-side Rust types — resource structs, event methods, request enums, and handler traits |
generate_interfaces! directly in user code — it populates the __interfaces inner module that the client and server code macros reference.
Module template
The canonical module layout comes directly from thewayland-scanner documentation. Wrap everything in a module so the generated names do not pollute your crate’s root namespace. The path is resolved at compile time relative to CARGO_MANIFEST_DIR.
Client-side
Server-side
The server-side template is identical exceptclient is replaced with server throughout:
Protocols that depend on other protocols
If your XML file references interfaces from another protocol (e.g.xdg_surface from XDG Shell, or wl_surface from the core protocol), you must import those interfaces into the __interfaces submodule so the generated code can reference them. For core Wayland objects, the use wayland_client::protocol::__interfaces::* line already covers this. For extension protocols from wayland-protocols, import the relevant __interfaces module:
Each XML file must be parsed twice — once by
generate_interfaces! and once by generate_client_code! or generate_server_code!. Both macros resolve the path relative to CARGO_MANIFEST_DIR at compile time. Rustc caches the result, so there is no runtime overhead.Understanding the __interfaces module
The __interfaces submodule is an implementation detail of the wayland-backend wire protocol layer. It contains wl_interface descriptors — C-compatible static structures that encode each interface’s name, version, and the argument types of all its requests and events. These descriptors are used by wayland-backend to validate messages at the wire level.
You interact with these descriptors only indirectly:
generate_interfaces!populates__interfaceswith descriptors for the interfaces in your XML file.generate_client_code!/generate_server_code!reference those descriptors when constructing proxy or resource objects.- The
use self::__interfaces::*glob import makes the descriptors visible to the generated code within the same module.
xdg_surface), you import that interface’s descriptor from the corresponding external __interfaces module so the generated code can resolve cross-protocol argument types.
Complete worked example
Suppose you have a custom compositor protocol inprotocols/my-bar-protocol.xml that defines a my_bar_manager_v1 global. Here is the full setup:
Mirroring the wayland-protocols crate pattern
Thewayland-protocols crate internally uses a wayland_protocol! macro that wraps both client and server generation behind #[cfg(feature = "client")] and #[cfg(feature = "server")] gates. You can replicate this pattern in your own crate to ship a clean protocol library: