1 | use std::{ |
2 | any::Any, |
3 | fmt, |
4 | os::unix::io::{BorrowedFd, OwnedFd}, |
5 | os::unix::{io::RawFd, net::UnixStream}, |
6 | sync::Arc, |
7 | }; |
8 | |
9 | use crate::protocol::{Interface, Message, ObjectInfo}; |
10 | |
11 | use super::client_impl; |
12 | |
13 | pub 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. |
22 | pub 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 | |
54 | impl 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 | |
61 | downcast_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)] |
70 | pub struct ObjectId { |
71 | pub(crate) id: client_impl::InnerObjectId, |
72 | } |
73 | |
74 | impl 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 | |
82 | impl 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 | |
90 | impl 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)] |
133 | pub 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)] |
142 | pub struct WeakBackend { |
143 | inner: client_impl::WeakInnerBackend, |
144 | } |
145 | |
146 | impl 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 | |
155 | impl 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)] |
303 | pub struct ReadEventsGuard { |
304 | pub(crate) guard: client_impl::InnerReadEventsGuard, |
305 | } |
306 | |
307 | impl 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 | } |
328 | pub(crate) struct DumbObjectData; |
329 | |
330 | impl 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 | |
346 | pub(crate) struct UninitObjectData; |
347 | |
348 | impl 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 | |