Skip to main content

wayland_backend/
server_api.rs

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