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}