Skip to main content

wayland_backend/
server_api.rs

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