wayland_server/
display.rs

1use std::{
2    os::unix::io::{AsFd, AsRawFd, BorrowedFd},
3    os::unix::net::UnixStream,
4    sync::Arc,
5};
6
7use wayland_backend::{
8    protocol::ObjectInfo,
9    server::{Backend, ClientData, GlobalId, Handle, InitError, InvalidId, ObjectId},
10};
11
12use crate::{
13    global::{GlobalData, GlobalDispatch},
14    Client, Resource,
15};
16
17/// The Wayland display
18///
19/// This struct is the core of your Wayland compositor. You'll use it in your event loop to drive the
20/// protocol processing of all your clients. All other interactions with the protocol itself are done
21/// through the [`DisplayHandle`] struct, on which the `State` type parameter is erased for convenience.
22///
23/// ## Usage
24///
25/// The main loop of a Wayland compositor generally needs to wait on several sources of events, using
26/// tools like `epoll` (on Linux). The Wayland display can be integrated in this mechanism by getting the
27/// file descriptor as from [`.backend()`][Self::backend()][`.poll_fd()`][Backend::poll_fd()] and invoking
28/// the [`dispatch_clients()`][Self::dispatch_clients()] method whenever it becomes readable.
29///
30/// To ensure all clients receive the events your compositor sends them, you also need to regularly invoke
31/// the [`flush_clients()`][Self::flush_clients()] method, which will write the outgoing buffers into the
32/// sockets.
33#[derive(Debug)]
34pub struct Display<State: 'static> {
35    backend: Backend<State>,
36}
37
38impl<State: 'static> Display<State> {
39    /// Create a new Wayland display
40    ///
41    /// Can only fail if both the `server_system` and `dlopen` features of `wayland-backend` were enabled,
42    /// and the `libwayland-server.so` library could not be found.
43    pub fn new() -> Result<Display<State>, InitError> {
44        Ok(Display { backend: Backend::new()? })
45    }
46
47    /// Retrieve a [`DisplayHandle`] for this [`Display`].
48    ///
49    /// This is the type with which all of your interactions with the Wayland protocol are done.
50    pub fn handle(&self) -> DisplayHandle {
51        DisplayHandle { handle: self.backend.handle() }
52    }
53
54    /// Dispatch all requests received from clients to their respective callbacks.
55    ///
56    /// The `state` argument is the main state of your compositor, which will be accessible from most of your
57    /// callbacks.
58    pub fn dispatch_clients(&mut self, state: &mut State) -> std::io::Result<usize> {
59        self.backend.dispatch_all_clients(state)
60    }
61
62    /// Flush outgoing buffers into their respective sockets.
63    pub fn flush_clients(&mut self) -> std::io::Result<()> {
64        self.backend.flush(None)
65    }
66
67    /// Access the underlying [`Backend`] of this [`Display`]
68    pub fn backend(&mut self) -> &mut Backend<State> {
69        &mut self.backend
70    }
71}
72
73impl<State> AsFd for Display<State> {
74    /// Provides fd from [`Backend::poll_fd`] for polling.
75    fn as_fd(&self) -> BorrowedFd<'_> {
76        self.backend.poll_fd()
77    }
78}
79
80/// A handle to the Wayland display
81///
82/// A display handle may be constructed from a [`Handle`] using it's [`From`] implementation.
83#[derive(Clone)]
84pub struct DisplayHandle {
85    pub(crate) handle: Handle,
86}
87
88impl std::fmt::Debug for DisplayHandle {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        f.debug_struct("DisplayHandle").finish_non_exhaustive()
91    }
92}
93
94impl DisplayHandle {
95    /// Returns the underlying [`Handle`] from `wayland-backend`.
96    pub fn backend_handle(&self) -> Handle {
97        self.handle.clone()
98    }
99
100    /// Insert a new client in your [`Display`]
101    ///
102    /// This client will be associated with the provided [`ClientData`], that you can then retrieve from
103    /// it via [`Client::get_data()`], and its requests will be processed by the [`Display`] and your
104    /// callbacks.
105    pub fn insert_client(
106        &mut self,
107        stream: UnixStream,
108        data: Arc<dyn ClientData>,
109    ) -> std::io::Result<Client> {
110        let id = self.handle.insert_client(stream, data.clone())?;
111        Ok(Client { id, data })
112    }
113
114    /// Retrieve the [`Client`] which owns the object represented by the given ID
115    pub fn get_client(&self, id: ObjectId) -> Result<Client, InvalidId> {
116        let client_id = self.handle.get_client(id)?;
117        Client::from_id(self, client_id)
118    }
119
120    /// Create a new protocol global
121    ///
122    /// This global will be advertized to clients through the `wl_registry` according to the rules
123    /// defined by your [`GlobalDispatch`] implementation for the given interface. Whenever a client
124    /// binds this global, the associated [`GlobalDispatch::bind()`] method will be invoked on your
125    /// `State`.
126    pub fn create_global<State, I: Resource + 'static, U: Send + Sync + 'static>(
127        &self,
128        version: u32,
129        data: U,
130    ) -> GlobalId
131    where
132        State: GlobalDispatch<I, U> + 'static,
133    {
134        self.handle.create_global::<State>(
135            I::interface(),
136            version,
137            Arc::new(GlobalData { data, _types: std::marker::PhantomData }),
138        )
139    }
140
141    /// Disable this global
142    ///
143    /// Clients will be notified of the global removal, and it will not be advertized to new clients. However
144    /// the state associated with this global is not freed, so clients which already know about it can still
145    /// bind it.
146    pub fn disable_global<State: 'static>(&self, id: GlobalId) {
147        self.handle.disable_global::<State>(id)
148    }
149
150    /// Remove this global
151    ///
152    /// Clients will be notified of the global removal if it was not already disabled. The state associated
153    /// with this global is freed, meaning clients trying to bind it will receive a protocol error.
154    ///
155    /// When removing a global, it is recommended to first disable it using
156    /// [`disable_global()`][Self::disable_global()] to allow some time for clients to register that
157    /// the global is getting removed, to avoid a race where a client would be killed because it bound a global
158    /// at the same as the server decided to remove it. After the global has been disabled for some time (like
159    /// a few seconds) it should be safe to actually remove it.
160    pub fn remove_global<State: 'static>(&self, id: GlobalId) {
161        self.handle.remove_global::<State>(id)
162    }
163
164    /// Access the protocol information for a Wayland object
165    ///
166    /// Returns an error if the object is no longer valid.
167    pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
168        self.handle.object_info(id)
169    }
170
171    /// Send an event to given Wayland object
172    ///
173    /// This is intended to be a low-level method. You can alternatively use the methods on the
174    /// type representing your object, or [`Resource::send_event()`], which may be more convenient.
175    pub fn send_event<I: Resource>(
176        &self,
177        resource: &I,
178        event: I::Event<'_>,
179    ) -> Result<(), InvalidId> {
180        let msg = resource.write_event(self, event)?;
181        let msg = msg.map_fd(|fd| fd.as_raw_fd());
182        self.handle.send_event(msg)
183    }
184
185    /// Trigger a protocol error on this object
186    ///
187    /// This is intended to be a low-level method. See [`Resource::post_error()`], for a more convenient
188    /// method.
189    pub fn post_error<I: Resource>(&self, resource: &I, code: u32, error: String) {
190        self.handle.post_error(resource.id(), code, std::ffi::CString::new(error).unwrap())
191    }
192
193    /// Access the object data associated with this object
194    ///
195    /// This is intended to be a low-level method. See [`Resource::object_data()`], for a more convenient
196    /// method.
197    pub fn get_object_data(
198        &self,
199        id: ObjectId,
200    ) -> Result<Arc<dyn std::any::Any + Send + Sync + 'static>, InvalidId> {
201        self.handle.get_object_data_any(id)
202    }
203
204    /// Flush outgoing buffers into their respective sockets.
205    pub fn flush_clients(&mut self) -> std::io::Result<()> {
206        self.handle.flush(None)
207    }
208}
209
210impl From<Handle> for DisplayHandle {
211    /// Creates a [`DisplayHandle`] using a [`Handle`] from `wayland-backend`.
212    fn from(handle: Handle) -> Self {
213        Self { handle }
214    }
215}