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