wayland_server/dispatch.rs
1use std::sync::Arc;
2
3use wayland_backend::{
4 protocol::ProtocolError,
5 server::{ClientId, DisconnectReason, ObjectData, ObjectId},
6};
7
8use crate::{Client, DisplayHandle, Resource};
9
10/// A trait which provides an implementation for handling a client's requests from a resource with some type
11/// of associated user data.
12///
13/// ## General usage
14///
15/// You need to implement this trait on your `State` for every type of Wayland object that will be processed
16/// by the [`Display`][crate::Display] working with your `State`.
17///
18/// You can have different implementations of the trait for the same interface but different `UserData` type,
19/// this way the events for a given object will be processed by the adequate implementation depending on
20/// which `UserData` was assigned to it at creation.
21///
22/// The way this trait works is that the [`Dispatch::request()`] method will be invoked by the
23/// [`Display`][crate::Display] for every request received by an object. Your implementation can then match
24/// on the associated [`Resource::Request`] enum and do any processing needed with that event.
25///
26/// If the request being processed created a new object, you'll receive it as a [`New<I>`]. When that is the
27/// case, you *must* initialize it using the [`DataInit`] argument. **Failing to do so will cause a **panic**.
28///
29/// ## Modularity
30///
31/// To provide generic handlers for downstream usage, it is possible to make an implementation of the trait
32/// that is generic over the last type argument, as illustrated below.
33///
34/// As a result, when your implementation is instanciated, the last type parameter `State` will be the state
35/// struct of the app using your generic implementation. You can put additional trait constraints on it to
36/// specify an interface between your module and downstream code, as illustrated in this example:
37///
38/// ```
39/// use wayland_server::{protocol::wl_output, Dispatch};
40///
41/// /// The type we want to delegate to
42/// struct DelegateToMe;
43///
44/// /// The user data relevant for your implementation.
45/// /// When providing delegate implementation, it is recommended to use your own type here, even if it is
46/// /// just a unit struct: using () would cause a risk of clashing with an other such implementation.
47/// struct MyUserData;
48///
49/// // Now a generic implementation of Dispatch, we are generic over the last type argument instead of using
50/// // the default State=Self.
51/// impl<State> Dispatch<wl_output::WlOutput, State> for MyUserData
52/// where
53/// // State is the type which has delegated to this type, so it needs to have an impl of Dispatch itself
54/// MyUserData: Dispatch<wl_output::WlOutput, State>,
55/// // If your delegate type has some internal state, it'll need to access it, and you can
56/// // require it by adding custom trait bounds.
57/// // In this example, we just require an AsMut implementation
58/// State: AsMut<DelegateToMe>,
59/// {
60/// fn request(
61/// &self,
62/// state: &mut State,
63/// _client: &wayland_server::Client,
64/// _resource: &wl_output::WlOutput,
65/// _request: wl_output::Request,
66/// _dhandle: &wayland_server::DisplayHandle,
67/// _data_init: &mut wayland_server::DataInit<'_, State>,
68/// ) {
69/// // Here the delegate may handle incoming requests as it pleases.
70///
71/// // For example, it retrives its state and does some processing with it
72/// let me: &mut DelegateToMe = state.as_mut();
73/// // do something with `me` ...
74/// # std::mem::drop(me) // use `me` to avoid a warning
75/// }
76/// }
77/// ```
78///
79/// **Note:** Due to limitations in Rust's trait resolution algorithm, a type providing a generic
80/// implementation of [`Dispatch`] cannot be used directly as the dispatching state, as rustc
81/// currently fails to understand that it also provides `Dispatch<I, U, Self>` (assuming all other
82/// trait bounds are respected as well).
83pub trait Dispatch<I: Resource, State> {
84 /// Called when a request from a client is processed.
85 ///
86 /// The implementation of this function will vary depending on what protocol is being implemented. Typically
87 /// the server may respond to clients by sending events to the resource, or some other resource stored in
88 /// the user data.
89 fn request(
90 &self,
91 state: &mut State,
92 client: &Client,
93 resource: &I,
94 request: I::Request,
95 dhandle: &DisplayHandle,
96 data_init: &mut DataInit<'_, State>,
97 );
98
99 /// Called when the object this user data is associated with has been destroyed.
100 ///
101 /// Note this type only provides an immutable reference to the user data, you will need to use
102 /// interior mutability to change it.
103 ///
104 /// Typically a [`Mutex`][std::sync::Mutex] would be used to have interior mutability.
105 ///
106 /// You are given the [`ObjectId`] and [`ClientId`] associated with the destroyed object for cleanup
107 /// convenience.
108 ///
109 /// By default this method does nothing.
110 fn destroyed(
111 &self,
112 _state: &mut State,
113 _client: &wayland_backend::server::ClientId,
114 _resource: &I,
115 ) {
116 }
117}
118
119/// The [`ObjectData`] implementation that is internally used by this crate
120#[derive(Debug)]
121pub struct ResourceData<I, U> {
122 marker: std::marker::PhantomData<fn(I)>,
123 /// The user-data associated with this object
124 pub udata: U,
125}
126
127/// A newly created object that needs to be initialized. See [`DataInit`].
128#[derive(Debug)]
129#[must_use = "The protocol object must be initialized using DataInit"]
130pub struct New<I> {
131 id: I,
132}
133
134impl<I> New<I> {
135 #[doc(hidden)]
136 // This is only to be used by code generated by wayland-scanner
137 pub fn wrap(id: I) -> New<I> {
138 New { id }
139 }
140}
141
142/// Helper to initialize client-created objects
143///
144/// This helper is provided to you in your [`Dispatch`] and [`GlobalDispatch`][super::GlobalDispatch] to
145/// initialize objects created by the client, by assigning them their user-data (or [`ObjectData`] if you
146/// need to go this lower-level route).
147///
148/// This step is mandatory, and **failing to initialize a newly created object will cause a panic**.
149#[derive(Debug)]
150pub struct DataInit<'a, D: 'static> {
151 pub(crate) store: &'a mut Option<Arc<dyn ObjectData<D>>>,
152 pub(crate) error: &'a mut Option<(u32, String)>,
153}
154
155impl<D> DataInit<'_, D> {
156 /// Initialize an object by assigning it its user-data
157 pub fn init<I: Resource + 'static, U>(&mut self, resource: New<I>, data: U) -> I
158 where
159 U: Dispatch<I, D> + Send + Sync + 'static,
160 {
161 let arc = Arc::new(ResourceData::<I, _>::new(data));
162 *self.store = Some(arc.clone());
163 let mut obj = resource.id;
164 obj.__set_object_data(arc);
165 obj
166 }
167
168 /// Set a custom [`ObjectData`] for this object
169 ///
170 /// This object data is not managed by `wayland-server`, as a result you will not
171 /// be able to retreive it through [`Resource::data()`].
172 /// Instead, you'll need to retrieve it using [`Resource::object_data()`] and
173 /// handle the downcasting yourself.
174 pub fn custom_init<I: Resource + 'static>(
175 &mut self,
176 resource: New<I>,
177 data: Arc<dyn ObjectData<D>>,
178 ) -> I {
179 *self.store = Some(data.clone());
180 let mut obj = resource.id;
181 obj.__set_object_data(data);
182 obj
183 }
184
185 /// Post an error on an uninitialized object.
186 ///
187 /// This is only meant to be used in [`GlobalDispatch`][crate::GlobalDispatch] where a global protocol
188 /// object is instantiated.
189 pub fn post_error<I: Resource + 'static>(
190 &mut self,
191 _resource: New<I>,
192 code: impl Into<u32>,
193 error: impl Into<String>,
194 ) {
195 *self.error = Some((code.into(), error.into()));
196 // This function takes ownership of the New, ensuring the handler never sees an uninitialized
197 // protocol object.
198 // drop(_resource);
199 }
200}
201
202/*
203 * Dispatch delegation helpers.
204 */
205
206impl<I, U> ResourceData<I, U> {
207 pub(crate) fn new(udata: U) -> Self {
208 ResourceData { marker: std::marker::PhantomData, udata }
209 }
210}
211
212impl<I: Resource + 'static, D: 'static, U: Dispatch<I, D> + Send + Sync + 'static> ObjectData<D>
213 for ResourceData<I, U>
214{
215 fn request(
216 self: Arc<Self>,
217 handle: &wayland_backend::server::Handle,
218 data: &mut D,
219 client_id: &wayland_backend::server::ClientId,
220 msg: wayland_backend::protocol::OwnedMessage<wayland_backend::server::ObjectId>,
221 ) -> Option<Arc<dyn ObjectData<D>>> {
222 let dhandle = DisplayHandle::from(handle.clone());
223 let client = match Client::from_id(&dhandle, client_id.clone()) {
224 Ok(v) => v,
225 Err(_) => {
226 crate::log_error!("Receiving a request from a dead client ?!");
227 return None;
228 }
229 };
230
231 let (sender_id, opcode) = (msg.sender_id.protocol_id(), msg.opcode);
232
233 let (resource, request) = match I::parse_request(&dhandle, msg) {
234 Ok(v) => v,
235 Err(e) => {
236 crate::log_warn!("Dispatching error encountered: {e:?}, killing client.");
237 handle.kill_client(
238 client.id(),
239 DisconnectReason::ProtocolError(ProtocolError {
240 code: 1,
241 object_id: 0,
242 object_interface: "wl_display".into(),
243 message: format!(
244 "Malformed request received for id {sender_id} and opcode {opcode}."
245 ),
246 }),
247 );
248 return None;
249 }
250 };
251 let udata = resource.data::<U>().expect("Wrong user_data value for object");
252
253 let mut new_data = None;
254
255 udata.request(
256 data,
257 &client,
258 &resource,
259 request,
260 &dhandle,
261 // The error is None since the creating object posts an error.
262 &mut DataInit { store: &mut new_data, error: &mut None },
263 );
264
265 new_data
266 }
267
268 fn destroyed(
269 self: Arc<Self>,
270 handle: &wayland_backend::server::Handle,
271 data: &mut D,
272 client_id: &ClientId,
273 object_id: &ObjectId,
274 ) {
275 let dhandle = DisplayHandle::from(handle.clone());
276 let mut resource = I::from_id(&dhandle, object_id.clone()).unwrap();
277
278 // Proxy::from_id will return an inert protocol object wrapper inside of ObjectData::destroyed,
279 // therefore manually initialize the data associated with protocol object wrapper.
280 resource.__set_object_data(self.clone());
281
282 self.udata.destroyed(data, client_id, &resource)
283 }
284}