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.
Dispatch trait is the backbone of event processing in wayland-client. Every Wayland object your client manages—registry, compositor, surface, keyboard, shell—sends events back from the compositor. Dispatch is how you tell the library what to do when each of those events arrives. This page explains the trait’s full signature, the role of user data, the helper types for ignoring events, and patterns for structuring Dispatch across a real application.
Trait signature
| Parameter | Role |
|---|---|
I: Proxy | The Wayland interface whose events this implementation handles. |
State | Your top-level application state struct. |
Dispatch<I, State> is implemented on the user-data type (Self = user-data, not State). The event() method receives &self (the user data value attached to the object) and &mut State (the shared application state). This lets different instances of the same interface be dispatched differently based on the user data type attached to each object at creation time.
The event() method parameters
| Parameter | Type | Description |
|---|---|---|
state | &mut State | Mutable reference to your app state—safe to modify freely. |
proxy | &I | The proxy that received this event. Useful for calling methods on the object in response. |
event | I::Event | The strongly-typed event enum. Match on it to handle specific events. |
conn | &Connection | The connection, in case you need to create objects outside an event queue. |
qhandle | &QueueHandle<State> | The queue handle for this dispatch invocation. Use it to create child objects assigned to the same queue. |
User data: differentiating object instances
Every Wayland object carries a user-data value whose type is the second type parameter of itsDispatch implementation. You supply this value when you create the object:
wayland-client looks up the user data, downcasts it to the expected type, and calls Dispatch::event() on it. Two surfaces with different user-data types will call different Dispatch implementations even though they are the same interface.
Simple case: () as user data
When you have only one kind of object and no per-object state is needed, implement Dispatch on AppState with () as the user-data type parameter:
Storing per-object state in user data
For objects where each instance needs its own data—for example tracking surface dimensions—use a custom user-data struct. ImplementDispatch<WlSurface, SurfaceData> on AppState, where SurfaceData is the user-data type:
User data is stored behind an
Arc<dyn Any + Send + Sync> inside QueueProxyData, so it must be Send + Sync + 'static. If you need to mutate per-object state in response to events, wrap it in a Mutex or Cell, or store it in the main State struct indexed by object ID.Storing per-object state in the main state struct
An alternative to user data is to store a simple identifier in the user data and look up the real state inState:
Noop and NoopIgnore
Two built-in implementations save you from writing boilerplate for objects whose events you don’t care about.
Noop — asserts events never arrive
Noop implements Dispatch for every interface and panics if any event is ever delivered. Use it for objects that should not produce events in your use-case, to catch unexpected compositor behaviour during development:
NoopIgnore — silently discards all events
NoopIgnore also implements Dispatch for every interface but does nothing when events arrive. Use it for objects whose events you genuinely want to discard:
QueueProxyData — how object data is stored
Under the hood, QueueHandle::make_data() creates a QueueProxyData<I, U, State> which implements wayland-backend’s ObjectData trait:
QueueProxyData::event()checks if the message contains aNewIdargument (meaning the event creates a child object). If so, it callsU::event_created_child()to allocateObjectDatafor the new object.- It pushes the raw message into the
EventQueue’s internalVecDeque. - When
dispatch_pending()orblocking_dispatch()drains the queue,queue_callbackparses the message and callsU::event()(yourDispatchimplementation).
Proxy::data::<U>():
Implementing Dispatch for multiple objects
Real applications implement Dispatch for many interface types. The simple_window example from the repository demonstrates this pattern clearly—a single GlobalData user-data type dispatches for the registry, the XDG shell, surfaces, and keyboard:
Generic Dispatch implementations for libraries
If you are writing a library or toolkit (like Smithay’s Client Toolkit) that provides reusable Wayland handling, make your Dispatch implementation generic over the downstream State:
State must itself implement Dispatch<WlRegistry, MyUserData>. This creates a delegation chain: the app state delegates handling of this particular (interface, user-data) combination to your library’s implementation.
event_created_child for events that produce objects
A handful of Wayland events create new child objects as part of the event itself (in the core protocol, wl_data_device.data_offer is the canonical example). In these cases you must override event_created_child to provide the ObjectData for the newly created object. The event_created_child! macro makes this straightforward:
event_created_child method that matches on the event opcode and returns the correct QueueProxyData for the child interface.
Common patterns summary
Unit user data `()`
Use when you have one instance of an interface and no per-object metadata. Minimal boilerplate.
Custom struct user data
Use when each object instance carries its own configuration or state that does not change after creation.
State-indexed by object ID
Use when per-object state must be mutable. Store a
HashMap<ObjectId, Data> in your State and look up by proxy.id().Generic delegation
Use when writing reusable library code. Make
Dispatch generic over State and add trait bounds for the parts of State your library needs.