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