1use std::{
2 env, fmt,
3 io::ErrorKind,
4 os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd},
5 os::unix::net::UnixStream,
6 path::PathBuf,
7 sync::{
8 atomic::{AtomicBool, Ordering},
9 Arc,
10 },
11};
12
13use wayland_backend::{
14 client::{Backend, InvalidId, ObjectData, ObjectId, ReadEventsGuard, WaylandError},
15 protocol::{ObjectInfo, ProtocolError},
16};
17
18use crate::{protocol::wl_display::WlDisplay, EventQueue, Proxy};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Connection {
39 pub(crate) backend: Backend,
40}
41
42impl Connection {
43 pub fn connect_to_env() -> Result<Self, ConnectError> {
47 let stream = if let Ok(txt) = env::var("WAYLAND_SOCKET") {
48 let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
50 let fd = unsafe { OwnedFd::from_raw_fd(fd) };
51 env::remove_var("WAYLAND_SOCKET");
53 let flags = rustix::io::fcntl_getfd(&fd);
55 let result = flags
56 .map(|f| f | rustix::io::FdFlags::CLOEXEC)
57 .and_then(|f| rustix::io::fcntl_setfd(&fd, f));
58 match result {
59 Ok(_) => {
60 UnixStream::from(fd)
62 }
63 Err(_) => {
64 return Err(ConnectError::InvalidFd);
66 }
67 }
68 } else {
69 let socket_name = env::var_os("WAYLAND_DISPLAY")
70 .map(Into::<PathBuf>::into)
71 .ok_or(ConnectError::NoCompositor)?;
72
73 let socket_path = if socket_name.is_absolute() {
74 socket_name
75 } else {
76 let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
77 .map(Into::<PathBuf>::into)
78 .ok_or(ConnectError::NoCompositor)?;
79 if !socket_path.is_absolute() {
80 return Err(ConnectError::NoCompositor);
81 }
82 socket_path.push(socket_name);
83 socket_path
84 };
85
86 UnixStream::connect(socket_path).map_err(|_| ConnectError::NoCompositor)?
87 };
88
89 let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
90 Ok(Self { backend })
91 }
92
93 pub fn from_socket(stream: UnixStream) -> Result<Self, ConnectError> {
95 let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
96 Ok(Self { backend })
97 }
98
99 pub fn display(&self) -> WlDisplay {
101 let display_id = self.backend.display_id();
102 Proxy::from_id(self, display_id).unwrap()
103 }
104
105 pub fn new_event_queue<State>(&self) -> EventQueue<State> {
107 EventQueue::new(self.clone())
108 }
109
110 pub fn from_backend(backend: Backend) -> Self {
112 Self { backend }
113 }
114
115 pub fn backend(&self) -> Backend {
117 self.backend.clone()
118 }
119
120 pub fn flush(&self) -> Result<(), WaylandError> {
125 self.backend.flush()
126 }
127
128 #[must_use]
137 pub fn prepare_read(&self) -> Option<ReadEventsGuard> {
138 self.backend.prepare_read()
139 }
140
141 pub fn roundtrip(&self) -> Result<usize, WaylandError> {
149 let done = Arc::new(SyncData::default());
150 let display = self.display();
151 self.send_request(
152 &display,
153 crate::protocol::wl_display::Request::Sync {},
154 Some(done.clone()),
155 )
156 .map_err(|_| WaylandError::Io(rustix::io::Errno::PIPE.into()))?;
157
158 let mut dispatched = 0;
159
160 loop {
161 self.backend.flush()?;
162
163 if let Some(guard) = self.backend.prepare_read() {
164 dispatched += blocking_read(guard)?;
165 } else {
166 dispatched += self.backend.dispatch_inner_queue()?;
167 }
168
169 if done.done.load(Ordering::Relaxed) {
171 break;
172 }
173 }
174
175 Ok(dispatched)
176 }
177
178 pub fn protocol_error(&self) -> Option<ProtocolError> {
182 match self.backend.last_error()? {
183 WaylandError::Protocol(err) => Some(err),
184 WaylandError::Io(_) => None,
185 }
186 }
187
188 pub fn send_request<I: Proxy>(
194 &self,
195 proxy: &I,
196 request: I::Request<'_>,
197 data: Option<Arc<dyn ObjectData>>,
198 ) -> Result<ObjectId, InvalidId> {
199 let (msg, child_spec) = proxy.write_request(self, request)?;
200 let msg = msg.map_fd(|fd| fd.as_raw_fd());
201 self.backend.send_request(msg, data, child_spec)
202 }
203
204 pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
206 self.backend.info(id)
207 }
208
209 pub fn get_object_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
215 self.backend.get_data(id)
216 }
217
218 #[cfg(feature = "libwayland_1_23")]
220 pub fn set_max_buffer_size(&self, max_buffer_size: Option<usize>) {
221 self.backend.set_max_buffer_size(max_buffer_size);
222 }
223}
224
225pub(crate) fn blocking_read(guard: ReadEventsGuard) -> Result<usize, WaylandError> {
226 let fd = guard.connection_fd();
227 let mut fds = [rustix::event::PollFd::new(
228 &fd,
229 rustix::event::PollFlags::IN | rustix::event::PollFlags::ERR,
230 )];
231
232 loop {
233 match rustix::event::poll(&mut fds, None) {
234 Ok(_) => break,
235 Err(rustix::io::Errno::INTR) => continue,
236 Err(e) => return Err(WaylandError::Io(e.into())),
237 }
238 }
239
240 match guard.read() {
242 Ok(n) => Ok(n),
243 Err(WaylandError::Io(e)) if e.kind() == ErrorKind::WouldBlock => Ok(0),
245 Err(e) => Err(e),
246 }
247}
248
249#[derive(Debug)]
251pub enum ConnectError {
252 NoWaylandLib,
254
255 NoCompositor,
257
258 InvalidFd,
260}
261
262impl std::error::Error for ConnectError {}
263
264impl fmt::Display for ConnectError {
265 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266 match self {
267 ConnectError::NoWaylandLib => {
268 write!(f, "The wayland library could not be loaded")
269 }
270 ConnectError::NoCompositor => {
271 write!(f, "Could not find wayland compositor")
272 }
273 ConnectError::InvalidFd => {
274 write!(f, "WAYLAND_SOCKET was set but contained garbage")
275 }
276 }
277 }
278}
279
280impl AsFd for Connection {
281 fn as_fd(&self) -> BorrowedFd<'_> {
283 self.backend.poll_fd()
284 }
285}
286
287#[derive(Default)]
292pub(crate) struct SyncData {
293 pub(crate) done: AtomicBool,
294}
295
296impl ObjectData for SyncData {
297 fn event(
298 self: Arc<Self>,
299 _handle: &Backend,
300 _msg: wayland_backend::protocol::Message<ObjectId, OwnedFd>,
301 ) -> Option<Arc<dyn ObjectData>> {
302 self.done.store(true, Ordering::Relaxed);
303 None
304 }
305
306 fn destroyed(&self, _: ObjectId) {}
307}