Skip to main content

wayland_server/
display.rs

1use std::{
2    os::unix::io::{AsFd, 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    Client, Resource,
14    global::{GlobalData, GlobalDispatch},
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>(&self, version: u32, data: U) -> GlobalId
127    where
128        State: 'static,
129        U: GlobalDispatch<I, State> + Send + Sync + 'static,
130    {
131        self.handle.create_global::<State>(
132            I::interface(),
133            version,
134            Arc::new(GlobalData { data, _types: std::marker::PhantomData }),
135        )
136    }
137
138    /// Disable this global
139    ///
140    /// Clients will be notified of the global removal, and it will not be advertized to new clients. However
141    /// the state associated with this global is not freed, so clients which already know about it can still
142    /// bind it.
143    pub fn disable_global<State: 'static>(&self, id: GlobalId) {
144        self.handle.disable_global::<State>(id)
145    }
146
147    /// Remove this global
148    ///
149    /// Clients will be notified of the global removal if it was not already disabled. The state associated
150    /// with this global is freed, meaning clients trying to bind it will receive a protocol error.
151    ///
152    /// When removing a global, it is recommended to first disable it using
153    /// [`disable_global()`][Self::disable_global()] to allow some time for clients to register that
154    /// the global is getting removed, to avoid a race where a client would be killed because it bound a global
155    /// at the same as the server decided to remove it. After the global has been disabled for some time (like
156    /// a few seconds) it should be safe to actually remove it.
157    pub fn remove_global<State: 'static>(&self, id: GlobalId) {
158        self.handle.remove_global::<State>(id)
159    }
160
161    /// Access the protocol information for a Wayland object
162    ///
163    /// Returns an error if the object is no longer valid.
164    pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
165        self.handle.object_info(id)
166    }
167
168    /// Send an event to given Wayland object
169    ///
170    /// This is intended to be a low-level method. You can alternatively use the methods on the
171    /// type representing your object, or [`Resource::send_event()`], which may be more convenient.
172    pub fn send_event<I: Resource>(
173        &self,
174        resource: &I,
175        event: I::Event<'_>,
176    ) -> Result<(), InvalidId> {
177        let msg = resource.write_event(self, event)?;
178        self.handle.send_event(msg)
179    }
180
181    /// Trigger a protocol error on this object
182    ///
183    /// This is intended to be a low-level method. See [`Resource::post_error()`], for a more convenient
184    /// method.
185    pub fn post_error<I: Resource>(&self, resource: &I, code: u32, error: String) {
186        self.handle.post_error(resource.id(), code, std::ffi::CString::new(error).unwrap())
187    }
188
189    /// Access the object data associated with this object
190    ///
191    /// This is intended to be a low-level method. See [`Resource::object_data()`], for a more convenient
192    /// method.
193    pub fn get_object_data(
194        &self,
195        id: ObjectId,
196    ) -> Result<Arc<dyn std::any::Any + Send + Sync + 'static>, InvalidId> {
197        self.handle.get_object_data_any(id)
198    }
199
200    /// Flush outgoing buffers into their respective sockets.
201    pub fn flush_clients(&mut self) -> std::io::Result<()> {
202        self.handle.flush(None)
203    }
204
205    /// Set default client maximum buffer size.
206    #[cfg(feature = "libwayland_1_23")]
207    pub fn set_default_max_buffer_size(&self, max_buffer_size: usize) {
208        self.handle.set_default_max_buffer_size(max_buffer_size);
209    }
210}
211
212impl From<Handle> for DisplayHandle {
213    /// Creates a [`DisplayHandle`] using a [`Handle`] from `wayland-backend`.
214    fn from(handle: Handle) -> Self {
215        Self { handle }
216    }
217}