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