wayland_backend/
client_api.rs

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
366
367
368
369
370
use std::{
    any::Any,
    fmt,
    os::unix::{
        io::{BorrowedFd, OwnedFd, RawFd},
        net::UnixStream,
    },
    sync::Arc,
};

#[cfg(doc)]
use std::io::ErrorKind::WouldBlock;

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`][downcast_rs::DowncastSync]), 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()`] 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()`] 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()`][Self::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()`], 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()`][Self::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()`] method. And the event reading is
/// triggered by consuming the guard using the [`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 [`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()
    }
}