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}