wl_proxy/
object.rs

1//! Wayland objects.
2
3use {
4    crate::{
5        client::Client,
6        endpoint::Endpoint,
7        handler::{HandlerAccessError, HandlerMut, HandlerRef},
8        protocols::ObjectInterface,
9        state::State,
10    },
11    error_reporter::Report,
12    std::{
13        any::Any,
14        cell::{Cell, RefCell},
15        collections::{VecDeque, hash_map::Entry},
16        fmt::Debug,
17        os::fd::OwnedFd,
18        rc::{Rc, Weak},
19    },
20    thiserror::Error,
21};
22
23#[cfg(test)]
24mod tests;
25
26pub(crate) trait ObjectPrivate: Any {
27    fn new(state: &Rc<State>, version: u32) -> Rc<Self>
28    where
29        Self: Sized;
30    fn delete_id(self: Rc<Self>) -> Result<(), (ObjectError, Rc<dyn Object>)>;
31    fn handle_request(
32        self: Rc<Self>,
33        client: &Rc<Client>,
34        msg: &[u32],
35        fds: &mut VecDeque<Rc<OwnedFd>>,
36    ) -> Result<(), ObjectError>;
37    fn handle_event(
38        self: Rc<Self>,
39        server: &Endpoint,
40        msg: &[u32],
41        fds: &mut VecDeque<Rc<OwnedFd>>,
42    ) -> Result<(), ObjectError>;
43    fn get_request_name(&self, id: u32) -> Option<&'static str>;
44    fn get_event_name(&self, id: u32) -> Option<&'static str>;
45}
46
47/// A wayland object.
48///
49/// Note that [`ObjectCoreApi`] provides additional functions for all `T: Object`.
50#[expect(private_bounds)]
51pub trait Object: Debug + ObjectPrivate {
52    /// Returns the [`ObjectCore`] of this object.
53    fn core(&self) -> &ObjectCore;
54    /// Unsets the handler of this object.
55    ///
56    /// Handlers are unset automatically when the [`State`] is destroyed. Otherwise, if
57    /// a handler creates a reference cycle, the handler has to be unset manually.
58    /// For example, within the handler of a destructor message or when the client
59    /// disconnects.
60    fn unset_handler(&self);
61    /// Returns a shared reference to the handler.
62    fn get_handler_any_ref(&self) -> Result<HandlerRef<'_, dyn Any>, HandlerAccessError>;
63    /// Returns a mutable reference to the handler.
64    fn get_handler_any_mut(&self) -> Result<HandlerMut<'_, dyn Any>, HandlerAccessError>;
65}
66
67/// A concrete (not `dyn`) object.
68pub trait ConcreteObject: Object {
69    /// The interface version from the XML file that the interface was generated from.
70    const XML_VERSION: u32;
71    /// The interface of the object.
72    const INTERFACE: ObjectInterface;
73    /// The interface of the object as a string.
74    const INTERFACE_NAME: &str;
75}
76
77/// The API implemented by [`ObjectCore`].
78pub trait ObjectCoreApi {
79    /// Returns the [`State`] of this object.
80    fn state(&self) -> &Rc<State>;
81
82    /// Returns the [`Client`] associated with this object, if any.
83    fn client(&self) -> Option<Rc<Client>>;
84
85    /// Creates a child of this object.
86    ///
87    /// This is a shorthand for
88    ///
89    /// ```
90    /// # use std::rc::Rc;
91    /// # use wl_proxy::object::{Object, ObjectCore, ObjectCoreApi};
92    /// # trait T { fn f<P: Object>(&self) -> Rc<P>; }
93    /// # impl T for ObjectCore {
94    /// #     fn f<P: Object>(&self) -> Rc<P> {
95    /// self.state().create_object::<P>(self.version())
96    /// #     }
97    /// # }
98    /// ```
99    fn create_child<P>(&self) -> Rc<P>
100    where
101        P: Object;
102
103    /// Returns the [`ObjectInterface`] of this object.
104    fn interface(&self) -> ObjectInterface;
105
106    /// Returns the version of this object.
107    fn version(&self) -> u32;
108
109    /// Returns the unique ID of this object.
110    ///
111    /// This ID is not reused for any other object for the lifetime of the [`State`].
112    fn unique_id(&self) -> u64;
113
114    /// Returns the client ID of this object, if any.
115    fn client_id(&self) -> Option<u32>;
116
117    /// Returns the server ID of this object, if any.
118    fn server_id(&self) -> Option<u32>;
119
120    /// Sends a wl_display.delete_id event for this object.
121    ///
122    /// This is similar to [`ObjectCoreApi::try_delete_id`] but logs a message instead of
123    /// returning an error.
124    fn delete_id(&self);
125
126    /// Tries to send a wl_display.delete_id event for this object.
127    ///
128    /// This should be used when overriding the `delete_id` function in message handlers
129    /// or in destructors when the destructor is not forwarded to the server.
130    fn try_delete_id(&self) -> Result<(), ObjectError>;
131
132    /// Enables or disables automatic forwarding of events to the client.
133    ///
134    /// This affects the default message handlers.
135    fn set_forward_to_client(&self, enabled: bool);
136
137    /// Enables or disables automatic forwarding of requests to the server.
138    ///
139    /// This affects the default message handlers.
140    fn set_forward_to_server(&self, enabled: bool);
141}
142
143impl ObjectCoreApi for ObjectCore {
144    fn state(&self) -> &Rc<State> {
145        &self.state
146    }
147
148    fn client(&self) -> Option<Rc<Client>> {
149        self.client.borrow().clone()
150    }
151
152    fn create_child<P>(&self) -> Rc<P>
153    where
154        P: Object,
155    {
156        self.state.create_object::<P>(self.version)
157    }
158
159    fn interface(&self) -> ObjectInterface {
160        self.interface
161    }
162
163    fn version(&self) -> u32 {
164        self.version
165    }
166
167    fn unique_id(&self) -> u64 {
168        self.id
169    }
170
171    fn client_id(&self) -> Option<u32> {
172        self.client_obj_id.get()
173    }
174
175    fn server_id(&self) -> Option<u32> {
176        self.server_obj_id.get()
177    }
178
179    fn delete_id(&self) {
180        if let Err(e) = self.try_delete_id() {
181            log::warn!("Could not release a client id: {}", Report::new(e));
182        }
183    }
184
185    fn try_delete_id(&self) -> Result<(), ObjectError> {
186        if !self.awaiting_delete_id.replace(false) {
187            if self.client.borrow().is_some() {
188                return Err(ObjectError(ObjectErrorKind::NotAwaitingDeleteId));
189            }
190            return Ok(());
191        }
192        let Some(id) = self.client_obj_id.take() else {
193            return Ok(());
194        };
195        self.client_id.take();
196        let Some(client) = self.client.take() else {
197            return Ok(());
198        };
199        let object = client.endpoint.objects.borrow_mut().remove(&id);
200        drop(object);
201        client.display.try_send_delete_id(id)
202    }
203
204    fn set_forward_to_client(&self, enabled: bool) {
205        self.forward_to_client.set(enabled);
206    }
207
208    fn set_forward_to_server(&self, enabled: bool) {
209        self.forward_to_server.set(enabled);
210    }
211}
212
213impl<T> ObjectCoreApi for T
214where
215    T: Object + ?Sized,
216{
217    fn state(&self) -> &Rc<State> {
218        self.core().state()
219    }
220
221    fn client(&self) -> Option<Rc<Client>> {
222        self.core().client()
223    }
224
225    fn create_child<P>(&self) -> Rc<P>
226    where
227        P: Object,
228    {
229        self.core().create_child()
230    }
231
232    fn interface(&self) -> ObjectInterface {
233        self.core().interface()
234    }
235
236    fn version(&self) -> u32 {
237        self.core().version()
238    }
239
240    fn unique_id(&self) -> u64 {
241        self.core().unique_id()
242    }
243
244    fn client_id(&self) -> Option<u32> {
245        self.core().client_id()
246    }
247
248    fn server_id(&self) -> Option<u32> {
249        self.core().server_id()
250    }
251
252    fn delete_id(&self) {
253        self.core().delete_id()
254    }
255
256    fn try_delete_id(&self) -> Result<(), ObjectError> {
257        self.core().try_delete_id()
258    }
259
260    fn set_forward_to_client(&self, enabled: bool) {
261        self.core().set_forward_to_client(enabled);
262    }
263
264    fn set_forward_to_server(&self, enabled: bool) {
265        self.core().set_forward_to_server(enabled);
266    }
267}
268
269/// Utilities for [`Object`]s.
270pub trait ObjectUtils: Object {
271    /// Tries to get a shared reference to the handler.
272    fn try_get_handler_ref<T>(&self) -> Result<HandlerRef<'_, T>, HandlerAccessError>
273    where
274        T: 'static,
275    {
276        let handler = self.get_handler_any_ref()?;
277        handler
278            .downcast_ref::<T>()
279            .ok_or(HandlerAccessError::InvalidType)?;
280        // SAFETY: We've just verified that `h` has type `T`.
281        Ok(HandlerRef::map(handler, |h| unsafe {
282            &*(h as *const dyn Any as *const T)
283        }))
284    }
285
286    /// Gets a shared reference to the handler.
287    ///
288    /// This function panics if a [`HandlerAccessError`] occurs.
289    fn get_handler_ref<T>(&self) -> HandlerRef<'_, T>
290    where
291        T: 'static,
292    {
293        self.try_get_handler_ref().map_err(Report::new).unwrap()
294    }
295
296    /// Tries to get a mutable reference to the handler.
297    fn try_get_handler_mut<T>(&self) -> Result<HandlerMut<'_, T>, HandlerAccessError>
298    where
299        T: 'static,
300    {
301        let mut handler = self.get_handler_any_mut()?;
302        handler
303            .downcast_mut::<T>()
304            .ok_or(HandlerAccessError::InvalidType)?;
305        // SAFETY: We've just verified that `h` has type `T`.
306        Ok(HandlerMut::map(handler, |h| unsafe {
307            &mut *(h as *mut dyn Any as *mut T)
308        }))
309    }
310
311    /// Gets a mutable reference to the handler.
312    ///
313    /// This function panics if a [`HandlerAccessError`] occurs.
314    fn get_handler_mut<T>(&self) -> HandlerMut<'_, T>
315    where
316        T: 'static,
317    {
318        self.try_get_handler_mut().map_err(Report::new).unwrap()
319    }
320}
321
322impl<T> ObjectUtils for T where T: Object + ?Sized {}
323
324/// Utilities for `Rc<dyn Object>`.
325pub trait ObjectRcUtils {
326    /// Tries to downcast the object to a [`ConcreteObject`].
327    fn try_downcast<T>(&self) -> Option<Rc<T>>
328    where
329        T: ConcreteObject;
330
331    /// Downcasts the object to a [`ConcreteObject`].
332    ///
333    /// This function panics if the object has a different interface.
334    fn downcast<T>(&self) -> Rc<T>
335    where
336        T: ConcreteObject;
337}
338
339impl ObjectRcUtils for Rc<dyn Object> {
340    fn try_downcast<T>(&self) -> Option<Rc<T>>
341    where
342        T: ConcreteObject,
343    {
344        (self.clone() as Rc<dyn Any>).downcast().ok()
345    }
346
347    fn downcast<T>(&self) -> Rc<T>
348    where
349        T: ConcreteObject,
350    {
351        let Some(t) = self.try_downcast() else {
352            panic!(
353                "Tried to downcast {} to {}",
354                self.interface().name(),
355                T::INTERFACE_NAME,
356            );
357        };
358        t
359    }
360}
361
362/// Core data structure shared by all objects.
363///
364/// This can be accessed via [`Object::core`].
365pub struct ObjectCore {
366    pub(crate) state: Rc<State>,
367    id: u64,
368    pub(crate) interface: ObjectInterface,
369    pub(crate) version: u32,
370    pub(crate) forward_to_client: Cell<bool>,
371    pub(crate) forward_to_server: Cell<bool>,
372    pub(crate) awaiting_delete_id: Cell<bool>,
373    pub(crate) server_obj_id: Cell<Option<u32>>,
374    pub(crate) client_obj_id: Cell<Option<u32>>,
375    pub(crate) client_id: Cell<Option<u64>>,
376    pub(crate) client: RefCell<Option<Rc<Client>>>,
377}
378
379#[derive(Debug, Error)]
380pub(crate) enum IdError {
381    #[error("the state is already destroyed")]
382    StateDestroyed,
383    #[error("the client is already destroyed")]
384    ClientDestroyed,
385    #[error("object already has the server id {0}")]
386    HasServerId(u32),
387    #[error("the state does not have a server")]
388    NoServer,
389    #[error("there are no server ids available")]
390    NoServerSpace,
391    #[error("the id {0} is too small to be a server id")]
392    NotServerId(u32),
393    #[error("the server id {0} is already in use")]
394    ServerIdInUse(u32),
395    #[error("object already has the client id {0}")]
396    HasClientId(u32),
397    #[error("there are no client ids available")]
398    NoClientSpace,
399    #[error("the id {0} is too large to be a client id")]
400    NotClientId(u32),
401    #[error("the client id {0} is already in use")]
402    ClientIdInUse(u32),
403}
404
405const MIN_SERVER_ID: u32 = 0xff000000;
406
407impl ObjectCore {
408    pub(crate) fn new(
409        state: &Rc<State>,
410        slf: Weak<dyn Object>,
411        interface: ObjectInterface,
412        version: u32,
413    ) -> Self {
414        let object_id = state.next_object_id.get();
415        state.next_object_id.set(object_id + 1);
416        state.all_objects.borrow_mut().insert(object_id, slf);
417        Self {
418            state: state.clone(),
419            id: object_id,
420            interface,
421            version,
422            forward_to_client: Cell::new(state.forward_to_client.get()),
423            forward_to_server: Cell::new(state.forward_to_server.get()),
424            awaiting_delete_id: Default::default(),
425            server_obj_id: Default::default(),
426            client_obj_id: Default::default(),
427            client_id: Default::default(),
428            client: Default::default(),
429        }
430    }
431
432    fn check_server_destroyed(&self) -> Result<(), IdError> {
433        if self.state.destroyed.get() {
434            return Err(IdError::StateDestroyed);
435        }
436        Ok(())
437    }
438
439    pub(crate) fn generate_server_id(&self, slf: Rc<dyn Object>) -> Result<(), IdError> {
440        self.check_server_destroyed()?;
441        if let Some(id) = self.server_obj_id.get() {
442            return Err(IdError::HasServerId(id));
443        }
444        let Some(server) = &self.state.server else {
445            return Err(IdError::NoServer);
446        };
447        let id = server.idl.acquire();
448        if id >= MIN_SERVER_ID {
449            server.idl.release(id);
450            return Err(IdError::NoServerSpace);
451        }
452        self.server_obj_id.set(Some(id));
453        server.objects.borrow_mut().insert(id, slf);
454        Ok(())
455    }
456
457    pub(crate) fn set_server_id(&self, id: u32, slf: Rc<dyn Object>) -> Result<(), IdError> {
458        if id < MIN_SERVER_ID {
459            return Err(IdError::NotServerId(id));
460        }
461        self.set_server_id_unchecked(id, slf)
462    }
463
464    pub(crate) fn set_server_id_unchecked(
465        &self,
466        id: u32,
467        slf: Rc<dyn Object>,
468    ) -> Result<(), IdError> {
469        self.check_server_destroyed()?;
470        let Some(server) = &self.state.server else {
471            return Err(IdError::NoServer);
472        };
473        let objects = &mut *server.objects.borrow_mut();
474        let Entry::Vacant(entry) = objects.entry(id) else {
475            return Err(IdError::ServerIdInUse(id));
476        };
477        entry.insert(slf);
478        self.server_obj_id.set(Some(id));
479        Ok(())
480    }
481
482    fn check_client_destroyed(&self, client: &Client) -> Result<(), IdError> {
483        if client.destroyed.get() {
484            return Err(IdError::ClientDestroyed);
485        }
486        Ok(())
487    }
488
489    pub(crate) fn generate_client_id(
490        &self,
491        client: &Rc<Client>,
492        slf: Rc<dyn Object>,
493    ) -> Result<(), IdError> {
494        self.check_client_destroyed(client)?;
495        if let Some(id) = self.client_obj_id.get() {
496            return Err(IdError::HasClientId(id));
497        }
498        let id = client.endpoint.idl.acquire();
499        let Some(id) = MIN_SERVER_ID.checked_add(id) else {
500            client.endpoint.idl.release(id);
501            return Err(IdError::NoClientSpace);
502        };
503        client.endpoint.objects.borrow_mut().insert(id, slf);
504        self.set_client_id_(client, id);
505        Ok(())
506    }
507
508    pub(crate) fn set_client_id(
509        &self,
510        client: &Rc<Client>,
511        id: u32,
512        slf: Rc<dyn Object>,
513    ) -> Result<(), IdError> {
514        self.check_client_destroyed(client)?;
515        if id >= MIN_SERVER_ID {
516            return Err(IdError::NotClientId(id));
517        }
518        let objects = &mut *client.endpoint.objects.borrow_mut();
519        let Entry::Vacant(entry) = objects.entry(id) else {
520            return Err(IdError::ClientIdInUse(id));
521        };
522        entry.insert(slf);
523        self.set_client_id_(client, id);
524        Ok(())
525    }
526
527    fn set_client_id_(&self, client: &Rc<Client>, id: u32) {
528        self.client_obj_id.set(Some(id));
529        self.client_id.set(Some(client.endpoint.id));
530        *self.client.borrow_mut() = Some(client.clone());
531    }
532
533    pub(crate) fn handle_client_destroy(&self) {
534        let id = self.client_obj_id.get().unwrap();
535        if let Some(idl) = id.checked_sub(MIN_SERVER_ID) {
536            self.client_obj_id.take();
537            self.client_id.take();
538            let client = self.client.take().unwrap();
539            let object = client.endpoint.objects.borrow_mut().remove(&id);
540            drop(object);
541            client.endpoint.idl.release(idl);
542        } else {
543            self.awaiting_delete_id.set(true);
544        }
545    }
546
547    pub(crate) fn handle_server_destroy(&self) {
548        let id = self.server_obj_id.get().unwrap();
549        if id < MIN_SERVER_ID {
550            return;
551        }
552        self.server_obj_id.take();
553        let _object = self
554            .state
555            .server
556            .as_ref()
557            .unwrap()
558            .objects
559            .borrow_mut()
560            .remove(&id);
561    }
562}
563
564impl Drop for ObjectCore {
565    fn drop(&mut self) {
566        self.state.all_objects.borrow_mut().remove(&self.id);
567    }
568}
569
570/// An error emitted by an [`Object`].
571#[derive(Debug, Error)]
572#[error(transparent)]
573pub struct ObjectError(#[from] pub(crate) ObjectErrorKind);
574
575#[derive(Debug, Error)]
576pub(crate) enum ObjectErrorKind {
577    #[error("could not generate a client id for argument {0}")]
578    GenerateClientId(&'static str, #[source] IdError),
579    #[error("could not generate a server id for argument {0}")]
580    GenerateServerId(&'static str, #[source] IdError),
581    #[error("could not assign client id {0} to argument {1}")]
582    SetClientId(u32, &'static str, #[source] IdError),
583    #[error("could not assign server id {0} to argument {1}")]
584    SetServerId(u32, &'static str, #[source] IdError),
585    #[error("client {0} has no object with id {1}")]
586    NoClientObject(u64, u32),
587    #[error("server has no object with id {0}")]
588    NoServerObject(u32),
589    #[error("argument {} has type {} but should have type {}", .0, .1.name(), .2.name())]
590    WrongObjectType(&'static str, ObjectInterface, ObjectInterface),
591    #[error("the requested version {} for interface {} is larger than the max version {}", .1, .0.name(), .0.xml_version())]
592    MaxVersion(ObjectInterface, u32),
593    #[error("the interface {0} is not supported")]
594    UnsupportedInterface(String),
595    #[error("the receiver has no server id")]
596    ReceiverNoServerId,
597    #[error("the receiver has no client")]
598    ReceiverNoClient,
599    #[error("the argument {0} is not associated with client {1}")]
600    ArgNoClientId(&'static str, u64),
601    #[error("the argument {0} has no server id")]
602    ArgNoServerId(&'static str),
603    #[error("the size of the message is {0} instead of {0}")]
604    WrongMessageSize(u32, u32),
605    #[error("unknown message id {0}")]
606    UnknownMessageId(u32),
607    #[error("the file descriptor for argument {0} is missing")]
608    MissingFd(&'static str),
609    #[error("there are trailing bytes after the message")]
610    TrailingBytes,
611    #[error("argument {0} is not present in the message")]
612    MissingArgument(&'static str),
613    #[error("argument {0} is a null string but the argument is not nullable")]
614    NullString(&'static str),
615    #[error("argument {0} is not valid UTF-8")]
616    NonUtf8(&'static str),
617    #[error("server sent error {} on object {}#{}", .2, .0.name(), .1)]
618    ServerError(ObjectInterface, u32, u32, #[source] StringError),
619    #[error("the message handler is already borrowed")]
620    HandlerBorrowed,
621    #[error("the client is not waiting for a delete_id message")]
622    NotAwaitingDeleteId,
623}
624
625#[derive(Debug, Error)]
626#[error("{0}")]
627pub(crate) struct StringError(pub String);