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};
1213use wayland_backend::{
14 client::{Backend, InvalidId, ObjectData, ObjectId, ReadEventsGuard, WaylandError},
15 protocol::{ObjectInfo, ProtocolError},
16};
1718use crate::{protocol::wl_display::WlDisplay, EventQueue, Proxy};
1920/// The Wayland connection
21///
22/// This is the main type representing your connection to the Wayland server, though most of the interaction
23/// with the protocol are actually done using other types. The two main uses a simple app has for the
24/// [`Connection`] are:
25///
26/// - Obtaining the initial [`WlDisplay`] through the [`display()`][Self::display()] method.
27/// - Creating new [`EventQueue`]s with the [`new_event_queue()`][Self::new_event_queue()] method.
28///
29/// It can be created through the [`connect_to_env()`][Self::connect_to_env()] method to follow the
30/// configuration from the environment (which is what you'll do most of the time), or using the
31/// [`from_socket()`][Self::from_socket()] method if you retrieved your connected Wayland socket through
32/// other means.
33///
34/// In case you need to plug yourself into an external Wayland connection that you don't control, you'll
35/// likely get access to it as a [`Backend`], in which case you can create a [`Connection`] from it using
36/// the [`from_backend()`][Self::from_backend()] method.
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Connection {
39pub(crate) backend: Backend,
40}
4142impl Connection {
43/// Try to connect to the Wayland server following the environment
44 ///
45 /// This is the standard way to initialize a Wayland connection.
46pub fn connect_to_env() -> Result<Self, ConnectError> {
47let stream = if let Ok(txt) = env::var("WAYLAND_SOCKET") {
48// We should connect to the provided WAYLAND_SOCKET
49let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
50let fd = unsafe { OwnedFd::from_raw_fd(fd) };
51// remove the variable so any child processes don't see it
52env::remove_var("WAYLAND_SOCKET");
53// set the CLOEXEC flag on this FD
54let flags = rustix::io::fcntl_getfd(&fd);
55let result = flags
56 .map(|f| f | rustix::io::FdFlags::CLOEXEC)
57 .and_then(|f| rustix::io::fcntl_setfd(&fd, f));
58match result {
59Ok(_) => {
60// setting the O_CLOEXEC worked
61UnixStream::from(fd)
62 }
63Err(_) => {
64// something went wrong in F_GETFD or F_SETFD
65return Err(ConnectError::InvalidFd);
66 }
67 }
68 } else {
69let socket_name = env::var_os("WAYLAND_DISPLAY")
70 .map(Into::<PathBuf>::into)
71 .ok_or(ConnectError::NoCompositor)?;
7273let socket_path = if socket_name.is_absolute() {
74 socket_name
75 } else {
76let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
77 .map(Into::<PathBuf>::into)
78 .ok_or(ConnectError::NoCompositor)?;
79if !socket_path.is_absolute() {
80return Err(ConnectError::NoCompositor);
81 }
82 socket_path.push(socket_name);
83 socket_path
84 };
8586 UnixStream::connect(socket_path).map_err(|_| ConnectError::NoCompositor)?
87};
8889let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
90Ok(Self { backend })
91 }
9293/// Initialize a Wayland connection from an already existing Unix stream
94pub fn from_socket(stream: UnixStream) -> Result<Self, ConnectError> {
95let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
96Ok(Self { backend })
97 }
9899/// Get the `WlDisplay` associated with this connection
100pub fn display(&self) -> WlDisplay {
101let display_id = self.backend.display_id();
102 Proxy::from_id(self, display_id).unwrap()
103 }
104105/// Create a new event queue
106pub fn new_event_queue<State>(&self) -> EventQueue<State> {
107 EventQueue::new(self.clone())
108 }
109110/// Wrap an existing [`Backend`] into a [`Connection`]
111pub fn from_backend(backend: Backend) -> Self {
112Self { backend }
113 }
114115/// Get the [`Backend`] underlying this [`Connection`]
116pub fn backend(&self) -> Backend {
117self.backend.clone()
118 }
119120/// Flush pending outgoing events to the server
121 ///
122 /// This needs to be done regularly to ensure the server receives all your requests, though several
123 /// dispatching methods do it implicitly (this is stated in their documentation when they do).
124pub fn flush(&self) -> Result<(), WaylandError> {
125self.backend.flush()
126 }
127128/// Start a synchronized read from the socket
129 ///
130 /// This is needed if you plan to wait on readiness of the Wayland socket using an event loop. See
131 /// [`ReadEventsGuard`] for details. Once the events are received, you'll then need to dispatch them from
132 /// their event queues using [`EventQueue::dispatch_pending()`].
133 ///
134 /// If you don't need to manage multiple event sources, see
135 /// [`EventQueue::blocking_dispatch()`] for a simpler mechanism.
136#[must_use]
137pub fn prepare_read(&self) -> Option<ReadEventsGuard> {
138self.backend.prepare_read()
139 }
140141/// Do a roundtrip to the server
142 ///
143 /// This method will block until the Wayland server has processed and answered all your
144 /// preceding requests. This is notably useful during the initial setup of an app, to wait for
145 /// the initial state from the server.
146 ///
147 /// See [`EventQueue::roundtrip()`] for a version that includes the dispatching of the event queue.
148pub fn roundtrip(&self) -> Result<usize, WaylandError> {
149let done = Arc::new(SyncData::default());
150let display = self.display();
151self.send_request(
152&display,
153crate::protocol::wl_display::Request::Sync {},
154Some(done.clone()),
155 )
156 .map_err(|_| WaylandError::Io(rustix::io::Errno::PIPE.into()))?;
157158let mut dispatched = 0;
159160loop {
161self.backend.flush()?;
162163if let Some(guard) = self.backend.prepare_read() {
164 dispatched += blocking_read(guard)?;
165 } else {
166 dispatched += self.backend.dispatch_inner_queue()?;
167 }
168169// see if the successful read included our callback
170if done.done.load(Ordering::Relaxed) {
171break;
172 }
173 }
174175Ok(dispatched)
176 }
177178/// Retrieve the protocol error that occured on the connection if any
179 ///
180 /// If this method returns [`Some`], it means your Wayland connection is already dead.
181pub fn protocol_error(&self) -> Option<ProtocolError> {
182match self.backend.last_error()? {
183 WaylandError::Protocol(err) => Some(err),
184 WaylandError::Io(_) => None,
185 }
186 }
187188/// Send a request associated with the provided object
189 ///
190 /// This is a low-level interface used by the code generated by `wayland-scanner`, you will likely
191 /// instead use the methods of the types representing each interface, or the [`Proxy::send_request()`] and
192 /// [`Proxy::send_constructor()`].
193pub fn send_request<I: Proxy>(
194&self,
195 proxy: &I,
196 request: I::Request<'_>,
197 data: Option<Arc<dyn ObjectData>>,
198 ) -> Result<ObjectId, InvalidId> {
199let (msg, child_spec) = proxy.write_request(self, request)?;
200let msg = msg.map_fd(|fd| fd.as_raw_fd());
201self.backend.send_request(msg, data, child_spec)
202 }
203204/// Get the protocol information related to given object ID
205pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
206self.backend.info(id)
207 }
208209/// Get the object data for a given object ID
210 ///
211 /// This is a low-level interface used by the code generated by `wayland-scanner`, a higher-level
212 /// interface for manipulating the user-data assocated to [`Dispatch`][crate::Dispatch] implementations
213 /// is given as [`Proxy::data()`]. Also see [`Proxy::object_data()`].
214pub fn get_object_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
215self.backend.get_data(id)
216 }
217}
218219pub(crate) fn blocking_read(guard: ReadEventsGuard) -> Result<usize, WaylandError> {
220let fd = guard.connection_fd();
221let mut fds = [rustix::event::PollFd::new(
222&fd,
223 rustix::event::PollFlags::IN | rustix::event::PollFlags::ERR,
224 )];
225226loop {
227match rustix::event::poll(&mut fds, -1) {
228Ok(_) => break,
229Err(rustix::io::Errno::INTR) => continue,
230Err(e) => return Err(WaylandError::Io(e.into())),
231 }
232 }
233234// at this point the fd is ready
235match guard.read() {
236Ok(n) => Ok(n),
237// if we are still "wouldblock", just return 0; the caller will retry.
238Err(WaylandError::Io(e)) if e.kind() == ErrorKind::WouldBlock => Ok(0),
239Err(e) => Err(e),
240 }
241}
242243/// An error when trying to establish a Wayland connection.
244#[derive(Debug)]
245pub enum ConnectError {
246/// The wayland library could not be loaded.
247NoWaylandLib,
248249/// Could not find wayland compositor
250NoCompositor,
251252/// `WAYLAND_SOCKET` was set but contained garbage
253InvalidFd,
254}
255256impl std::error::Error for ConnectError {}
257258impl fmt::Display for ConnectError {
259fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260match self {
261 ConnectError::NoWaylandLib => {
262write!(f, "The wayland library could not be loaded")
263 }
264 ConnectError::NoCompositor => {
265write!(f, "Could not find wayland compositor")
266 }
267 ConnectError::InvalidFd => {
268write!(f, "WAYLAND_SOCKET was set but contained garbage")
269 }
270 }
271 }
272}
273274impl AsFd for Connection {
275/// Provides fd from [`Backend::poll_fd()`] for polling.
276fn as_fd(&self) -> BorrowedFd<'_> {
277self.backend.poll_fd()
278 }
279}
280281/*
282 wl_callback object data for wl_display.sync
283*/
284285#[derive(Default)]
286pub(crate) struct SyncData {
287pub(crate) done: AtomicBool,
288}
289290impl ObjectData for SyncData {
291fn event(
292self: Arc<Self>,
293 _handle: &Backend,
294 _msg: wayland_backend::protocol::Message<ObjectId, OwnedFd>,
295 ) -> Option<Arc<dyn ObjectData>> {
296self.done.store(true, Ordering::Relaxed);
297None
298}
299300fn destroyed(&self, _: ObjectId) {}
301}