Skip to main content

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}