1 | //! The event-loop routines. |
2 | |
3 | use std::cell::{Cell, RefCell}; |
4 | use std::io::Result as IOResult; |
5 | use std::marker::PhantomData; |
6 | use std::mem; |
7 | use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; |
8 | use std::rc::Rc; |
9 | use std::sync::atomic::Ordering; |
10 | use std::sync::{Arc, Mutex}; |
11 | use std::time::{Duration, Instant}; |
12 | |
13 | use sctk::reexports::calloop::Error as CalloopError; |
14 | use sctk::reexports::calloop_wayland_source::WaylandSource; |
15 | use sctk::reexports::client::globals; |
16 | use sctk::reexports::client::{Connection, QueueHandle}; |
17 | |
18 | use crate::dpi::LogicalSize; |
19 | use crate::error::{EventLoopError, OsError as RootOsError}; |
20 | use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent}; |
21 | use crate::event_loop::{ |
22 | ControlFlow, DeviceEvents, EventLoopWindowTarget as RootEventLoopWindowTarget, |
23 | }; |
24 | use crate::platform::pump_events::PumpStatus; |
25 | use crate::platform_impl::platform::min_timeout; |
26 | use crate::platform_impl::{EventLoopWindowTarget as PlatformEventLoopWindowTarget, OsError}; |
27 | |
28 | mod proxy; |
29 | pub mod sink; |
30 | |
31 | pub use proxy::EventLoopProxy; |
32 | use sink::EventSink; |
33 | |
34 | use super::state::{WindowCompositorUpdate, WinitState}; |
35 | use super::window::state::FrameCallbackState; |
36 | use super::{logical_to_physical_rounded, DeviceId, WaylandError, WindowId}; |
37 | |
38 | type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>; |
39 | |
40 | /// The Wayland event loop. |
41 | pub struct EventLoop<T: 'static> { |
42 | /// Has `run` or `run_on_demand` been called or a call to `pump_events` that starts the loop |
43 | loop_running: bool, |
44 | |
45 | buffer_sink: EventSink, |
46 | compositor_updates: Vec<WindowCompositorUpdate>, |
47 | window_ids: Vec<WindowId>, |
48 | |
49 | /// Sender of user events. |
50 | user_events_sender: calloop::channel::Sender<T>, |
51 | |
52 | // XXX can't remove RefCell out of here, unless we can plumb generics into the `Window`, which |
53 | // we don't really want, since it'll break public API by a lot. |
54 | /// Pending events from the user. |
55 | pending_user_events: Rc<RefCell<Vec<T>>>, |
56 | |
57 | /// The Wayland dispatcher to has raw access to the queue when needed, such as |
58 | /// when creating a new window. |
59 | wayland_dispatcher: WaylandDispatcher, |
60 | |
61 | /// Connection to the wayland server. |
62 | connection: Connection, |
63 | |
64 | /// Event loop window target. |
65 | window_target: RootEventLoopWindowTarget<T>, |
66 | |
67 | // XXX drop after everything else, just to be safe. |
68 | /// Calloop's event loop. |
69 | event_loop: calloop::EventLoop<'static, WinitState>, |
70 | } |
71 | |
72 | impl<T: 'static> EventLoop<T> { |
73 | pub fn new() -> Result<EventLoop<T>, EventLoopError> { |
74 | macro_rules! map_err { |
75 | ($e:expr, $err:expr) => { |
76 | $e.map_err(|error| os_error!($err(error).into())) |
77 | }; |
78 | } |
79 | |
80 | let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?; |
81 | |
82 | let (globals, mut event_queue) = map_err!( |
83 | globals::registry_queue_init(&connection), |
84 | WaylandError::Global |
85 | )?; |
86 | let queue_handle = event_queue.handle(); |
87 | |
88 | let event_loop = map_err!( |
89 | calloop::EventLoop::<WinitState>::try_new(), |
90 | WaylandError::Calloop |
91 | )?; |
92 | |
93 | let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle()) |
94 | .map_err(|error| os_error!(error))?; |
95 | |
96 | // NOTE: do a roundtrip after binding the globals to prevent potential |
97 | // races with the server. |
98 | map_err!( |
99 | event_queue.roundtrip(&mut winit_state), |
100 | WaylandError::Dispatch |
101 | )?; |
102 | |
103 | // Register Wayland source. |
104 | let wayland_source = WaylandSource::new(connection.clone(), event_queue); |
105 | let wayland_dispatcher = |
106 | calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| { |
107 | let result = queue.dispatch_pending(winit_state); |
108 | if result.is_ok() |
109 | && (!winit_state.events_sink.is_empty() |
110 | || !winit_state.window_compositor_updates.is_empty()) |
111 | { |
112 | winit_state.dispatched_events = true; |
113 | } |
114 | result |
115 | }); |
116 | |
117 | map_err!( |
118 | event_loop |
119 | .handle() |
120 | .register_dispatcher(wayland_dispatcher.clone()), |
121 | WaylandError::Calloop |
122 | )?; |
123 | |
124 | // Setup the user proxy. |
125 | let pending_user_events = Rc::new(RefCell::new(Vec::new())); |
126 | let pending_user_events_clone = pending_user_events.clone(); |
127 | let (user_events_sender, user_events_channel) = calloop::channel::channel(); |
128 | let result = event_loop |
129 | .handle() |
130 | .insert_source( |
131 | user_events_channel, |
132 | move |event, _, winit_state: &mut WinitState| { |
133 | if let calloop::channel::Event::Msg(msg) = event { |
134 | winit_state.dispatched_events = true; |
135 | pending_user_events_clone.borrow_mut().push(msg); |
136 | } |
137 | }, |
138 | ) |
139 | .map_err(|error| error.error); |
140 | map_err!(result, WaylandError::Calloop)?; |
141 | |
142 | // An event's loop awakener to wake up for window events from winit's windows. |
143 | let (event_loop_awakener, event_loop_awakener_source) = map_err!( |
144 | calloop::ping::make_ping() |
145 | .map_err(|error| CalloopError::OtherError(Box::new(error).into())), |
146 | WaylandError::Calloop |
147 | )?; |
148 | |
149 | let result = event_loop |
150 | .handle() |
151 | .insert_source( |
152 | event_loop_awakener_source, |
153 | move |_, _, winit_state: &mut WinitState| { |
154 | // Mark that we have something to dispatch. |
155 | winit_state.dispatched_events = true; |
156 | }, |
157 | ) |
158 | .map_err(|error| error.error); |
159 | map_err!(result, WaylandError::Calloop)?; |
160 | |
161 | let window_target = EventLoopWindowTarget { |
162 | connection: connection.clone(), |
163 | wayland_dispatcher: wayland_dispatcher.clone(), |
164 | event_loop_awakener, |
165 | queue_handle, |
166 | control_flow: Cell::new(ControlFlow::default()), |
167 | exit: Cell::new(None), |
168 | state: RefCell::new(winit_state), |
169 | _marker: PhantomData, |
170 | }; |
171 | |
172 | let event_loop = Self { |
173 | loop_running: false, |
174 | compositor_updates: Vec::new(), |
175 | buffer_sink: EventSink::default(), |
176 | window_ids: Vec::new(), |
177 | connection, |
178 | wayland_dispatcher, |
179 | user_events_sender, |
180 | pending_user_events, |
181 | event_loop, |
182 | window_target: RootEventLoopWindowTarget { |
183 | p: PlatformEventLoopWindowTarget::Wayland(window_target), |
184 | _marker: PhantomData, |
185 | }, |
186 | }; |
187 | |
188 | Ok(event_loop) |
189 | } |
190 | |
191 | pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError> |
192 | where |
193 | F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>), |
194 | { |
195 | if self.loop_running { |
196 | return Err(EventLoopError::AlreadyRunning); |
197 | } |
198 | |
199 | let exit = loop { |
200 | match self.pump_events(None, &mut event_handler) { |
201 | PumpStatus::Exit(0) => { |
202 | break Ok(()); |
203 | } |
204 | PumpStatus::Exit(code) => { |
205 | break Err(EventLoopError::ExitFailure(code)); |
206 | } |
207 | _ => { |
208 | continue; |
209 | } |
210 | } |
211 | }; |
212 | |
213 | // Applications aren't allowed to carry windows between separate |
214 | // `run_on_demand` calls but if they have only just dropped their |
215 | // windows we need to make sure those last requests are sent to the |
216 | // compositor. |
217 | let _ = self.roundtrip().map_err(EventLoopError::Os); |
218 | |
219 | exit |
220 | } |
221 | |
222 | pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus |
223 | where |
224 | F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>), |
225 | { |
226 | if !self.loop_running { |
227 | self.loop_running = true; |
228 | |
229 | // Run the initial loop iteration. |
230 | self.single_iteration(&mut callback, StartCause::Init); |
231 | } |
232 | |
233 | // Consider the possibility that the `StartCause::Init` iteration could |
234 | // request to Exit. |
235 | if !self.exiting() { |
236 | self.poll_events_with_timeout(timeout, &mut callback); |
237 | } |
238 | if let Some(code) = self.exit_code() { |
239 | self.loop_running = false; |
240 | |
241 | callback(Event::LoopExiting, self.window_target()); |
242 | |
243 | PumpStatus::Exit(code) |
244 | } else { |
245 | PumpStatus::Continue |
246 | } |
247 | } |
248 | |
249 | pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F) |
250 | where |
251 | F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>), |
252 | { |
253 | let cause = loop { |
254 | let start = Instant::now(); |
255 | |
256 | timeout = { |
257 | let control_flow_timeout = match self.control_flow() { |
258 | ControlFlow::Wait => None, |
259 | ControlFlow::Poll => Some(Duration::ZERO), |
260 | ControlFlow::WaitUntil(wait_deadline) => { |
261 | Some(wait_deadline.saturating_duration_since(start)) |
262 | } |
263 | }; |
264 | min_timeout(control_flow_timeout, timeout) |
265 | }; |
266 | |
267 | // NOTE Ideally we should flush as the last thing we do before polling |
268 | // to wait for events, and this should be done by the calloop |
269 | // WaylandSource but we currently need to flush writes manually. |
270 | // |
271 | // Checking for flush error is essential to perform an exit with error, since |
272 | // once we have a protocol error, we could get stuck retrying... |
273 | if self.connection.flush().is_err() { |
274 | self.set_exit_code(1); |
275 | return; |
276 | } |
277 | |
278 | if let Err(error) = self.loop_dispatch(timeout) { |
279 | // NOTE We exit on errors from dispatches, since if we've got protocol error |
280 | // libwayland-client/wayland-rs will inform us anyway, but crashing downstream is not |
281 | // really an option. Instead we inform that the event loop got destroyed. We may |
282 | // communicate an error that something was terminated, but winit doesn't provide us |
283 | // with an API to do that via some event. |
284 | // Still, we set the exit code to the error's OS error code, or to 1 if not possible. |
285 | let exit_code = error.raw_os_error().unwrap_or(1); |
286 | self.set_exit_code(exit_code); |
287 | return; |
288 | } |
289 | |
290 | // NB: `StartCause::Init` is handled as a special case and doesn't need |
291 | // to be considered here |
292 | let cause = match self.control_flow() { |
293 | ControlFlow::Poll => StartCause::Poll, |
294 | ControlFlow::Wait => StartCause::WaitCancelled { |
295 | start, |
296 | requested_resume: None, |
297 | }, |
298 | ControlFlow::WaitUntil(deadline) => { |
299 | if Instant::now() < deadline { |
300 | StartCause::WaitCancelled { |
301 | start, |
302 | requested_resume: Some(deadline), |
303 | } |
304 | } else { |
305 | StartCause::ResumeTimeReached { |
306 | start, |
307 | requested_resume: deadline, |
308 | } |
309 | } |
310 | } |
311 | }; |
312 | |
313 | // Reduce spurious wake-ups. |
314 | let dispatched_events = self.with_state(|state| state.dispatched_events); |
315 | if matches!(cause, StartCause::WaitCancelled { .. }) && !dispatched_events { |
316 | continue; |
317 | } |
318 | |
319 | break cause; |
320 | }; |
321 | |
322 | self.single_iteration(&mut callback, cause); |
323 | } |
324 | |
325 | fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause) |
326 | where |
327 | F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>), |
328 | { |
329 | // NOTE currently just indented to simplify the diff |
330 | |
331 | // We retain these grow-only scratch buffers as part of the EventLoop |
332 | // for the sake of avoiding lots of reallocs. We take them here to avoid |
333 | // trying to mutably borrow `self` more than once and we swap them back |
334 | // when finished. |
335 | let mut compositor_updates = std::mem::take(&mut self.compositor_updates); |
336 | let mut buffer_sink = std::mem::take(&mut self.buffer_sink); |
337 | let mut window_ids = std::mem::take(&mut self.window_ids); |
338 | |
339 | callback(Event::NewEvents(cause), &self.window_target); |
340 | |
341 | // NB: For consistency all platforms must emit a 'resumed' event even though Wayland |
342 | // applications don't themselves have a formal suspend/resume lifecycle. |
343 | if cause == StartCause::Init { |
344 | callback(Event::Resumed, &self.window_target); |
345 | } |
346 | |
347 | // Handle pending user events. We don't need back buffer, since we can't dispatch |
348 | // user events indirectly via callback to the user. |
349 | for user_event in self.pending_user_events.borrow_mut().drain(..) { |
350 | callback(Event::UserEvent(user_event), &self.window_target); |
351 | } |
352 | |
353 | // Drain the pending compositor updates. |
354 | self.with_state(|state| compositor_updates.append(&mut state.window_compositor_updates)); |
355 | |
356 | for mut compositor_update in compositor_updates.drain(..) { |
357 | let window_id = compositor_update.window_id; |
358 | if compositor_update.scale_changed { |
359 | let (physical_size, scale_factor) = self.with_state(|state| { |
360 | let windows = state.windows.get_mut(); |
361 | let window = windows.get(&window_id).unwrap().lock().unwrap(); |
362 | let scale_factor = window.scale_factor(); |
363 | let size = logical_to_physical_rounded(window.inner_size(), scale_factor); |
364 | (size, scale_factor) |
365 | }); |
366 | |
367 | // Stash the old window size. |
368 | let old_physical_size = physical_size; |
369 | |
370 | let new_inner_size = Arc::new(Mutex::new(physical_size)); |
371 | callback( |
372 | Event::WindowEvent { |
373 | window_id: crate::window::WindowId(window_id), |
374 | event: WindowEvent::ScaleFactorChanged { |
375 | scale_factor, |
376 | inner_size_writer: InnerSizeWriter::new(Arc::downgrade( |
377 | &new_inner_size, |
378 | )), |
379 | }, |
380 | }, |
381 | &self.window_target, |
382 | ); |
383 | |
384 | let physical_size = *new_inner_size.lock().unwrap(); |
385 | drop(new_inner_size); |
386 | |
387 | // Resize the window when user altered the size. |
388 | if old_physical_size != physical_size { |
389 | self.with_state(|state| { |
390 | let windows = state.windows.get_mut(); |
391 | let mut window = windows.get(&window_id).unwrap().lock().unwrap(); |
392 | |
393 | let new_logical_size: LogicalSize<f64> = |
394 | physical_size.to_logical(scale_factor); |
395 | window.request_inner_size(new_logical_size.into()); |
396 | }); |
397 | |
398 | // Make it queue resize. |
399 | compositor_update.resized = true; |
400 | } |
401 | } |
402 | |
403 | // NOTE: Rescale changed the physical size which winit operates in, thus we should |
404 | // resize. |
405 | if compositor_update.resized || compositor_update.scale_changed { |
406 | let physical_size = self.with_state(|state| { |
407 | let windows = state.windows.get_mut(); |
408 | let window = windows.get(&window_id).unwrap().lock().unwrap(); |
409 | |
410 | let scale_factor = window.scale_factor(); |
411 | let size = logical_to_physical_rounded(window.inner_size(), scale_factor); |
412 | |
413 | // Mark the window as needed a redraw. |
414 | state |
415 | .window_requests |
416 | .get_mut() |
417 | .get_mut(&window_id) |
418 | .unwrap() |
419 | .redraw_requested |
420 | .store(true, Ordering::Relaxed); |
421 | |
422 | size |
423 | }); |
424 | |
425 | callback( |
426 | Event::WindowEvent { |
427 | window_id: crate::window::WindowId(window_id), |
428 | event: WindowEvent::Resized(physical_size), |
429 | }, |
430 | &self.window_target, |
431 | ); |
432 | } |
433 | |
434 | if compositor_update.close_window { |
435 | callback( |
436 | Event::WindowEvent { |
437 | window_id: crate::window::WindowId(window_id), |
438 | event: WindowEvent::CloseRequested, |
439 | }, |
440 | &self.window_target, |
441 | ); |
442 | } |
443 | } |
444 | |
445 | // Push the events directly from the window. |
446 | self.with_state(|state| { |
447 | buffer_sink.append(&mut state.window_events_sink.lock().unwrap()); |
448 | }); |
449 | for event in buffer_sink.drain() { |
450 | let event = event.map_nonuser_event().unwrap(); |
451 | callback(event, &self.window_target); |
452 | } |
453 | |
454 | // Handle non-synthetic events. |
455 | self.with_state(|state| { |
456 | buffer_sink.append(&mut state.events_sink); |
457 | }); |
458 | for event in buffer_sink.drain() { |
459 | let event = event.map_nonuser_event().unwrap(); |
460 | callback(event, &self.window_target); |
461 | } |
462 | |
463 | // Collect the window ids |
464 | self.with_state(|state| { |
465 | window_ids.extend(state.window_requests.get_mut().keys()); |
466 | }); |
467 | |
468 | for window_id in window_ids.iter() { |
469 | let event = self.with_state(|state| { |
470 | let window_requests = state.window_requests.get_mut(); |
471 | if window_requests.get(window_id).unwrap().take_closed() { |
472 | mem::drop(window_requests.remove(window_id)); |
473 | mem::drop(state.windows.get_mut().remove(window_id)); |
474 | return Some(WindowEvent::Destroyed); |
475 | } |
476 | |
477 | let mut window = state |
478 | .windows |
479 | .get_mut() |
480 | .get_mut(window_id) |
481 | .unwrap() |
482 | .lock() |
483 | .unwrap(); |
484 | |
485 | if window.frame_callback_state() == FrameCallbackState::Requested { |
486 | return None; |
487 | } |
488 | |
489 | // Reset the frame callbacks state. |
490 | window.frame_callback_reset(); |
491 | let mut redraw_requested = window_requests |
492 | .get(window_id) |
493 | .unwrap() |
494 | .take_redraw_requested(); |
495 | |
496 | // Redraw the frame while at it. |
497 | redraw_requested |= window.refresh_frame(); |
498 | |
499 | redraw_requested.then_some(WindowEvent::RedrawRequested) |
500 | }); |
501 | |
502 | if let Some(event) = event { |
503 | callback( |
504 | Event::WindowEvent { |
505 | window_id: crate::window::WindowId(*window_id), |
506 | event, |
507 | }, |
508 | &self.window_target, |
509 | ); |
510 | } |
511 | } |
512 | |
513 | // Reset the hint that we've dispatched events. |
514 | self.with_state(|state| { |
515 | state.dispatched_events = false; |
516 | }); |
517 | |
518 | // This is always the last event we dispatch before poll again |
519 | callback(Event::AboutToWait, &self.window_target); |
520 | |
521 | // Update the window frames and schedule redraws. |
522 | let mut wake_up = false; |
523 | for window_id in window_ids.drain(..) { |
524 | wake_up |= self.with_state(|state| match state.windows.get_mut().get_mut(&window_id) { |
525 | Some(window) => { |
526 | let refresh = window.lock().unwrap().refresh_frame(); |
527 | if refresh { |
528 | state |
529 | .window_requests |
530 | .get_mut() |
531 | .get_mut(&window_id) |
532 | .unwrap() |
533 | .redraw_requested |
534 | .store(true, Ordering::Relaxed); |
535 | } |
536 | |
537 | refresh |
538 | } |
539 | None => false, |
540 | }); |
541 | } |
542 | |
543 | // Wakeup event loop if needed. |
544 | // |
545 | // If the user draws from the `AboutToWait` this is likely not required, however |
546 | // we can't do much about it. |
547 | if wake_up { |
548 | match &self.window_target.p { |
549 | PlatformEventLoopWindowTarget::Wayland(window_target) => { |
550 | window_target.event_loop_awakener.ping(); |
551 | } |
552 | #[cfg (x11_platform)] |
553 | PlatformEventLoopWindowTarget::X(_) => unreachable!(), |
554 | } |
555 | } |
556 | |
557 | std::mem::swap(&mut self.compositor_updates, &mut compositor_updates); |
558 | std::mem::swap(&mut self.buffer_sink, &mut buffer_sink); |
559 | std::mem::swap(&mut self.window_ids, &mut window_ids); |
560 | } |
561 | |
562 | #[inline ] |
563 | pub fn create_proxy(&self) -> EventLoopProxy<T> { |
564 | EventLoopProxy::new(self.user_events_sender.clone()) |
565 | } |
566 | |
567 | #[inline ] |
568 | pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> { |
569 | &self.window_target |
570 | } |
571 | |
572 | fn with_state<'a, U: 'a, F: FnOnce(&'a mut WinitState) -> U>(&'a mut self, callback: F) -> U { |
573 | let state = match &mut self.window_target.p { |
574 | PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(), |
575 | #[cfg (x11_platform)] |
576 | _ => unreachable!(), |
577 | }; |
578 | |
579 | callback(state) |
580 | } |
581 | |
582 | fn loop_dispatch<D: Into<Option<std::time::Duration>>>(&mut self, timeout: D) -> IOResult<()> { |
583 | let state = match &mut self.window_target.p { |
584 | PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(), |
585 | #[cfg (feature = "x11" )] |
586 | _ => unreachable!(), |
587 | }; |
588 | |
589 | self.event_loop.dispatch(timeout, state).map_err(|error| { |
590 | error!("Error dispatching event loop: {}" , error); |
591 | error.into() |
592 | }) |
593 | } |
594 | |
595 | fn roundtrip(&mut self) -> Result<usize, RootOsError> { |
596 | let state = match &mut self.window_target.p { |
597 | PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(), |
598 | #[cfg (feature = "x11" )] |
599 | _ => unreachable!(), |
600 | }; |
601 | |
602 | let mut wayland_source = self.wayland_dispatcher.as_source_mut(); |
603 | let event_queue = wayland_source.queue(); |
604 | event_queue.roundtrip(state).map_err(|error| { |
605 | os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch( |
606 | error |
607 | )))) |
608 | }) |
609 | } |
610 | |
611 | fn control_flow(&self) -> ControlFlow { |
612 | self.window_target.p.control_flow() |
613 | } |
614 | |
615 | fn exiting(&self) -> bool { |
616 | self.window_target.p.exiting() |
617 | } |
618 | |
619 | fn set_exit_code(&self, code: i32) { |
620 | self.window_target.p.set_exit_code(code) |
621 | } |
622 | |
623 | fn exit_code(&self) -> Option<i32> { |
624 | self.window_target.p.exit_code() |
625 | } |
626 | } |
627 | |
628 | impl<T> AsFd for EventLoop<T> { |
629 | fn as_fd(&self) -> BorrowedFd<'_> { |
630 | self.event_loop.as_fd() |
631 | } |
632 | } |
633 | |
634 | impl<T> AsRawFd for EventLoop<T> { |
635 | fn as_raw_fd(&self) -> RawFd { |
636 | self.event_loop.as_raw_fd() |
637 | } |
638 | } |
639 | |
640 | pub struct EventLoopWindowTarget<T> { |
641 | /// The event loop wakeup source. |
642 | pub event_loop_awakener: calloop::ping::Ping, |
643 | |
644 | /// The main queue used by the event loop. |
645 | pub queue_handle: QueueHandle<WinitState>, |
646 | |
647 | /// The application's latest control_flow state |
648 | pub(crate) control_flow: Cell<ControlFlow>, |
649 | |
650 | /// The application's exit state. |
651 | pub(crate) exit: Cell<Option<i32>>, |
652 | |
653 | // TODO remove that RefCell once we can pass `&mut` in `Window::new`. |
654 | /// Winit state. |
655 | pub state: RefCell<WinitState>, |
656 | |
657 | /// Dispatcher of Wayland events. |
658 | pub wayland_dispatcher: WaylandDispatcher, |
659 | |
660 | /// Connection to the wayland server. |
661 | pub connection: Connection, |
662 | |
663 | _marker: std::marker::PhantomData<T>, |
664 | } |
665 | |
666 | impl<T> EventLoopWindowTarget<T> { |
667 | pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { |
668 | self.control_flow.set(control_flow) |
669 | } |
670 | |
671 | pub(crate) fn control_flow(&self) -> ControlFlow { |
672 | self.control_flow.get() |
673 | } |
674 | |
675 | pub(crate) fn exit(&self) { |
676 | self.exit.set(Some(0)) |
677 | } |
678 | |
679 | pub(crate) fn clear_exit(&self) { |
680 | self.exit.set(None) |
681 | } |
682 | |
683 | pub(crate) fn exiting(&self) -> bool { |
684 | self.exit.get().is_some() |
685 | } |
686 | |
687 | pub(crate) fn set_exit_code(&self, code: i32) { |
688 | self.exit.set(Some(code)) |
689 | } |
690 | |
691 | pub(crate) fn exit_code(&self) -> Option<i32> { |
692 | self.exit.get() |
693 | } |
694 | |
695 | #[inline ] |
696 | pub fn listen_device_events(&self, _allowed: DeviceEvents) {} |
697 | |
698 | #[cfg (feature = "rwh_05" )] |
699 | #[inline ] |
700 | pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { |
701 | use sctk::reexports::client::Proxy; |
702 | |
703 | let mut display_handle = rwh_05::WaylandDisplayHandle::empty(); |
704 | display_handle.display = self.connection.display().id().as_ptr() as *mut _; |
705 | rwh_05::RawDisplayHandle::Wayland(display_handle) |
706 | } |
707 | |
708 | #[cfg (feature = "rwh_06" )] |
709 | #[inline ] |
710 | pub fn raw_display_handle_rwh_06( |
711 | &self, |
712 | ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> { |
713 | use sctk::reexports::client::Proxy; |
714 | |
715 | Ok(rwh_06::WaylandDisplayHandle::new({ |
716 | let ptr = self.connection.display().id().as_ptr(); |
717 | std::ptr::NonNull::new(ptr as *mut _).expect("wl_display should never be null" ) |
718 | }) |
719 | .into()) |
720 | } |
721 | } |
722 | |