Skip to main content

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