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