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