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