1 | use 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)] |
12 | use std::io::ErrorKind::WouldBlock; |
13 | |
14 | use crate::protocol::{Interface, Message, ObjectInfo}; |
15 | |
16 | use super::client_impl; |
17 | |
18 | pub 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 | pub 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 | |
59 | impl 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 | |
66 | downcast_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)] |
75 | pub struct ObjectId { |
76 | pub(crate) id: client_impl::InnerObjectId, |
77 | } |
78 | |
79 | impl 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 | |
87 | impl 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 | |
95 | impl 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)] |
138 | pub 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)] |
147 | pub struct WeakBackend { |
148 | inner: client_impl::WeakInnerBackend, |
149 | } |
150 | |
151 | impl 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: InnerBackend| Backend { backend }) |
157 | } |
158 | } |
159 | |
160 | impl 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)] |
308 | pub struct ReadEventsGuard { |
309 | pub(crate) guard: client_impl::InnerReadEventsGuard, |
310 | } |
311 | |
312 | impl 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 | } |
333 | pub(crate) struct DumbObjectData; |
334 | |
335 | impl 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 | |
351 | pub(crate) struct UninitObjectData; |
352 | |
353 | impl 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(name:"UninitObjectData" ).finish() |
369 | } |
370 | } |
371 | |