| 1 | // SPDX-License-Identifier: MIT |
| 2 | |
| 3 | //! Utilities for using an [`EventQueue`] from wayland-client with an event loop |
| 4 | //! that performs polling with [`calloop`](https://crates.io/crates/calloop). |
| 5 | //! |
| 6 | //! # Example |
| 7 | //! |
| 8 | //! ```no_run,rust |
| 9 | //! use calloop::EventLoop; |
| 10 | //! use calloop_wayland_source::WaylandSource; |
| 11 | //! use wayland_client::{Connection, QueueHandle}; |
| 12 | //! |
| 13 | //! // Create a Wayland connection and a queue. |
| 14 | //! let connection = Connection::connect_to_env().unwrap(); |
| 15 | //! let event_queue = connection.new_event_queue(); |
| 16 | //! let queue_handle = event_queue.handle(); |
| 17 | //! |
| 18 | //! // Create the calloop event loop to drive everytihng. |
| 19 | //! let mut event_loop: EventLoop<()> = EventLoop::try_new().unwrap(); |
| 20 | //! let loop_handle = event_loop.handle(); |
| 21 | //! |
| 22 | //! // Insert the wayland source into the calloop's event loop. |
| 23 | //! WaylandSource::new(connection, event_queue).insert(loop_handle).unwrap(); |
| 24 | //! |
| 25 | //! // This will start dispatching the event loop and processing pending wayland requests. |
| 26 | //! while let Ok(_) = event_loop.dispatch(None, &mut ()) { |
| 27 | //! // Your logic here. |
| 28 | //! } |
| 29 | //! ``` |
| 30 | |
| 31 | #![deny (unsafe_op_in_unsafe_fn)] |
| 32 | use std::io; |
| 33 | |
| 34 | use calloop::generic::Generic; |
| 35 | use calloop::{ |
| 36 | EventSource, InsertError, Interest, LoopHandle, Mode, Poll, PostAction, Readiness, |
| 37 | RegistrationToken, Token, TokenFactory, |
| 38 | }; |
| 39 | use rustix::io::Errno; |
| 40 | use wayland_backend::client::{ReadEventsGuard, WaylandError}; |
| 41 | use wayland_client::{Connection, DispatchError, EventQueue}; |
| 42 | |
| 43 | #[cfg (feature = "log" )] |
| 44 | use log::error as log_error; |
| 45 | #[cfg (not(feature = "log" ))] |
| 46 | use std::eprintln as log_error; |
| 47 | |
| 48 | /// An adapter to insert an [`EventQueue`] into a calloop |
| 49 | /// [`EventLoop`](calloop::EventLoop). |
| 50 | /// |
| 51 | /// This type implements [`EventSource`] which generates an event whenever |
| 52 | /// events on the event queue need to be dispatched. The event queue available |
| 53 | /// in the callback calloop registers may be used to dispatch pending |
| 54 | /// events using [`EventQueue::dispatch_pending`]. |
| 55 | /// |
| 56 | /// [`WaylandSource::insert`] can be used to insert this source into an event |
| 57 | /// loop and automatically dispatch pending events on the event queue. |
| 58 | #[derive (Debug)] |
| 59 | pub struct WaylandSource<D> { |
| 60 | // In theory, we could use the same event queue inside `connection_source` |
| 61 | // However, calloop's safety requirements mean that we cannot then give |
| 62 | // mutable access to the queue, which is incompatible with our current interface |
| 63 | // Additionally, `Connection` is cheaply cloneable, so it's not a huge burden |
| 64 | queue: EventQueue<D>, |
| 65 | connection_source: Generic<Connection>, |
| 66 | read_guard: Option<ReadEventsGuard>, |
| 67 | /// Calloop's before_will_sleep method allows |
| 68 | /// skipping the sleeping by returning a `Token`. |
| 69 | /// We cannot produce this on the fly, so store it here instead |
| 70 | fake_token: Option<Token>, |
| 71 | // Some calloop event handlers don't support error handling, so we have to store the error |
| 72 | // for a short time until we reach a method which allows it |
| 73 | stored_error: Result<(), io::Error>, |
| 74 | } |
| 75 | |
| 76 | impl<D> WaylandSource<D> { |
| 77 | /// Wrap an [`EventQueue`] as a [`WaylandSource`]. |
| 78 | /// |
| 79 | /// `queue` must be from the connection `Connection`. |
| 80 | /// This is not a safety invariant, but not following this may cause |
| 81 | /// freezes or hangs |
| 82 | pub fn new(connection: Connection, queue: EventQueue<D>) -> WaylandSource<D> { |
| 83 | let connection_source = Generic::new(connection, Interest::READ, Mode::Level); |
| 84 | |
| 85 | WaylandSource { |
| 86 | queue, |
| 87 | connection_source, |
| 88 | read_guard: None, |
| 89 | fake_token: None, |
| 90 | stored_error: Ok(()), |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | /// Access the underlying event queue |
| 95 | /// |
| 96 | /// Note that you should not replace this queue with a queue from a |
| 97 | /// different `Connection`, as that may cause freezes or other hangs. |
| 98 | pub fn queue(&mut self) -> &mut EventQueue<D> { |
| 99 | &mut self.queue |
| 100 | } |
| 101 | |
| 102 | /// Access the connection to the Wayland server |
| 103 | pub fn connection(&self) -> &Connection { |
| 104 | self.connection_source.get_ref() |
| 105 | } |
| 106 | |
| 107 | /// Insert this source into the given event loop. |
| 108 | /// |
| 109 | /// This adapter will pass the event loop's shared data as the `D` type for |
| 110 | /// the event loop. |
| 111 | pub fn insert(self, handle: LoopHandle<D>) -> Result<RegistrationToken, InsertError<Self>> |
| 112 | where |
| 113 | D: 'static, |
| 114 | { |
| 115 | handle.insert_source(self, |_, queue, data| queue.dispatch_pending(data)) |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | impl<D> EventSource for WaylandSource<D> { |
| 120 | type Error = calloop::Error; |
| 121 | type Event = (); |
| 122 | /// The underlying event queue. |
| 123 | /// |
| 124 | /// You should call [`EventQueue::dispatch_pending`] inside your callback |
| 125 | /// using this queue. |
| 126 | type Metadata = EventQueue<D>; |
| 127 | type Ret = Result<usize, DispatchError>; |
| 128 | |
| 129 | const NEEDS_EXTRA_LIFECYCLE_EVENTS: bool = true; |
| 130 | |
| 131 | fn process_events<F>( |
| 132 | &mut self, |
| 133 | _: Readiness, |
| 134 | _: Token, |
| 135 | mut callback: F, |
| 136 | ) -> Result<PostAction, Self::Error> |
| 137 | where |
| 138 | F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, |
| 139 | { |
| 140 | debug_assert!(self.read_guard.is_none()); |
| 141 | |
| 142 | // Take the stored error |
| 143 | std::mem::replace(&mut self.stored_error, Ok(()))?; |
| 144 | |
| 145 | // We know that the event will either be a fake event |
| 146 | // produced in `before_will_sleep`, or a "real" event from the underlying |
| 147 | // source (self.queue_events). Our behaviour in both cases is the same. |
| 148 | // In theory we might want to call the process_events handler on the underlying |
| 149 | // event source. However, we know that Generic's `process_events` call is a |
| 150 | // no-op, so we just handle the event ourselves. |
| 151 | |
| 152 | let queue = &mut self.queue; |
| 153 | // Dispatch any pending events in the queue |
| 154 | Self::loop_callback_pending(queue, &mut callback)?; |
| 155 | |
| 156 | // Once dispatching is finished, flush the responses to the compositor |
| 157 | flush_queue(queue)?; |
| 158 | |
| 159 | Ok(PostAction::Continue) |
| 160 | } |
| 161 | |
| 162 | fn register( |
| 163 | &mut self, |
| 164 | poll: &mut Poll, |
| 165 | token_factory: &mut TokenFactory, |
| 166 | ) -> calloop::Result<()> { |
| 167 | self.fake_token = Some(token_factory.token()); |
| 168 | self.connection_source.register(poll, token_factory) |
| 169 | } |
| 170 | |
| 171 | fn reregister( |
| 172 | &mut self, |
| 173 | poll: &mut Poll, |
| 174 | token_factory: &mut TokenFactory, |
| 175 | ) -> calloop::Result<()> { |
| 176 | self.connection_source.reregister(poll, token_factory) |
| 177 | } |
| 178 | |
| 179 | fn unregister(&mut self, poll: &mut Poll) -> calloop::Result<()> { |
| 180 | self.connection_source.unregister(poll) |
| 181 | } |
| 182 | |
| 183 | fn before_sleep(&mut self) -> calloop::Result<Option<(Readiness, Token)>> { |
| 184 | debug_assert!(self.read_guard.is_none()); |
| 185 | |
| 186 | flush_queue(&mut self.queue)?; |
| 187 | |
| 188 | self.read_guard = self.queue.prepare_read(); |
| 189 | match self.read_guard { |
| 190 | Some(_) => Ok(None), |
| 191 | // If getting the guard failed, that means that there are |
| 192 | // events in the queue, and so we need to handle the events instantly |
| 193 | // rather than waiting on an event in polling. We tell calloop this |
| 194 | // by returning Some here. Note that the readiness value is |
| 195 | // never used, so we just need some marker |
| 196 | None => Ok(Some((Readiness::EMPTY, self.fake_token.unwrap()))), |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | fn before_handle_events(&mut self, events: calloop::EventIterator<'_>) { |
| 201 | // It's important that the guard isn't held whilst process_events calls occur |
| 202 | // This can use arbitrary user-provided code, which may want to use the wayland |
| 203 | // socket For example, creating a Vulkan surface needs access to the |
| 204 | // connection |
| 205 | let guard = self.read_guard.take(); |
| 206 | if events.count() > 0 { |
| 207 | // Read events from the socket if any are available |
| 208 | if let Some(Err(WaylandError::Io(err))) = guard.map(ReadEventsGuard::read) { |
| 209 | // If some other thread read events before us, concurrently, that's an expected |
| 210 | // case, so this error isn't an issue. Other error kinds do need to be returned, |
| 211 | // however |
| 212 | if err.kind() != io::ErrorKind::WouldBlock { |
| 213 | // before_handle_events doesn't allow returning errors |
| 214 | // For now, cache it in self until process_events is called |
| 215 | self.stored_error = Err(err); |
| 216 | } |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | fn flush_queue<D>(queue: &mut EventQueue<D>) -> Result<(), calloop::Error> { |
| 223 | if let Err(WaylandError::Io(err: Error)) = queue.flush() { |
| 224 | // WouldBlock error means the compositor could not process all |
| 225 | // our messages quickly. Either it is slowed |
| 226 | // down or we are a spammer. Should not really |
| 227 | // happen, if it does we do nothing and will flush again later |
| 228 | if err.kind() != io::ErrorKind::WouldBlock { |
| 229 | // in case of error, forward it and fast-exit |
| 230 | log_error!("Error trying to flush the wayland display: {}" , err); |
| 231 | return Err(err.into()); |
| 232 | } |
| 233 | } |
| 234 | Ok(()) |
| 235 | } |
| 236 | |
| 237 | impl<D> WaylandSource<D> { |
| 238 | /// Loop over the callback until all pending messages have been dispatched. |
| 239 | fn loop_callback_pending<F>(queue: &mut EventQueue<D>, callback: &mut F) -> io::Result<()> |
| 240 | where |
| 241 | F: FnMut((), &mut EventQueue<D>) -> Result<usize, DispatchError>, |
| 242 | { |
| 243 | // Loop on the callback until no pending events are left. |
| 244 | loop { |
| 245 | match callback((), queue) { |
| 246 | // No more pending events. |
| 247 | Ok(0) => break Ok(()), |
| 248 | Ok(_) => continue, |
| 249 | Err(DispatchError::Backend(WaylandError::Io(err))) => { |
| 250 | return Err(err); |
| 251 | }, |
| 252 | Err(DispatchError::Backend(WaylandError::Protocol(err))) => { |
| 253 | log_error!("Protocol error received on display: {}" , err); |
| 254 | |
| 255 | break Err(Errno::PROTO.into()); |
| 256 | }, |
| 257 | Err(DispatchError::BadMessage { interface, sender_id, opcode }) => { |
| 258 | log_error!( |
| 259 | "Bad message on interface \"{}\": (sender_id: {}, opcode: {})" , |
| 260 | interface, |
| 261 | sender_id, |
| 262 | opcode, |
| 263 | ); |
| 264 | |
| 265 | break Err(Errno::PROTO.into()); |
| 266 | }, |
| 267 | } |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | |