servoshell/desktop/
events_loop.rs1use std::sync::{Arc, Condvar, Mutex};
8use std::time;
9
10use log::warn;
11use servo::EventLoopWaker;
12use winit::error::EventLoopError;
13use winit::event_loop::EventLoop as WinitEventLoop;
14
15use super::app::App;
16
17pub type EventLoopProxy = winit::event_loop::EventLoopProxy<AppEvent>;
18
19#[derive(Debug)]
20pub enum AppEvent {
21 Waker,
23 Accessibility(egui_winit::accesskit_winit::Event),
24}
25
26impl From<egui_winit::accesskit_winit::Event> for AppEvent {
27 fn from(event: egui_winit::accesskit_winit::Event) -> AppEvent {
28 AppEvent::Accessibility(event)
29 }
30}
31
32#[allow(dead_code)]
34#[allow(clippy::large_enum_variant)]
35enum EventLoop {
36 Winit(winit::event_loop::EventLoop<AppEvent>),
38 Headless(Arc<(Mutex<bool>, Condvar)>),
42}
43
44pub struct EventsLoop(EventLoop);
45
46impl EventsLoop {
47 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
50 pub fn new(_headless: bool) -> Result<EventsLoop, EventLoopError> {
51 Ok(EventsLoop(EventLoop::Winit(
52 WinitEventLoop::with_user_event().build()?,
53 )))
54 }
55 #[cfg(any(target_os = "linux", target_os = "windows"))]
56 pub fn new(headless: bool) -> Result<EventsLoop, EventLoopError> {
57 Ok(EventsLoop(if headless {
58 EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
59 } else {
60 EventLoop::Winit(WinitEventLoop::with_user_event().build()?)
61 }))
62 }
63 #[cfg(target_os = "macos")]
64 pub fn new(headless: bool) -> Result<EventsLoop, EventLoopError> {
65 Ok(EventsLoop(if headless {
66 EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
67 } else {
68 EventLoop::Winit(WinitEventLoop::with_user_event().build()?)
69 }))
70 }
71}
72
73impl EventsLoop {
74 pub(crate) fn event_loop_proxy(&self) -> Option<EventLoopProxy> {
75 match self.0 {
76 EventLoop::Winit(ref events_loop) => Some(events_loop.create_proxy()),
77 EventLoop::Headless(..) => None,
78 }
79 }
80
81 pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
82 match self.0 {
83 EventLoop::Winit(ref events_loop) => Box::new(HeadedEventLoopWaker::new(events_loop)),
84 EventLoop::Headless(ref data) => Box::new(HeadlessEventLoopWaker(data.clone())),
85 }
86 }
87
88 pub fn run_app(self, app: &mut App) {
89 match self.0 {
90 EventLoop::Winit(events_loop) => {
91 events_loop
92 .run_app(app)
93 .expect("Failed while running events loop");
94 },
95 EventLoop::Headless(ref data) => {
96 let (flag, condvar) = &**data;
97
98 app.init(None);
99 loop {
100 self.sleep(flag, condvar);
101 app.handle_webdriver_messages();
102 if !app.handle_events_with_headless() {
103 break;
104 }
105 if !app.animating() {
106 *flag.lock().unwrap() = false;
107 }
108 }
109 },
110 }
111 }
112
113 fn sleep(&self, lock: &Mutex<bool>, condvar: &Condvar) {
114 let guard = lock.lock().unwrap();
119 if *guard {
120 return;
121 }
122 let _ = condvar
123 .wait_timeout(guard, time::Duration::from_millis(5))
124 .unwrap();
125 }
126}
127
128struct HeadedEventLoopWaker {
129 proxy: Arc<Mutex<winit::event_loop::EventLoopProxy<AppEvent>>>,
130}
131impl HeadedEventLoopWaker {
132 fn new(events_loop: &winit::event_loop::EventLoop<AppEvent>) -> HeadedEventLoopWaker {
133 let proxy = Arc::new(Mutex::new(events_loop.create_proxy()));
134 HeadedEventLoopWaker { proxy }
135 }
136}
137impl EventLoopWaker for HeadedEventLoopWaker {
138 fn wake(&self) {
139 if let Err(err) = self.proxy.lock().unwrap().send_event(AppEvent::Waker) {
141 warn!("Failed to wake up event loop ({}).", err);
142 }
143 }
144 fn clone_box(&self) -> Box<dyn EventLoopWaker> {
145 Box::new(HeadedEventLoopWaker {
146 proxy: self.proxy.clone(),
147 })
148 }
149}
150
151struct HeadlessEventLoopWaker(Arc<(Mutex<bool>, Condvar)>);
152impl EventLoopWaker for HeadlessEventLoopWaker {
153 fn wake(&self) {
154 let (ref flag, ref condvar) = *self.0;
159 let mut flag = flag.lock().unwrap();
160 *flag = true;
161 condvar.notify_all();
162 }
163 fn clone_box(&self) -> Box<dyn EventLoopWaker> {
164 Box::new(HeadlessEventLoopWaker(self.0.clone()))
165 }
166}