1use rustix::{
7 fd::{FromRawFd, OwnedFd},
8 net::AddressFamily,
9};
10use types::ObjectId;
11
12mod wayland;
13
14pub use bitflags;
15pub use rustix;
16pub mod objman;
17pub mod shm;
18pub mod types;
19pub mod wire;
20
21pub use wire::Error;
22
23pub struct Waybackend {
27 pub wire_msg_builder: wire::MessageBuilder,
29 pub wayland_fd: OwnedFd,
31}
32
33impl Waybackend {
34 #[inline]
35 #[must_use]
36 fn new(wayland_fd: OwnedFd) -> Self {
37 Self {
38 wire_msg_builder: wire::MessageBuilder::new(),
39 wayland_fd,
40 }
41 }
42
43 #[inline]
44 pub fn flush(&mut self) -> Result<(), wire::Error> {
45 self.wire_msg_builder.flush(&self.wayland_fd)
46 }
47}
48
49use std::{num::NonZeroU32, path::PathBuf};
50
51pub const WL_DISPLAY: types::ObjectId = types::ObjectId::new(NonZeroU32::new(1).unwrap());
53
54#[derive(Debug)]
55pub enum ConnectionError {
56 InvalidWaylandSocketEnvVar,
57 InvalidSocketAddrFamily(rustix::net::AddressFamily),
58 GetSocketNameFailed(rustix::io::Errno),
59 SocketCreationFailed(rustix::io::Errno),
60 ConnectionFailed(rustix::io::Errno),
61}
62
63impl std::fmt::Display for ConnectionError {
64 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
65 match self {
66 ConnectionError::InvalidWaylandSocketEnvVar => write!(
67 f,
68 "WAYLAND_SOCKET environment variable contains a value we failed to parse"
69 ),
70 ConnectionError::InvalidSocketAddrFamily(actual) => write!(
71 f,
72 "socket address in WAYLAND_SOCKET is not a unix socket. It's actual address family is: {actual:?}"
73 ),
74 ConnectionError::GetSocketNameFailed(errno) => {
75 write!(f, "failed to get socket name: {errno}")
76 }
77 ConnectionError::SocketCreationFailed(errno) => {
78 write!(f, "failed to create socket: {errno}")
79 }
80 ConnectionError::ConnectionFailed(errno) => {
81 write!(f, "failed to connect to the unix stream: {errno}")
82 }
83 }
84 }
85}
86
87impl std::error::Error for ConnectionError {}
88
89#[inline]
98pub fn connect() -> Result<Waybackend, ConnectionError> {
99 if let Ok(txt) = std::env::var("WAYLAND_SOCKET") {
100 let fd = txt
102 .parse::<i32>()
103 .map_err(|_| ConnectionError::InvalidWaylandSocketEnvVar)?;
104 let fd = unsafe { OwnedFd::from_raw_fd(fd) };
105
106 match rustix::net::getsockname(&fd) {
107 Ok(socket_addr) => {
108 if socket_addr.address_family() == AddressFamily::UNIX {
109 Ok(Waybackend::new(fd))
110 } else {
111 Err(ConnectionError::InvalidSocketAddrFamily(
112 socket_addr.address_family(),
113 ))
114 }
115 }
116 Err(e) => Err(ConnectionError::GetSocketNameFailed(e)),
117 }
118 } else {
119 let socket_name: PathBuf = std::env::var_os("WAYLAND_DISPLAY")
120 .unwrap_or_else(|| {
121 log::warn!("WAYLAND_DISPLAY is not set! Defaulting to wayland-0");
122 std::ffi::OsString::from("wayland-0")
123 })
124 .into();
125
126 let socket_path = if socket_name.is_absolute() {
127 socket_name
128 } else {
129 let mut socket_path: PathBuf = std::env::var_os("XDG_RUNTIME_DIR")
130 .unwrap_or_else(|| {
131 log::warn!("XDG_RUNTIME_DIR is not set! Defaulting to /run/user/UID");
132 let uid = rustix::process::getuid();
133 let mut p: PathBuf = ["run", "user"].iter().collect();
134 p.push(format!("{}", uid.as_raw()));
135 p.into_os_string()
136 })
137 .into();
138
139 socket_path.push(socket_name);
140 socket_path
141 };
142
143 let unix_addr =
144 rustix::net::SocketAddrUnix::new(socket_path.display().to_string().as_str()).unwrap();
145 let socket = rustix::net::socket_with(
146 rustix::net::AddressFamily::UNIX,
147 rustix::net::SocketType::STREAM,
148 rustix::net::SocketFlags::CLOEXEC,
149 None,
150 )
151 .map_err(ConnectionError::SocketCreationFailed)?;
152
153 rustix::net::connect(&socket, &unix_addr).map_err(ConnectionError::ConnectionFailed)?;
154 Ok(Waybackend::new(socket))
155 }
156}
157
158#[derive(Debug)]
159pub enum RoundtripError {
160 WireError(wire::Error),
161 WaylandError((ObjectId, u32, String)),
162 MessageFromUnknownObject(ObjectId),
163 UnexpectedDeleteId(u32),
164}
165
166impl std::fmt::Display for RoundtripError {
167 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
168 match self {
169 RoundtripError::WireError(error) => {
170 write!(f, "roundtrip failed due to wayland wire error: {error}")
171 }
172 RoundtripError::MessageFromUnknownObject(id) => {
173 write!(f, "received message from unknown object of id: {id}")
174 }
175 RoundtripError::UnexpectedDeleteId(id) => {
176 write!(
177 f,
178 "Received a delete_id message from the display for id: {id}.\n\
179 This should never happen during the roundtrip initialization.\n\
180 This wayland implementation is probably fucked."
181 )
182 }
183 RoundtripError::WaylandError((id, code, msg)) => write!(
184 f,
185 "Wayland protocol error. Object: {id}. Code: {code}. Message: {msg}"
186 ),
187 }
188 }
189}
190
191impl std::error::Error for RoundtripError {}
192
193#[derive(Debug)]
194pub struct Global {
196 name: u32,
197 interface: String,
198 version: u32,
199}
200
201impl Global {
202 #[inline]
203 pub fn name(&self) -> u32 {
204 self.name
205 }
206
207 #[inline]
208 pub fn interface(&self) -> &str {
209 &self.interface
210 }
211
212 #[inline]
213 pub fn version(&self) -> u32 {
214 self.version
215 }
216
217 #[inline]
218 pub fn bind<T: Copy + PartialEq>(
219 &self,
220 backend: &mut crate::Waybackend,
221 registry: ObjectId,
222 objman: &mut objman::ObjectManager<T>,
223 object: T,
224 ) -> Result<(), wire::Error> {
225 let id = objman.create(object);
226 wayland::wl_registry::req::bind(
227 backend,
228 registry,
229 self.name,
230 id,
231 &self.interface,
232 self.version,
233 )
234 }
235}
236
237struct GlobalHandler {
238 globals: Vec<Global>,
239 error: Option<RoundtripError>,
240 done: bool,
241 delete_callback: bool,
242}
243
244impl GlobalHandler {
245 fn new() -> Self {
246 Self {
247 globals: Vec::new(),
248 error: None,
249 done: false,
250 delete_callback: false,
251 }
252 }
253}
254
255impl wayland::wl_display::EvHandler for GlobalHandler {
256 fn error(&mut self, _: ObjectId, object_id: ObjectId, code: u32, message: &str) {
257 self.error = Some(RoundtripError::WaylandError((
258 object_id,
259 code,
260 message.to_string(),
261 )));
262 }
263
264 fn delete_id(&mut self, _: ObjectId, id: u32) {
265 if id != 3 {
266 self.error = Some(RoundtripError::UnexpectedDeleteId(id));
267 } else {
268 self.delete_callback = true;
269 }
270 }
271}
272
273impl wayland::wl_registry::EvHandler for GlobalHandler {
274 fn global(&mut self, _: ObjectId, name: u32, interface: &str, version: u32) {
275 self.globals.push(Global {
276 name,
277 interface: interface.to_string(),
278 version,
279 });
280 }
281
282 fn global_remove(&mut self, _: ObjectId, name: u32) {
283 self.globals.retain(|g| g.name != name)
284 }
285}
286
287impl wayland::wl_callback::EvHandler for GlobalHandler {
288 fn done(&mut self, _: ObjectId, _: u32) {
289 self.done = true;
290 }
291}
292
293#[inline]
298pub fn roundtrip(
299 backend: &mut Waybackend,
300 receiver: &mut wire::Receiver,
301 registry_id: ObjectId,
302 callback_id: ObjectId,
303) -> Result<(Vec<Global>, bool), RoundtripError> {
304 let mut global_handler = GlobalHandler::new();
305 wayland::wl_display::req::get_registry(backend, WL_DISPLAY, registry_id)
306 .map_err(RoundtripError::WireError)?;
307 wayland::wl_display::req::sync(backend, WL_DISPLAY, callback_id)
308 .map_err(RoundtripError::WireError)?;
309 backend.flush().map_err(RoundtripError::WireError)?;
310
311 while !global_handler.done && global_handler.error.is_none() {
312 let mut msg = receiver
313 .recv(&backend.wayland_fd)
314 .map_err(RoundtripError::WireError)?;
315 while msg.has_next().map_err(RoundtripError::WireError)? {
316 match msg.sender_id() {
317 WL_DISPLAY => wayland::wl_display::event(&mut global_handler, &mut msg)
318 .map_err(RoundtripError::WireError)?,
319 id if id == registry_id => {
320 wayland::wl_registry::event(&mut global_handler, &mut msg)
321 .map_err(RoundtripError::WireError)?
322 }
323 id if id == callback_id => {
324 wayland::wl_callback::event(&mut global_handler, &mut msg)
325 .map_err(RoundtripError::WireError)?
326 }
327 otherwise => return Err(RoundtripError::MessageFromUnknownObject(otherwise)),
328 }
329 }
330 }
331
332 if let Some(error) = global_handler.error {
333 return Err(error);
334 }
335
336 Ok((global_handler.globals, global_handler.delete_callback))
337}
338
339#[macro_export]
340macro_rules! bind_globals {
341 (
342 $backend:ident,
343 $objman:ident,
344 $registry:ident,
345 $globals:ident,
346 $(($interface:ident, $object:path)),*$(,)?
347 ) => {
348 for global in $globals.iter() {
349 match global.interface() {
350 $($interface::NAME => global.bind(&mut $backend, $registry, &mut $objman, $object)?),*,
351 _ => (),
352 }
353 }
354 }
355}