use std::sync::{Arc, Condvar, Mutex};
use std::time;
use log::warn;
use servo::embedder_traits::EventLoopWaker;
#[cfg(target_os = "macos")]
use winit::platform::macos::{ActivationPolicy, EventLoopBuilderExtMacOS};
#[derive(Debug)]
pub struct WakerEvent;
#[allow(dead_code)]
enum EventLoop {
Winit(Option<winit::event_loop::EventLoop<WakerEvent>>),
Headless(Arc<(Mutex<bool>, Condvar)>),
}
pub struct EventsLoop(EventLoop);
impl EventsLoop {
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
pub fn new(
_headless: bool,
_has_output_file: bool,
) -> Result<EventsLoop, winit::error::EventLoopError> {
Ok(EventsLoop(EventLoop::Winit(Some(
winit::event_loop::EventLoopBuilder::with_user_event().build()?,
))))
}
#[cfg(target_os = "linux")]
pub fn new(
headless: bool,
_has_output_file: bool,
) -> Result<EventsLoop, winit::error::EventLoopError> {
Ok(EventsLoop(if headless {
EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
} else {
EventLoop::Winit(Some(
winit::event_loop::EventLoopBuilder::with_user_event().build()?,
))
}))
}
#[cfg(target_os = "macos")]
pub fn new(
headless: bool,
_has_output_file: bool,
) -> Result<EventsLoop, winit::error::EventLoopError> {
Ok(EventsLoop(if headless {
EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
} else {
let mut event_loop_builder = winit::event_loop::EventLoopBuilder::with_user_event();
if _has_output_file {
event_loop_builder.with_activation_policy(ActivationPolicy::Prohibited);
}
EventLoop::Winit(Some(event_loop_builder.build()?))
}))
}
}
impl EventsLoop {
pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
match self.0 {
EventLoop::Winit(ref events_loop) => {
let events_loop = events_loop
.as_ref()
.expect("Can't create waker for unavailable event loop.");
Box::new(HeadedEventLoopWaker::new(events_loop))
},
EventLoop::Headless(ref data) => Box::new(HeadlessEventLoopWaker(data.clone())),
}
}
pub fn as_winit(&self) -> &winit::event_loop::EventLoop<WakerEvent> {
match self.0 {
EventLoop::Winit(Some(ref event_loop)) => event_loop,
EventLoop::Winit(None) | EventLoop::Headless(..) => {
panic!("Can't access winit event loop while using the fake headless event loop")
},
}
}
pub fn run_forever<F>(self, mut callback: F)
where
F: 'static
+ FnMut(
winit::event::Event<WakerEvent>,
Option<&winit::event_loop::EventLoopWindowTarget<WakerEvent>>,
&mut ControlFlow,
),
{
match self.0 {
EventLoop::Winit(events_loop) => {
let events_loop = events_loop.expect("Can't run an unavailable event loop.");
events_loop
.run(move |e, window_target| {
let mut control_flow = ControlFlow::default();
callback(e, Some(window_target), &mut control_flow);
control_flow.apply_to(window_target);
})
.expect("Failed while running events loop");
},
EventLoop::Headless(ref data) => {
let (flag, condvar) = &**data;
let mut event = winit::event::Event::NewEvents(winit::event::StartCause::Init);
loop {
self.sleep(flag, condvar);
let mut control_flow = ControlFlow::Poll;
callback(event, None, &mut control_flow);
event = winit::event::Event::<WakerEvent>::UserEvent(WakerEvent);
if control_flow != ControlFlow::Poll {
*flag.lock().unwrap() = false;
}
if control_flow == ControlFlow::Exit {
break;
}
}
},
}
}
fn sleep(&self, lock: &Mutex<bool>, condvar: &Condvar) {
let guard = lock.lock().unwrap();
if *guard {
return;
}
let _ = condvar
.wait_timeout(guard, time::Duration::from_millis(5))
.unwrap();
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum ControlFlow {
Poll,
#[default]
Wait,
WaitUntil(std::time::Instant),
Exit,
}
impl ControlFlow {
fn apply_to(self, window_target: &winit::event_loop::EventLoopWindowTarget<WakerEvent>) {
match self {
ControlFlow::Poll => {
window_target.set_control_flow(winit::event_loop::ControlFlow::Poll)
},
ControlFlow::Wait => {
window_target.set_control_flow(winit::event_loop::ControlFlow::Wait)
},
ControlFlow::WaitUntil(instant) => {
window_target.set_control_flow(winit::event_loop::ControlFlow::WaitUntil(instant))
},
ControlFlow::Exit => window_target.exit(),
}
}
pub fn set_poll(&mut self) {
*self = ControlFlow::Poll;
}
pub fn set_wait(&mut self) {
*self = ControlFlow::Wait;
}
#[allow(unused)]
pub fn set_wait_until(&mut self, instant: std::time::Instant) {
*self = ControlFlow::WaitUntil(instant);
}
pub fn set_exit(&mut self) {
*self = ControlFlow::Exit;
}
}
impl From<winit::event_loop::ControlFlow> for ControlFlow {
fn from(cf: winit::event_loop::ControlFlow) -> Self {
match cf {
winit::event_loop::ControlFlow::Poll => Self::Poll,
winit::event_loop::ControlFlow::Wait => Self::Wait,
winit::event_loop::ControlFlow::WaitUntil(instant) => Self::WaitUntil(instant),
}
}
}
struct HeadedEventLoopWaker {
proxy: Arc<Mutex<winit::event_loop::EventLoopProxy<WakerEvent>>>,
}
impl HeadedEventLoopWaker {
fn new(events_loop: &winit::event_loop::EventLoop<WakerEvent>) -> HeadedEventLoopWaker {
let proxy = Arc::new(Mutex::new(events_loop.create_proxy()));
HeadedEventLoopWaker { proxy }
}
}
impl EventLoopWaker for HeadedEventLoopWaker {
fn wake(&self) {
if let Err(err) = self.proxy.lock().unwrap().send_event(WakerEvent) {
warn!("Failed to wake up event loop ({}).", err);
}
}
fn clone_box(&self) -> Box<dyn EventLoopWaker> {
Box::new(HeadedEventLoopWaker {
proxy: self.proxy.clone(),
})
}
}
struct HeadlessEventLoopWaker(Arc<(Mutex<bool>, Condvar)>);
impl EventLoopWaker for HeadlessEventLoopWaker {
fn wake(&self) {
let (ref flag, ref condvar) = *self.0;
let mut flag = flag.lock().unwrap();
*flag = true;
condvar.notify_all();
}
fn clone_box(&self) -> Box<dyn EventLoopWaker> {
Box::new(HeadlessEventLoopWaker(self.0.clone()))
}
}