Skip to main content

wayland_backend/
client_api.rs

1use std::{
2    any::Any,
3    fmt,
4    os::unix::{io::BorrowedFd, net::UnixStream},
5    sync::Arc,
6};
7
8#[cfg(doc)]
9use std::io::ErrorKind::WouldBlock;
10
11use crate::protocol::{Interface, Message, ObjectInfo, OwnedMessage};
12
13use super::client_impl;
14
15pub use crate::types::client::{InvalidId, NoWaylandLib, WaylandError};
16
17/// A trait representing your data associated to an object
18///
19/// You will only be given access to it as a `&` reference, so you
20/// need to handle interior mutability by yourself.
21///
22/// The methods of this trait will be invoked internally every time a
23/// new object is created to initialize its data.
24#[allow(private_bounds)]
25pub trait ObjectData: AsAny + Any + Send + Sync {
26    /// Dispatch an event for the associated object
27    ///
28    /// If the event has a `NewId` argument, the callback must return the object data
29    /// for the newly created object
30    fn event(
31        self: Arc<Self>,
32        backend: &Backend,
33        msg: OwnedMessage<ObjectId>,
34    ) -> Option<Arc<dyn ObjectData>>;
35
36    /// Notification that the object has been destroyed and is no longer active
37    fn destroyed(&self, object_id: &ObjectId);
38
39    /// Helper for forwarding a Debug implementation of your `ObjectData` type
40    ///
41    /// By default will just print `ObjectData { ... }`
42    #[cfg_attr(unstable_coverage, coverage(off))]
43    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        f.debug_struct("ObjectData").finish_non_exhaustive()
45    }
46
47    /// Helper for accessing user data
48    ///
49    /// This function is used to back the `Proxy::data()` function in `wayland_client`.  By default,
50    /// it returns `self`, but this may be overridden to allow downcasting user data
51    /// without needing to have access to the full type.
52    fn data_as_any(&self) -> &dyn Any {
53        self.as_any()
54    }
55}
56
57trait AsAny: 'static {
58    fn as_any(&self) -> &dyn Any;
59}
60
61impl<T: 'static> AsAny for T {
62    fn as_any(&self) -> &dyn Any {
63        self
64    }
65}
66
67impl std::fmt::Debug for dyn ObjectData {
68    #[cfg_attr(unstable_coverage, coverage(off))]
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        self.debug(f)
71    }
72}
73
74/// An ID representing a Wayland object
75///
76/// The backend internally tracks which IDs are still valid, invalidates them when the protocol object they
77/// represent is destroyed. As such even though the Wayland protocol reuses IDs, you can confidently compare
78/// two `ObjectId` for equality, they will only compare as equal if they both represent the same protocol
79/// object.
80#[derive(Clone, PartialEq, Eq, Hash)]
81pub struct ObjectId {
82    pub(crate) id: client_impl::InnerObjectId,
83}
84
85impl fmt::Display for ObjectId {
86    #[cfg_attr(unstable_coverage, coverage(off))]
87    #[inline]
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        self.id.fmt(f)
90    }
91}
92
93impl fmt::Debug for ObjectId {
94    #[cfg_attr(unstable_coverage, coverage(off))]
95    #[inline]
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        self.id.fmt(f)
98    }
99}
100
101impl ObjectId {
102    /// Check if this is a null ID
103    ///
104    /// **Note:** This is not the same as checking if the ID is still valid, which cannot be done without the
105    /// [`Backend`]. A null ID is the ID equivalent of a null pointer: it never has been valid and never will
106    /// be.
107    #[inline]
108    pub fn is_null(&self) -> bool {
109        self.id.is_null()
110    }
111
112    /// Create a null object ID
113    ///
114    /// This object ID is always invalid, and should be used as placeholder in requests that create objects,
115    /// or for request with an optional `Object` argument.
116    ///
117    /// See [`Backend::send_request()`] for details.
118    #[inline]
119    pub fn null() -> &'static ObjectId {
120        client_impl::InnerBackend::null_id()
121    }
122
123    /// Interface of the represented object
124    #[inline]
125    pub fn interface(&self) -> &'static Interface {
126        self.id.interface()
127    }
128
129    /// Return the protocol-level numerical ID of this object
130    ///
131    /// Protocol IDs are reused after object destruction, so this should not be used as a unique identifier,
132    /// instead use the [`ObjectId`] directly, it implements [`Clone`], [`PartialEq`], [`Eq`] and [`Hash`].
133    #[inline]
134    pub fn protocol_id(&self) -> u32 {
135        self.id.protocol_id()
136    }
137}
138
139/// A Wayland client backend
140///
141/// This type hosts all the interface for interacting with the wayland protocol. It can be
142/// cloned, all clones refer to the same underlying connection.
143#[derive(Clone, Debug, PartialEq, Eq)]
144pub struct Backend {
145    pub(crate) backend: client_impl::InnerBackend,
146}
147
148/// A weak handle to a [`Backend`]
149///
150/// This handle behaves similarly to [`Weak`][std::sync::Weak], and can be used to keep access to
151/// the backend without actually preventing it from being dropped.
152#[derive(Clone, Debug)]
153pub struct WeakBackend {
154    inner: client_impl::WeakInnerBackend,
155}
156
157impl WeakBackend {
158    /// Try to upgrade this weak handle to a [`Backend`]
159    ///
160    /// Returns [`None`] if the associated backend was already dropped.
161    pub fn upgrade(&self) -> Option<Backend> {
162        self.inner.upgrade().map(|backend| Backend { backend })
163    }
164}
165
166impl Backend {
167    /// Try to initialize a Wayland backend on the provided unix stream
168    ///
169    /// The provided stream should correspond to an already established unix connection with
170    /// the Wayland server.
171    ///
172    /// This method can only fail on the `sys` backend if the `dlopen` cargo feature was enabled
173    /// and the system wayland library could not be found.
174    pub fn connect(stream: UnixStream) -> Result<Self, NoWaylandLib> {
175        client_impl::InnerBackend::connect(stream).map(|backend| Self { backend })
176    }
177
178    /// Get a [`WeakBackend`] from this backend
179    pub fn downgrade(&self) -> WeakBackend {
180        WeakBackend { inner: self.backend.downgrade() }
181    }
182
183    /// Flush all pending outgoing requests to the server
184    ///
185    /// Most errors on this method mean that the Wayland connection is no longer valid, the only
186    /// exception being an IO [`WouldBlock`] error. In that case it means that you should try flushing again
187    /// later.
188    ///
189    /// You can however expect this method returning [`WouldBlock`] to be very rare: it can only occur if
190    /// either your client sent a lot of big messages at once, or the server is very laggy.
191    pub fn flush(&self) -> Result<(), WaylandError> {
192        self.backend.flush()
193    }
194
195    /// Access the Wayland socket FD for polling
196    #[inline]
197    pub fn poll_fd(&self) -> BorrowedFd<'_> {
198        self.backend.poll_fd()
199    }
200
201    /// Get the object ID for the `wl_display`
202    #[inline]
203    pub fn display_id(&self) -> ObjectId {
204        self.backend.display_id()
205    }
206
207    /// Get the last error that occurred on this backend
208    ///
209    /// If this returns [`Some`], your Wayland connection is already dead.
210    #[inline]
211    pub fn last_error(&self) -> Option<WaylandError> {
212        self.backend.last_error()
213    }
214
215    /// Get the detailed protocol information about a wayland object
216    ///
217    /// Returns an error if the provided object ID is no longer valid.
218    #[inline]
219    pub fn info(&self, id: &ObjectId) -> Result<ObjectInfo, InvalidId> {
220        self.backend.info(id)
221    }
222
223    /// Destroy an object
224    ///
225    /// For most protocols, this is handled automatically when a destructor
226    /// message is sent or received.
227    ///
228    /// This corresponds to `wl_proxy_destroy` in the C API. Or a `_destroy`
229    /// method generated for an object without a destructor request.
230    pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
231        self.backend.destroy_object(id)
232    }
233
234    /// Sends a request to the server
235    ///
236    /// Returns an error if the sender ID of the provided message is no longer valid.
237    ///
238    /// **Panic:**
239    ///
240    /// Several checks against the protocol specification are done, and this method will panic if they do
241    /// not pass:
242    ///
243    /// - the message opcode must be valid for the sender interface
244    /// - the argument list must match the prototype for the message associated with this opcode
245    /// - if the method creates a new object, a [`ObjectId::null()`] must be given
246    ///   in the argument list at the appropriate place, and a `child_spec` (interface and version)
247    ///   can be provided. If one is provided, it'll be checked against the protocol spec. If the
248    ///   protocol specification does not define the interface of the created object (notable example
249    ///   is `wl_registry.bind`), the `child_spec` must be provided.
250    pub fn send_request(
251        &self,
252        msg: Message<ObjectId>,
253        data: Option<Arc<dyn ObjectData>>,
254        child_spec: Option<(&'static Interface, u32)>,
255    ) -> Result<ObjectId, InvalidId> {
256        self.backend.send_request(msg, data, child_spec)
257    }
258
259    /// Access the object data associated with a given object ID
260    ///
261    /// Returns an error if the object ID is not longer valid or if it corresponds to a Wayland
262    /// object that is not managed by this backend (when multiple libraries share the same Wayland
263    /// socket via `libwayland` if using the system backend).
264    pub fn get_data(&self, id: &ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
265        self.backend.get_data(id)
266    }
267
268    /// Set the object data associated with a given object ID
269    ///
270    /// Returns an error if the object ID is not longer valid or if it corresponds to a Wayland
271    /// object that is not managed by this backend (when multiple libraries share the same Wayland
272    /// socket via `libwayland` if using the system backend).
273    pub fn set_data(&self, id: &ObjectId, data: Arc<dyn ObjectData>) -> Result<(), InvalidId> {
274        self.backend.set_data(id, data)
275    }
276
277    /// Create a new reading guard
278    ///
279    /// This is the first step for actually reading events from the Wayland socket. See
280    /// [`ReadEventsGuard`] for how to use it.
281    ///
282    /// This call will not block, but may return [`None`] if the inner queue of the backend needs to
283    /// be dispatched. In which case you should invoke
284    /// [`dispatch_inner_queue()`][Self::dispatch_inner_queue()].
285    #[inline]
286    #[must_use]
287    pub fn prepare_read(&self) -> Option<ReadEventsGuard> {
288        client_impl::InnerReadEventsGuard::try_new(self.backend.clone())
289            .map(|guard| ReadEventsGuard { guard })
290    }
291
292    /// Dispatches the inner queue of this backend if necessary
293    ///
294    /// This function actually only does something when using the system backend. It dispaches an inner
295    /// queue that the backend uses to wrap `libwayland`. While this dispatching is generally done in
296    /// [`ReadEventsGuard::read()`], if multiple threads are interacting with the
297    /// Wayland socket it can happen that this queue was filled by another thread. In that case
298    /// [`prepare_read()`][Self::prepare_read()] will return [`None`], and you should invoke
299    /// this function instead of using the [`ReadEventsGuard`]
300    ///
301    /// Returns the number of messages that were dispatched to their [`ObjectData`] callbacks.
302    #[inline]
303    pub fn dispatch_inner_queue(&self) -> Result<usize, WaylandError> {
304        self.backend.dispatch_inner_queue()
305    }
306
307    /// Set maximum buffer size for connection
308    #[cfg(feature = "libwayland_client_1_23")]
309    pub fn set_max_buffer_size(&self, max_buffer_size: Option<usize>) {
310        self.backend.set_max_buffer_size(max_buffer_size);
311    }
312}
313
314/// Guard for synchronizing event reading across multiple threads
315///
316/// If multiple threads need to read events from the Wayland socket concurrently,
317/// it is necessary to synchronize their access. Failing to do so may cause some of the
318/// threads to not be notified of new events, and sleep much longer than appropriate.
319///
320/// This guard is provided to ensure the proper synchronization is done. The guard is created using
321/// the [`Backend::prepare_read()`] method. And the event reading is
322/// triggered by consuming the guard using the [`ReadEventsGuard::read()`] method, synchronizing
323/// with other threads as necessary so that only one of the threads will actually perform the socket read.
324///
325/// If you plan to poll the Wayland socket for readiness, the file descriptor can be retrieved via
326/// the [`ReadEventsGuard::connection_fd()`] method. Note that for the synchronization to
327/// correctly occur, you must *always* create the `ReadEventsGuard` *before* polling the socket.
328///
329/// Dropping the guard is valid and will cancel the prepared read.
330#[derive(Debug)]
331pub struct ReadEventsGuard {
332    pub(crate) guard: client_impl::InnerReadEventsGuard,
333}
334
335impl ReadEventsGuard {
336    /// Access the Wayland socket FD for polling
337    #[inline]
338    pub fn connection_fd(&self) -> BorrowedFd<'_> {
339        self.guard.connection_fd()
340    }
341
342    /// Attempt to read events from the Wayland socket
343    ///
344    /// If multiple threads have a live reading guard, this method will block until all of them
345    /// are either dropped or have their `read()` method invoked, at which point one of the threads
346    /// will read events from the socket and invoke the callbacks for the received events. All
347    /// threads will then resume their execution.
348    ///
349    /// This returns the number of dispatched events, or `0` if no events are available to read from
350    /// the socket, or an other thread handled the dispatching. On success, the socket has been
351    /// read until EOF or `WouldBlock`.
352    #[inline]
353    pub fn read(self) -> Result<usize, WaylandError> {
354        self.guard.read()
355    }
356}
357pub(crate) struct DumbObjectData;
358
359impl ObjectData for DumbObjectData {
360    #[cfg_attr(unstable_coverage, coverage(off))]
361    fn event(
362        self: Arc<Self>,
363        _handle: &Backend,
364        _msg: OwnedMessage<ObjectId>,
365    ) -> Option<Arc<dyn ObjectData>> {
366        unreachable!()
367    }
368
369    #[cfg_attr(unstable_coverage, coverage(off))]
370    fn destroyed(&self, _object_id: &ObjectId) {
371        unreachable!()
372    }
373}
374
375pub(crate) struct UninitObjectData;
376
377impl ObjectData for UninitObjectData {
378    #[cfg_attr(unstable_coverage, coverage(off))]
379    fn event(
380        self: Arc<Self>,
381        _handle: &Backend,
382        msg: OwnedMessage<ObjectId>,
383    ) -> Option<Arc<dyn ObjectData>> {
384        panic!("Received a message on an uninitialized object: {msg:?}");
385    }
386
387    #[cfg_attr(unstable_coverage, coverage(off))]
388    fn destroyed(&self, _object_id: &ObjectId) {}
389
390    #[cfg_attr(unstable_coverage, coverage(off))]
391    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
392        f.debug_struct("UninitObjectData").finish()
393    }
394}