wayland_backend/
server_api.rs

1use std::{
2    ffi::CString,
3    fmt,
4    os::unix::{
5        io::{BorrowedFd, OwnedFd, RawFd},
6        net::UnixStream,
7    },
8    sync::Arc,
9};
10
11use crate::protocol::{Interface, Message, ObjectInfo};
12pub use crate::types::server::{Credentials, DisconnectReason, GlobalInfo, InitError, InvalidId};
13
14use super::server_impl;
15
16/// A trait representing your data associated to an object
17///
18/// You will only be given access to it as a `&` reference, so you
19/// need to handle interior mutability by yourself.
20///
21/// The methods of this trait will be invoked internally every time a
22/// new object is created to initialize its data.
23pub trait ObjectData<D>: downcast_rs::DowncastSync {
24    /// Dispatch a request for the associated object
25    ///
26    /// If the request has a `NewId` argument, the callback must return the object data
27    /// for the newly created object
28    fn request(
29        self: Arc<Self>,
30        handle: &Handle,
31        data: &mut D,
32        client_id: ClientId,
33        msg: Message<ObjectId, OwnedFd>,
34    ) -> Option<Arc<dyn ObjectData<D>>>;
35    /// Notification that the object has been destroyed and is no longer active
36    fn destroyed(
37        self: Arc<Self>,
38        handle: &Handle,
39        data: &mut D,
40        client_id: ClientId,
41        object_id: ObjectId,
42    );
43    /// Helper for forwarding a Debug implementation of your `ObjectData` type
44    ///
45    /// By default will just print `ObjectData { ... }`
46    #[cfg_attr(unstable_coverage, coverage(off))]
47    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        f.debug_struct("ObjectData").finish_non_exhaustive()
49    }
50}
51
52downcast_rs::impl_downcast!(sync ObjectData<D>);
53
54impl<D: 'static> std::fmt::Debug for dyn ObjectData<D> {
55    #[cfg_attr(unstable_coverage, coverage(off))]
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        self.debug(f)
58    }
59}
60
61/// A trait representing the handling of new bound globals
62pub trait GlobalHandler<D>: downcast_rs::DowncastSync {
63    /// Check if given client is allowed to interact with given global
64    ///
65    /// If this function returns false, the client will not be notified of the existence
66    /// of this global, and any attempt to bind it will result in a protocol error as if
67    /// the global did not exist.
68    ///
69    /// Default implementation always return true.
70    fn can_view(
71        &self,
72        _client_id: ClientId,
73        _client_data: &Arc<dyn ClientData>,
74        _global_id: GlobalId,
75    ) -> bool {
76        true
77    }
78    /// A global has been bound
79    ///
80    /// Given client bound given global, creating given object.
81    ///
82    /// The method must return the object data for the newly created object.
83    fn bind(
84        self: Arc<Self>,
85        handle: &Handle,
86        data: &mut D,
87        client_id: ClientId,
88        global_id: GlobalId,
89        object_id: ObjectId,
90    ) -> Arc<dyn ObjectData<D>>;
91    /// Helper for forwarding a Debug implementation of your `GlobalHandler` type
92    ///
93    /// By default will just print `GlobalHandler { ... }`
94    #[cfg_attr(unstable_coverage, coverage(off))]
95    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        f.debug_struct("GlobalHandler").finish_non_exhaustive()
97    }
98}
99
100impl<D: 'static> std::fmt::Debug for dyn GlobalHandler<D> {
101    #[cfg_attr(unstable_coverage, coverage(off))]
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        self.debug(f)
104    }
105}
106
107downcast_rs::impl_downcast!(sync GlobalHandler<D>);
108
109/// A trait representing your data associated to a client
110pub trait ClientData: downcast_rs::DowncastSync {
111    /// Notification that the client was initialized
112    fn initialized(&self, _client_id: ClientId) {}
113    /// Notification that the client is disconnected
114    fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {}
115    /// Helper for forwarding a Debug implementation of your `ClientData` type
116    ///
117    /// By default will just print `GlobalHandler { ... }`
118    #[cfg_attr(unstable_coverage, coverage(off))]
119    fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120        f.debug_struct("ClientData").finish_non_exhaustive()
121    }
122}
123
124impl std::fmt::Debug for dyn ClientData {
125    #[cfg_attr(unstable_coverage, coverage(off))]
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        self.debug(f)
128    }
129}
130
131impl ClientData for () {}
132
133downcast_rs::impl_downcast!(sync ClientData);
134
135/// An ID representing a Wayland object
136///
137/// The backend internally tracks which IDs are still valid, invalidates them when the protocol object they
138/// represent is destroyed. As such even though the Wayland protocol reuses IDs, you still confidently compare
139/// two `ObjectId` for equality, they will only compare as equal if they both represent the same protocol
140/// object from the same client.
141#[derive(Clone, PartialEq, Eq, Hash)]
142pub struct ObjectId {
143    pub(crate) id: server_impl::InnerObjectId,
144}
145
146impl ObjectId {
147    /// Returns whether this object is a null object.
148    ///
149    /// **Note:** This is not the same as checking if the ID is still valid, which cannot be done without the
150    /// [`Backend`]. A null ID is the ID equivalent of a null pointer: it never has been valid and never will
151    /// be.
152    pub fn is_null(&self) -> bool {
153        self.id.is_null()
154    }
155
156    /// Returns an object id that represents a null object.
157    ///
158    /// This object ID is always invalid, and should be used for events with an optional `Object` argument.
159    #[inline]
160    pub fn null() -> ObjectId {
161        server_impl::InnerHandle::null_id()
162    }
163
164    /// Returns the interface of this object.
165    pub fn interface(&self) -> &'static Interface {
166        self.id.interface()
167    }
168
169    /// Check if two object IDs are associated with the same client
170    ///
171    /// *Note:* This may spuriously return `false` if one (or both) of the objects to compare
172    /// is no longer valid.
173    pub fn same_client_as(&self, other: &Self) -> bool {
174        self.id.same_client_as(&other.id)
175    }
176
177    /// Return the protocol-level numerical ID of this object
178    ///
179    /// Protocol IDs are reused after object destruction and each client has its own ID space, so this should
180    /// not be used as a unique identifier, instead use the `ObjectId` directly, it implements `Clone`,
181    /// `PartialEq`, `Eq` and `Hash`.
182    pub fn protocol_id(&self) -> u32 {
183        self.id.protocol_id()
184    }
185}
186
187impl fmt::Display for ObjectId {
188    #[cfg_attr(unstable_coverage, coverage(off))]
189    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190        self.id.fmt(f)
191    }
192}
193
194impl fmt::Debug for ObjectId {
195    #[cfg_attr(unstable_coverage, coverage(off))]
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        self.id.fmt(f)
198    }
199}
200
201/// An ID representing a Wayland client
202///
203/// The backend internally tracks which IDs are still valid, invalidates them when the client they represent
204/// is disconnected. As such you can confidently compare two `ClientId` for equality, they will only compare
205/// as equal if they both represent the same client.
206#[derive(Clone, PartialEq, Eq, Hash)]
207pub struct ClientId {
208    pub(crate) id: server_impl::InnerClientId,
209}
210
211impl fmt::Debug for ClientId {
212    #[cfg_attr(unstable_coverage, coverage(off))]
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        self.id.fmt(f)
215    }
216}
217
218/// An Id representing a global
219#[derive(Clone, PartialEq, Eq, Hash)]
220pub struct GlobalId {
221    pub(crate) id: server_impl::InnerGlobalId,
222}
223
224impl fmt::Debug for GlobalId {
225    #[cfg_attr(unstable_coverage, coverage(off))]
226    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        self.id.fmt(f)
228    }
229}
230
231/// Main handle of a backend to the Wayland protocol
232///
233/// This type hosts most of the protocol-related functionality of the backend, and is the
234/// main entry point for manipulating Wayland objects. It can be retrieved from the backend via
235/// [`Backend::handle()`] and cloned, and is given to you as argument in many callbacks.
236#[derive(Clone, Debug)]
237pub struct Handle {
238    pub(crate) handle: server_impl::InnerHandle,
239}
240
241/// A weak reference to a [`Handle`]
242///
243/// This handle behaves similarly to [`Weak`][std::sync::Weak], and can be used to keep access to
244/// the handle without actually preventing it from being dropped.
245#[derive(Clone, Debug)]
246pub struct WeakHandle {
247    pub(crate) handle: server_impl::WeakInnerHandle,
248}
249
250impl WeakHandle {
251    /// Try to upgrade this weak handle to a [`Handle`]
252    ///
253    /// Returns [`None`] if the associated backend was already dropped.
254    #[inline]
255    pub fn upgrade(&self) -> Option<Handle> {
256        self.handle.upgrade().map(|handle| Handle { handle })
257    }
258}
259
260impl Handle {
261    /// Get a [`WeakHandle`] from this handle
262    #[inline]
263    pub fn downgrade(&self) -> WeakHandle {
264        WeakHandle { handle: self.handle.downgrade() }
265    }
266
267    /// Get the detailed protocol information about a wayland object
268    ///
269    /// Returns an error if the provided object ID is no longer valid.
270    #[inline]
271    pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
272        self.handle.object_info(id.id)
273    }
274
275    /// Initializes a connection with a client.
276    ///
277    /// The `data` parameter contains data that will be associated with the client.
278    #[inline]
279    pub fn insert_client(
280        &mut self,
281        stream: UnixStream,
282        data: Arc<dyn ClientData>,
283    ) -> std::io::Result<ClientId> {
284        Ok(ClientId { id: self.handle.insert_client(stream, data)? })
285    }
286
287    /// Returns the id of the client which owns the object.
288    #[inline]
289    pub fn get_client(&self, id: ObjectId) -> Result<ClientId, InvalidId> {
290        self.handle.get_client(id.id)
291    }
292
293    /// Returns the data associated with a client.
294    #[inline]
295    pub fn get_client_data(&self, id: ClientId) -> Result<Arc<dyn ClientData>, InvalidId> {
296        self.handle.get_client_data(id.id)
297    }
298
299    /// Retrive the [`Credentials`] of a client
300    #[inline]
301    pub fn get_client_credentials(&self, id: ClientId) -> Result<Credentials, InvalidId> {
302        self.handle.get_client_credentials(id.id)
303    }
304
305    /// Invokes a closure for all clients connected to this server
306    ///
307    /// Note that while this method is running, an internal lock of the backend is held,
308    /// as a result invoking other methods of the `Handle` within the closure will deadlock.
309    /// You should thus store the relevant `ClientId` in a container of your choice and process
310    /// them after this method has returned.
311    #[inline]
312    pub fn with_all_clients(&self, f: impl FnMut(ClientId)) {
313        self.handle.with_all_clients(f)
314    }
315
316    /// Invokes a closure for all objects owned by a client.
317    ///
318    /// Note that while this method is running, an internal lock of the backend is held,
319    /// as a result invoking other methods of the `Handle` within the closure will deadlock.
320    /// You should thus store the relevant `ObjectId` in a container of your choice and process
321    /// them after this method has returned.
322    #[inline]
323    pub fn with_all_objects_for(
324        &self,
325        client_id: ClientId,
326        f: impl FnMut(ObjectId),
327    ) -> Result<(), InvalidId> {
328        self.handle.with_all_objects_for(client_id.id, f)
329    }
330
331    /// Retrieve the `ObjectId` for a wayland object given its protocol numerical ID
332    #[inline]
333    pub fn object_for_protocol_id(
334        &self,
335        client_id: ClientId,
336        interface: &'static Interface,
337        protocol_id: u32,
338    ) -> Result<ObjectId, InvalidId> {
339        self.handle.object_for_protocol_id(client_id.id, interface, protocol_id)
340    }
341
342    /// Create a new object for given client
343    ///
344    /// To ensure state coherence of the protocol, the created object should be immediately
345    /// sent as a "New ID" argument in an event to the client.
346    ///
347    /// # Panics
348    ///
349    /// This method will panic if the type parameter `D` is not same to the same type as the
350    /// one the backend was initialized with.
351    #[inline]
352    pub fn create_object<D: 'static>(
353        &self,
354        client_id: ClientId,
355        interface: &'static Interface,
356        version: u32,
357        data: Arc<dyn ObjectData<D>>,
358    ) -> Result<ObjectId, InvalidId> {
359        self.handle.create_object(client_id.id, interface, version, data)
360    }
361
362    /// Destroy an object
363    ///
364    /// For most protocols, this is handled automatically when a destructor
365    /// message is sent or received.
366    ///
367    /// This corresponds to `wl_resource_destroy` in the C API.
368    ///
369    /// # Panics
370    ///
371    /// This method will panic if the type parameter `D` is not same to the same type as the
372    /// one the backend was initialized with.
373    pub fn destroy_object<D: 'static>(&self, id: &ObjectId) -> Result<(), InvalidId> {
374        self.handle.destroy_object::<D>(id)
375    }
376
377    /// Send an event to the client
378    ///
379    /// Returns an error if the sender ID of the provided message is no longer valid.
380    ///
381    /// # Panics
382    ///
383    /// Checks against the protocol specification are done, and this method will panic if they do
384    /// not pass:
385    ///
386    /// - the message opcode must be valid for the sender interface
387    /// - the argument list must match the prototype for the message associated with this opcode
388    #[inline]
389    pub fn send_event(&self, msg: Message<ObjectId, RawFd>) -> Result<(), InvalidId> {
390        self.handle.send_event(msg)
391    }
392
393    /// Returns the data associated with an object.
394    ///
395    /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
396    /// one the backend was initialized with.
397    #[inline]
398    pub fn get_object_data<D: 'static>(
399        &self,
400        id: ObjectId,
401    ) -> Result<Arc<dyn ObjectData<D>>, InvalidId> {
402        self.handle.get_object_data(id.id)
403    }
404
405    /// Returns the data associated with an object as a `dyn Any`
406    #[inline]
407    pub fn get_object_data_any(
408        &self,
409        id: ObjectId,
410    ) -> Result<Arc<dyn std::any::Any + Send + Sync>, InvalidId> {
411        self.handle.get_object_data_any(id.id)
412    }
413
414    /// Sets the data associated with some object.
415    ///
416    /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
417    /// one the backend was initialized with.
418    #[inline]
419    pub fn set_object_data<D: 'static>(
420        &self,
421        id: ObjectId,
422        data: Arc<dyn ObjectData<D>>,
423    ) -> Result<(), InvalidId> {
424        self.handle.set_object_data(id.id, data)
425    }
426
427    /// Posts a protocol error on an object. This will also disconnect the client which created the object.
428    #[inline]
429    pub fn post_error(&self, object_id: ObjectId, error_code: u32, message: CString) {
430        self.handle.post_error(object_id.id, error_code, message)
431    }
432
433    /// Kills the connection to a client.
434    ///
435    /// The disconnection reason determines the error message that is sent to the client (if any).
436    #[inline]
437    pub fn kill_client(&self, client_id: ClientId, reason: DisconnectReason) {
438        self.handle.kill_client(client_id.id, reason)
439    }
440
441    /// Creates a global of the specified interface and version and then advertises it to clients.
442    ///
443    /// The clients which the global is advertised to is determined by the implementation of the [`GlobalHandler`].
444    ///
445    /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
446    /// one the backend was initialized with.
447    #[inline]
448    pub fn create_global<D: 'static>(
449        &self,
450        interface: &'static Interface,
451        version: u32,
452        handler: Arc<dyn GlobalHandler<D>>,
453    ) -> GlobalId {
454        GlobalId { id: self.handle.create_global(interface, version, handler) }
455    }
456
457    /// Disables a global object that is currently active.
458    ///
459    /// The global removal will be signaled to all currently connected clients. New clients will not know of
460    /// the global, but the associated state and callbacks will not be freed. As such, clients that still try
461    /// to bind the global afterwards (because they have not yet realized it was removed) will succeed.
462    ///
463    /// Invoking this method on an already disabled or removed global does nothing. It is not possible to
464    /// re-enable a disabled global, this method is meant to be invoked some time before actually removing
465    /// the global, to avoid killing clients because of a race.
466    ///
467    /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
468    /// one the backend was initialized with.
469    #[inline]
470    pub fn disable_global<D: 'static>(&self, id: GlobalId) {
471        self.handle.disable_global::<D>(id.id)
472    }
473
474    /// Removes a global object and free its ressources.
475    ///
476    /// The global object will no longer be considered valid by the server, clients trying to bind it will be
477    /// killed, and the global ID is freed for re-use.
478    ///
479    /// It is advised to first disable a global and wait some amount of time before removing it, to ensure all
480    /// clients are correctly aware of its removal. Note that clients will generally not expect globals that
481    /// represent a capability of the server to be removed, as opposed to globals representing peripherals
482    /// (like `wl_output` or `wl_seat`).
483    ///
484    /// This methods does nothing if the provided `GlobalId` corresponds to an already removed global.
485    ///
486    /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
487    /// one the backend was initialized with.
488    #[inline]
489    pub fn remove_global<D: 'static>(&self, id: GlobalId) {
490        self.handle.remove_global::<D>(id.id)
491    }
492
493    /// Returns information about a global.
494    #[inline]
495    pub fn global_info(&self, id: GlobalId) -> Result<GlobalInfo, InvalidId> {
496        self.handle.global_info(id.id)
497    }
498
499    /// Returns the handler which manages the visibility and notifies when a client has bound the global.
500    #[inline]
501    pub fn get_global_handler<D: 'static>(
502        &self,
503        id: GlobalId,
504    ) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
505        self.handle.get_global_handler(id.id)
506    }
507
508    /// Flushes pending events destined for a client.
509    ///
510    /// If no client is specified, all pending events are flushed to all clients.
511    pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
512        self.handle.flush(client)
513    }
514}
515
516/// A backend object that represents the state of a wayland server.
517///
518/// A backend is used to drive a wayland server by receiving requests, dispatching messages to the appropriate
519/// handlers and flushes requests to be sent back to the client.
520#[derive(Debug)]
521pub struct Backend<D: 'static> {
522    pub(crate) backend: server_impl::InnerBackend<D>,
523}
524
525impl<D> Backend<D> {
526    /// Initialize a new Wayland backend
527    #[inline]
528    pub fn new() -> Result<Self, InitError> {
529        Ok(Self { backend: server_impl::InnerBackend::new()? })
530    }
531
532    /// Flushes pending events destined for a client.
533    ///
534    /// If no client is specified, all pending events are flushed to all clients.
535    #[inline]
536    pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
537        self.backend.flush(client)
538    }
539
540    /// Returns a handle which represents the server side state of the backend.
541    ///
542    /// The handle provides a variety of functionality, such as querying information about wayland objects,
543    /// obtaining data associated with a client and it's objects, and creating globals.
544    #[inline]
545    pub fn handle(&self) -> Handle {
546        self.backend.handle()
547    }
548
549    /// Returns the underlying file descriptor.
550    ///
551    /// The file descriptor may be monitored for activity with a polling mechanism such as epoll or kqueue.
552    /// When it becomes readable, this means there are pending messages that would be dispatched if you call
553    /// [`Backend::dispatch_all_clients`].
554    ///
555    /// The file descriptor should not be used for any other purpose than monitoring it.
556    #[inline]
557    pub fn poll_fd(&self) -> BorrowedFd<'_> {
558        self.backend.poll_fd()
559    }
560
561    /// Dispatches all pending messages from the specified client.
562    ///
563    /// This method will not block if there are no pending messages.
564    ///
565    /// The provided `data` will be provided to the handler of messages received from the client.
566    ///
567    /// For performance reasons, use of this function should be integrated with an event loop, monitoring
568    /// the file descriptor associated with the client and only calling this method when messages are
569    /// available.
570    ///
571    /// **Note:** This functionality is currently only available on the rust backend, invoking this method on
572    /// the system backend will do the same as invoking
573    /// [`Backend::dispatch_all_clients()`].
574    #[inline]
575    pub fn dispatch_single_client(
576        &mut self,
577        data: &mut D,
578        client_id: ClientId,
579    ) -> std::io::Result<usize> {
580        self.backend.dispatch_client(data, client_id.id)
581    }
582
583    /// Dispatches all pending messages from all clients.
584    ///
585    /// This method will not block if there are no pending messages.
586    ///
587    /// The provided `data` will be provided to the handler of messages received from the clients.
588    ///
589    /// For performance reasons, use of this function should be integrated with an event loop, monitoring the
590    /// file descriptor retrieved by [`Backend::poll_fd`] and only calling this method when messages are
591    /// available.
592    #[inline]
593    pub fn dispatch_all_clients(&mut self, data: &mut D) -> std::io::Result<usize> {
594        self.backend.dispatch_all_clients(data)
595    }
596}
597
598// Workaround: Some versions of rustc throw a `struct is never constructed`-warning here,
599// if the `server_system`-feature is enabled, even though the `rs`-module makes use if it.
600#[allow(dead_code)]
601pub(crate) struct DumbObjectData;
602
603#[allow(dead_code)]
604impl<D> ObjectData<D> for DumbObjectData {
605    #[cfg_attr(unstable_coverage, coverage(off))]
606    fn request(
607        self: Arc<Self>,
608        _handle: &Handle,
609        _data: &mut D,
610        _client_id: ClientId,
611        _msg: Message<ObjectId, OwnedFd>,
612    ) -> Option<Arc<dyn ObjectData<D>>> {
613        unreachable!()
614    }
615
616    #[cfg_attr(unstable_coverage, coverage(off))]
617    fn destroyed(
618        self: Arc<Self>,
619        _handle: &Handle,
620        _: &mut D,
621        _client_id: ClientId,
622        _object_id: ObjectId,
623    ) {
624    }
625}