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