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(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(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(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(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(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(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(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(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(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(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 /// Send an event to the client
363 ///
364 /// Returns an error if the sender ID of the provided message is no longer valid.
365 ///
366 /// # Panics
367 ///
368 /// Checks against the protocol specification are done, and this method will panic if they do
369 /// not pass:
370 ///
371 /// - the message opcode must be valid for the sender interface
372 /// - the argument list must match the prototype for the message associated with this opcode
373 #[inline]
374 pub fn send_event(&self, msg: Message<ObjectId, RawFd>) -> Result<(), InvalidId> {
375 self.handle.send_event(msg)
376 }
377
378 /// Returns the data associated with an object.
379 ///
380 /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
381 /// one the backend was initialized with.
382 #[inline]
383 pub fn get_object_data<D: 'static>(
384 &self,
385 id: ObjectId,
386 ) -> Result<Arc<dyn ObjectData<D>>, InvalidId> {
387 self.handle.get_object_data(id.id)
388 }
389
390 /// Returns the data associated with an object as a `dyn Any`
391 #[inline]
392 pub fn get_object_data_any(
393 &self,
394 id: ObjectId,
395 ) -> Result<Arc<dyn std::any::Any + Send + Sync>, InvalidId> {
396 self.handle.get_object_data_any(id.id)
397 }
398
399 /// Sets the data associated with some object.
400 ///
401 /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
402 /// one the backend was initialized with.
403 #[inline]
404 pub fn set_object_data<D: 'static>(
405 &self,
406 id: ObjectId,
407 data: Arc<dyn ObjectData<D>>,
408 ) -> Result<(), InvalidId> {
409 self.handle.set_object_data(id.id, data)
410 }
411
412 /// Posts a protocol error on an object. This will also disconnect the client which created the object.
413 #[inline]
414 pub fn post_error(&self, object_id: ObjectId, error_code: u32, message: CString) {
415 self.handle.post_error(object_id.id, error_code, message)
416 }
417
418 /// Kills the connection to a client.
419 ///
420 /// The disconnection reason determines the error message that is sent to the client (if any).
421 #[inline]
422 pub fn kill_client(&self, client_id: ClientId, reason: DisconnectReason) {
423 self.handle.kill_client(client_id.id, reason)
424 }
425
426 /// Creates a global of the specified interface and version and then advertises it to clients.
427 ///
428 /// The clients which the global is advertised to is determined by the implementation of the [`GlobalHandler`].
429 ///
430 /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
431 /// one the backend was initialized with.
432 #[inline]
433 pub fn create_global<D: 'static>(
434 &self,
435 interface: &'static Interface,
436 version: u32,
437 handler: Arc<dyn GlobalHandler<D>>,
438 ) -> GlobalId {
439 GlobalId { id: self.handle.create_global(interface, version, handler) }
440 }
441
442 /// Disables a global object that is currently active.
443 ///
444 /// The global removal will be signaled to all currently connected clients. New clients will not know of
445 /// the global, but the associated state and callbacks will not be freed. As such, clients that still try
446 /// to bind the global afterwards (because they have not yet realized it was removed) will succeed.
447 ///
448 /// Invoking this method on an already disabled or removed global does nothing. It is not possible to
449 /// re-enable a disabled global, this method is meant to be invoked some time before actually removing
450 /// the global, to avoid killing clients because of a race.
451 ///
452 /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
453 /// one the backend was initialized with.
454 #[inline]
455 pub fn disable_global<D: 'static>(&self, id: GlobalId) {
456 self.handle.disable_global::<D>(id.id)
457 }
458
459 /// Removes a global object and free its ressources.
460 ///
461 /// The global object will no longer be considered valid by the server, clients trying to bind it will be
462 /// killed, and the global ID is freed for re-use.
463 ///
464 /// It is advised to first disable a global and wait some amount of time before removing it, to ensure all
465 /// clients are correctly aware of its removal. Note that clients will generally not expect globals that
466 /// represent a capability of the server to be removed, as opposed to globals representing peripherals
467 /// (like `wl_output` or `wl_seat`).
468 ///
469 /// This methods does nothing if the provided `GlobalId` corresponds to an already removed global.
470 ///
471 /// **Panic:** This method will panic if the type parameter `D` is not same to the same type as the
472 /// one the backend was initialized with.
473 #[inline]
474 pub fn remove_global<D: 'static>(&self, id: GlobalId) {
475 self.handle.remove_global::<D>(id.id)
476 }
477
478 /// Returns information about a global.
479 #[inline]
480 pub fn global_info(&self, id: GlobalId) -> Result<GlobalInfo, InvalidId> {
481 self.handle.global_info(id.id)
482 }
483
484 /// Returns the handler which manages the visibility and notifies when a client has bound the global.
485 #[inline]
486 pub fn get_global_handler<D: 'static>(
487 &self,
488 id: GlobalId,
489 ) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
490 self.handle.get_global_handler(id.id)
491 }
492
493 /// Flushes pending events destined for a client.
494 ///
495 /// If no client is specified, all pending events are flushed to all clients.
496 pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
497 self.handle.flush(client)
498 }
499}
500
501/// A backend object that represents the state of a wayland server.
502///
503/// A backend is used to drive a wayland server by receiving requests, dispatching messages to the appropriate
504/// handlers and flushes requests to be sent back to the client.
505#[derive(Debug)]
506pub struct Backend<D: 'static> {
507 pub(crate) backend: server_impl::InnerBackend<D>,
508}
509
510impl<D> Backend<D> {
511 /// Initialize a new Wayland backend
512 #[inline]
513 pub fn new() -> Result<Self, InitError> {
514 Ok(Self { backend: server_impl::InnerBackend::new()? })
515 }
516
517 /// Flushes pending events destined for a client.
518 ///
519 /// If no client is specified, all pending events are flushed to all clients.
520 #[inline]
521 pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
522 self.backend.flush(client)
523 }
524
525 /// Returns a handle which represents the server side state of the backend.
526 ///
527 /// The handle provides a variety of functionality, such as querying information about wayland objects,
528 /// obtaining data associated with a client and it's objects, and creating globals.
529 #[inline]
530 pub fn handle(&self) -> Handle {
531 self.backend.handle()
532 }
533
534 /// Returns the underlying file descriptor.
535 ///
536 /// The file descriptor may be monitored for activity with a polling mechanism such as epoll or kqueue.
537 /// When it becomes readable, this means there are pending messages that would be dispatched if you call
538 /// [`Backend::dispatch_all_clients`].
539 ///
540 /// The file descriptor should not be used for any other purpose than monitoring it.
541 #[inline]
542 pub fn poll_fd(&self) -> BorrowedFd {
543 self.backend.poll_fd()
544 }
545
546 /// Dispatches all pending messages from the specified client.
547 ///
548 /// This method will not block if there are no pending messages.
549 ///
550 /// The provided `data` will be provided to the handler of messages received from the client.
551 ///
552 /// For performance reasons, use of this function should be integrated with an event loop, monitoring
553 /// the file descriptor associated with the client and only calling this method when messages are
554 /// available.
555 ///
556 /// **Note:** This functionality is currently only available on the rust backend, invoking this method on
557 /// the system backend will do the same as invoking
558 /// [`Backend::dispatch_all_clients()`].
559 #[inline]
560 pub fn dispatch_single_client(
561 &mut self,
562 data: &mut D,
563 client_id: ClientId,
564 ) -> std::io::Result<usize> {
565 self.backend.dispatch_client(data, client_id.id)
566 }
567
568 /// Dispatches all pending messages from all clients.
569 ///
570 /// This method will not block if there are no pending messages.
571 ///
572 /// The provided `data` will be provided to the handler of messages received from the clients.
573 ///
574 /// For performance reasons, use of this function should be integrated with an event loop, monitoring the
575 /// file descriptor retrieved by [`Backend::poll_fd`] and only calling this method when messages are
576 /// available.
577 #[inline]
578 pub fn dispatch_all_clients(&mut self, data: &mut D) -> std::io::Result<usize> {
579 self.backend.dispatch_all_clients(data)
580 }
581}
582
583// Workaround: Some versions of rustc throw a `struct is never constructed`-warning here,
584// if the `server_system`-feature is enabled, even though the `rs`-module makes use if it.
585#[allow(dead_code)]
586pub(crate) struct DumbObjectData;
587
588#[allow(dead_code)]
589impl<D> ObjectData<D> for DumbObjectData {
590 #[cfg_attr(coverage, coverage(off))]
591 fn request(
592 self: Arc<Self>,
593 _handle: &Handle,
594 _data: &mut D,
595 _client_id: ClientId,
596 _msg: Message<ObjectId, OwnedFd>,
597 ) -> Option<Arc<dyn ObjectData<D>>> {
598 unreachable!()
599 }
600
601 #[cfg_attr(coverage, coverage(off))]
602 fn destroyed(
603 self: Arc<Self>,
604 _handle: &Handle,
605 _: &mut D,
606 _client_id: ClientId,
607 _object_id: ObjectId,
608 ) {
609 }
610}