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