When a Wayland client sends a request,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.
wayland-server routes it to your application logic through the Dispatch trait. Each Wayland object — called a resource on the server side — has an associated Request enum generated from the protocol XML. Your State struct implements Dispatch<Resource, State> for every resource type it handles, and Display::dispatch_clients() calls the appropriate implementation automatically. This page covers the full lifecycle: receiving requests, sending events back, posting fatal protocol errors, managing child objects, and avoiding reference cycles with Weak<I>.
The Dispatch trait
Dispatch is implemented on the user-data type, not the state. The self receiver is the user-data stored alongside the resource. This makes it possible to have multiple Dispatch implementations for the same interface, differentiated by the user-data type — a key mechanism for building reusable Wayland handler libraries.
The request() method
request() is invoked once per incoming client message. The parameters are:
| Parameter | Type | Description |
|---|---|---|
state | &mut State | Mutable reference to your compositor state |
client | &Client | The client that sent the request |
resource | &I | The resource the request was sent to |
request | I::Request | Enum variant for the specific request |
dhandle | &DisplayHandle | Handle for sending events and creating objects |
data_init | &mut DataInit<'_, State> | Used to initialize any child objects created by this request |
The destroyed() method
destroyed() is called when the resource is destroyed — either because the client explicitly destroyed it or because the client disconnected. The default implementation is a no-op. Use it to clean up any server-side state tied to the resource.
Handling requests: a wl_surface example
If a request creates a child object (indicated by a
New<I> argument in the Request enum), you must call data_init.init() on it before request() returns. Forgetting to do so causes a panic.The Resource trait
Every generated Wayland interface type (e.g.WlSurface, WlCompositor) implements the Resource trait. It provides everything you need to inspect and interact with a protocol object.
Sending events
send_event() returns Err(InvalidId) if the resource is no longer alive. Events placed into the output buffer are not written to the socket immediately — call Display::flush_clients() or DisplayHandle::flush_clients() to push them out.
Posting protocol errors
Protocol errors are fatal: the client’s connection is terminated immediately after the error message is sent.Checking liveness
is_alive() returns false either after the resource has been protocol-destroyed or after the underlying Wayland connection has been closed.
Reading object metadata
Accessing user-data
User-data is the value you passed toDataInit::init() when the resource was created. Access it from any code that holds a reference to the resource:
DataInit: initializing child objects
DataInit appears in both Dispatch::request() and GlobalDispatch::bind(). Its purpose is to assign user-data (and therefore a Dispatch implementation) to a freshly created resource before it becomes visible.
DataInit::init() returns the fully initialized resource, which you can store or immediately send an event on:
DispatchError: BadMessage
DispatchError has a single variant, BadMessage, which is generated when the underlying message received from the client does not match the specification for the object’s interface — for example, a request opcode that does not exist or an argument of the wrong type.
DispatchError yourself. wayland-server catches it during request parsing, logs a warning, and kills the offending client with a protocol error. It surfaces in the type system as the return type of Resource::parse_request(), which is an implementation detail called by the generated code.
Weak<I>: non-owning resource references
Storing aResource handle in another resource’s user-data creates a reference cycle — both objects keep each other alive indefinitely. Weak<I> breaks that cycle by holding a non-owning reference that does not prevent cleanup.
Weak<I> is Clone, PartialEq, Eq, and Hash. Clones share the same underlying identity.
Generic Dispatch implementations (delegation pattern)
A common pattern in libraries like Smithay is to implementDispatch generically over the last type parameter, allowing downstream code to delegate to a shared handler:
Dispatch implementation and require only a trait bound on State, rather than demanding a concrete state type.
Quick-reference
| API | Description |
|---|---|
Dispatch::request() | Handle an incoming client request |
Dispatch::destroyed() | Clean up when a resource is destroyed |
resource.send_event(evt) | Send a protocol event to the client |
resource.post_error(code, msg) | Send a fatal protocol error (disconnects client) |
resource.is_alive() | Check if the resource still exists |
resource.version() | Negotiated interface version |
resource.id() | Unique ObjectId for this resource |
resource.client() | Option<Client> that owns this resource |
resource.data::<U>() | Access typed user-data |
resource.downgrade() | Create a Weak<I> non-owning handle |
data_init.init(new, data) | Initialize a child resource |
data_init.custom_init(new, arc) | Initialize with raw ObjectData |
weak.upgrade() | Attempt to recover a full resource from Weak<I> |