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