Skip to main content

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}