| 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 | |