Skip to main content

wayland_backend/
server_api.rs

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