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