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#[cfg(target_os = "macos")]
15use winit::platform::macos::{ActivationPolicy, EventLoopBuilderExtMacOS};
16
17use super::app::App;
18
19pub type EventLoopProxy = winit::event_loop::EventLoopProxy<AppEvent>;
20
21#[derive(Debug)]
22pub enum AppEvent {
23 Waker,
25 Accessibility(accesskit_winit::Event),
26}
27
28impl From<accesskit_winit::Event> for AppEvent {
29 fn from(event: accesskit_winit::Event) -> AppEvent {
30 AppEvent::Accessibility(event)
31 }
32}
33
34#[allow(dead_code)]
36#[allow(clippy::large_enum_variant)]
37enum EventLoop {
38 Winit(winit::event_loop::EventLoop<AppEvent>),
40 Headless(Arc<(Mutex<bool>, Condvar)>),
44}
45
46pub struct EventsLoop(EventLoop);
47
48impl EventsLoop {
49 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
52 pub fn new(_headless: bool, _has_output_file: bool) -> Result<EventsLoop, EventLoopError> {
53 Ok(EventsLoop(EventLoop::Winit(
54 WinitEventLoop::with_user_event().build()?,
55 )))
56 }
57 #[cfg(any(target_os = "linux", target_os = "windows"))]
58 pub fn new(headless: bool, _has_output_file: bool) -> Result<EventsLoop, EventLoopError> {
59 Ok(EventsLoop(if headless {
60 EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
61 } else {
62 EventLoop::Winit(WinitEventLoop::with_user_event().build()?)
63 }))
64 }
65 #[cfg(target_os = "macos")]
66 pub fn new(headless: bool, _has_output_file: bool) -> Result<EventsLoop, EventLoopError> {
67 Ok(EventsLoop(if headless {
68 EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
69 } else {
70 let mut event_loop_builder = WinitEventLoop::with_user_event();
71 if _has_output_file {
72 event_loop_builder.with_activation_policy(ActivationPolicy::Prohibited);
75 }
76 EventLoop::Winit(event_loop_builder.build()?)
77 }))
78 }
79}
80
81impl EventsLoop {
82 pub(crate) fn event_loop_proxy(&self) -> Option<EventLoopProxy> {
83 match self.0 {
84 EventLoop::Winit(ref events_loop) => Some(events_loop.create_proxy()),
85 EventLoop::Headless(..) => None,
86 }
87 }
88
89 pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
90 match self.0 {
91 EventLoop::Winit(ref events_loop) => Box::new(HeadedEventLoopWaker::new(events_loop)),
92 EventLoop::Headless(ref data) => Box::new(HeadlessEventLoopWaker(data.clone())),
93 }
94 }
95
96 pub fn run_app(self, app: &mut App) {
97 match self.0 {
98 EventLoop::Winit(events_loop) => {
99 events_loop
100 .run_app(app)
101 .expect("Failed while running events loop");
102 },
103 EventLoop::Headless(ref data) => {
104 let (flag, condvar) = &**data;
105
106 app.init(None);
107 loop {
108 self.sleep(flag, condvar);
109 app.handle_webdriver_messages();
110 if !app.handle_events_with_headless() {
111 break;
112 }
113 if !app.animating() {
114 *flag.lock().unwrap() = false;
115 }
116 }
117 },
118 }
119 }
120
121 fn sleep(&self, lock: &Mutex<bool>, condvar: &Condvar) {
122 let guard = lock.lock().unwrap();
127 if *guard {
128 return;
129 }
130 let _ = condvar
131 .wait_timeout(guard, time::Duration::from_millis(5))
132 .unwrap();
133 }
134}
135
136struct HeadedEventLoopWaker {
137 proxy: Arc<Mutex<winit::event_loop::EventLoopProxy<AppEvent>>>,
138}
139impl HeadedEventLoopWaker {
140 fn new(events_loop: &winit::event_loop::EventLoop<AppEvent>) -> HeadedEventLoopWaker {
141 let proxy = Arc::new(Mutex::new(events_loop.create_proxy()));
142 HeadedEventLoopWaker { proxy }
143 }
144}
145impl EventLoopWaker for HeadedEventLoopWaker {
146 fn wake(&self) {
147 if let Err(err) = self.proxy.lock().unwrap().send_event(AppEvent::Waker) {
149 warn!("Failed to wake up event loop ({}).", err);
150 }
151 }
152 fn clone_box(&self) -> Box<dyn EventLoopWaker> {
153 Box::new(HeadedEventLoopWaker {
154 proxy: self.proxy.clone(),
155 })
156 }
157}
158
159struct HeadlessEventLoopWaker(Arc<(Mutex<bool>, Condvar)>);
160impl EventLoopWaker for HeadlessEventLoopWaker {
161 fn wake(&self) {
162 let (ref flag, ref condvar) = *self.0;
167 let mut flag = flag.lock().unwrap();
168 *flag = true;
169 condvar.notify_all();
170 }
171 fn clone_box(&self) -> Box<dyn EventLoopWaker> {
172 Box::new(HeadlessEventLoopWaker(self.0.clone()))
173 }
174}