chore: remove deprecated winit method (#34638)

* Add ApplicationHandler stub

Signed-off-by: Wu Wayne <yuweiwu@pm.me>

* Implement ApplicationHandler

Signed-off-by: Wu Wayne <yuweiwu@pm.me>

* Abstract common methods

Signed-off-by: Wu Wayne <yuweiwu@pm.me>

* Impliment headless mode

Signed-off-by: Wu Yuwei <yuweiwu@pm.me>

* Apply suggestions

Signed-off-by: Wu Yuwei <yuweiwu@pm.me>

---------

Signed-off-by: Wu Wayne <yuweiwu@pm.me>
Signed-off-by: Wu Yuwei <yuweiwu@pm.me>
This commit is contained in:
Ngo Iok Ui (Wu Yu Wei) 2024-12-19 14:21:09 +09:00 committed by GitHub
parent fcf996196b
commit a0ca34d9e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 392 additions and 367 deletions

View file

@ -11,20 +11,24 @@ use std::time::Instant;
use std::{env, fs};
use gleam::gl;
use log::{info, trace, warn};
use log::{info, trace};
use servo::compositing::windowing::EmbedderEvent;
use servo::compositing::CompositeTarget;
use servo::config::{opts, set_pref};
use servo::embedder_traits::EventLoopWaker;
use servo::servo_config::pref;
use servo::url::ServoUrl;
use servo::Servo;
use surfman::GLApi;
use webxr::glwindow::GlWindowDiscovery;
#[cfg(target_os = "windows")]
use webxr::openxr::{AppInfo, OpenXrDiscovery};
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow};
use winit::window::WindowId;
use super::events_loop::{EventsLoop, WakerEvent};
use super::events_loop::{EventLoopGuard, EventsLoop, WakerEvent};
use super::minibrowser::Minibrowser;
use super::webview::WebViewManager;
use super::{headed_window, headless_window};
@ -41,6 +45,11 @@ pub struct App {
suspended: Cell<bool>,
windows: HashMap<WindowId, Rc<dyn WindowPortsMethods>>,
minibrowser: Option<RefCell<Minibrowser>>,
user_agent: Option<String>,
waker: Box<dyn EventLoopWaker>,
initial_url: ServoUrl,
t_start: Instant,
t: Instant,
}
enum Present {
@ -60,15 +69,13 @@ enum PumpResult {
}
impl App {
pub fn run(
pub fn new(
events_loop: &EventsLoop,
no_native_titlebar: bool,
device_pixel_ratio_override: Option<f32>,
user_agent: Option<String>,
url: Option<String>,
) {
let events_loop = EventsLoop::new(opts::get().headless, opts::get().output_file.is_some())
.expect("Failed to create events loop");
) -> Self {
// Implements window methods, used by compositor.
let window = if opts::get().headless {
// GL video rendering is not supported on headless windows.
@ -91,7 +98,7 @@ impl App {
let initial_url = get_default_url(url.as_deref(), env::current_dir().unwrap(), |path| {
fs::metadata(path).is_ok()
});
let t = Instant::now();
let mut app = App {
event_queue: RefCell::new(vec![]),
webviews: RefCell::new(webviews),
@ -99,6 +106,11 @@ impl App {
suspended: Cell::new(false),
windows: HashMap::new(),
minibrowser: None,
user_agent,
waker: events_loop.create_event_loop_waker(),
initial_url: initial_url.clone(),
t_start: t,
t,
};
if window.winit_window().is_some() {
@ -136,245 +148,77 @@ impl App {
window.set_toolbar_height(minibrowser.toolbar_height);
}
let t_start = Instant::now();
let mut t = t_start;
let ev_waker = events_loop.create_event_loop_waker();
events_loop.run_forever(move |event, control_flow| {
let now = Instant::now();
trace_winit_event!(event, "@{:?} (+{:?}) {event:?}", now - t_start, now - t);
t = now;
if let winit::event::Event::NewEvents(winit::event::StartCause::Init) = event {
let surfman = window.rendering_context();
app.windows.insert(window.id(), window);
let openxr_discovery = if pref!(dom.webxr.openxr.enabled) && !opts::get().headless {
#[cfg(target_os = "windows")]
let openxr = {
let app_info = AppInfo::new("Servoshell", 0, "Servo", 0);
Some(XrDiscovery::OpenXr(OpenXrDiscovery::new(None, app_info)))
};
#[cfg(not(target_os = "windows"))]
let openxr = None;
openxr
} else {
None
};
let glwindow_discovery =
if pref!(dom.webxr.glwindow.enabled) && !opts::get().headless {
let window = window.clone();
let factory = Box::new(move || {
with_current_event_loop(|w| Ok(window.new_glwindow(w)))
.expect("An event loop should always be active in headed mode")
});
Some(XrDiscovery::GlWindow(GlWindowDiscovery::new(
surfman.connection(),
surfman.adapter(),
surfman.context_attributes(),
factory,
)))
} else {
None
};
let xr_discovery = openxr_discovery.or(glwindow_discovery);
let window = window.clone();
// Implements embedder methods, used by libservo and constellation.
let embedder = Box::new(EmbedderCallbacks::new(ev_waker.clone(), xr_discovery));
let composite_target = if app.minibrowser.is_some() {
CompositeTarget::Fbo
} else {
CompositeTarget::Window
};
let servo_data = Servo::new(
embedder,
window.clone(),
user_agent.clone(),
composite_target,
);
let mut servo = servo_data.servo;
servo.handle_events(vec![EmbedderEvent::NewWebView(
initial_url.to_owned(),
servo_data.browser_id,
)]);
servo.setup_logging();
app.windows.insert(window.id(), window.clone());
app.servo = Some(servo);
}
// If self.servo is None here, it means that we're in the process of shutting down,
// let's ignore events.
if app.servo.is_none() {
return;
}
if let winit::event::Event::WindowEvent {
window_id: _,
event: winit::event::WindowEvent::RedrawRequested,
} = event
{
// We need to redraw the window for some reason.
trace!("RedrawRequested");
// WARNING: do not defer painting or presenting to some later tick of the event
// loop or servoshell may become unresponsive! (servo#30312)
if let Some(mut minibrowser) = app.minibrowser() {
minibrowser.update(
window.winit_window().unwrap(),
&mut app.webviews.borrow_mut(),
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"RedrawRequested",
);
minibrowser.paint(window.winit_window().unwrap());
}
app.servo.as_mut().unwrap().present();
}
// Handle the event
let mut consumed = false;
if let Some(mut minibrowser) = app.minibrowser() {
match event {
winit::event::Event::WindowEvent {
event: WindowEvent::ScaleFactorChanged { scale_factor, .. },
..
} => {
// Intercept any ScaleFactorChanged events away from EguiGlow::on_window_event, so
// we can use our own logic for calculating the scale factor and set eguis
// scale factor to that value manually.
let desired_scale_factor = window.hidpi_factor().get();
let effective_egui_zoom_factor = desired_scale_factor / scale_factor as f32;
info!(
"window scale factor changed to {}, setting egui zoom factor to {}",
scale_factor, effective_egui_zoom_factor
);
minibrowser
.context
.egui_ctx
.set_zoom_factor(effective_egui_zoom_factor);
// Request a winit redraw event, so we can recomposite, update and paint
// the minibrowser, and present the new frame.
window.winit_window().unwrap().request_redraw();
},
winit::event::Event::WindowEvent {
ref event,
window_id: _,
} => {
let response =
minibrowser.on_window_event(window.winit_window().unwrap(), event);
// Update minibrowser if there's resize event to sync up with window.
if let WindowEvent::Resized(_) = event {
minibrowser.update(
window.winit_window().unwrap(),
&mut app.webviews.borrow_mut(),
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"Sync WebView size with Window Resize event",
);
}
if response.repaint && *event != winit::event::WindowEvent::RedrawRequested
{
// Request a winit redraw event, so we can recomposite, update and paint
// the minibrowser, and present the new frame.
window.winit_window().unwrap().request_redraw();
}
// TODO how do we handle the tab key? (see doc for consumed)
// Note that servo doesnt yet support tabbing through links and inputs
consumed = response.consumed;
},
_ => {},
}
}
if !consumed {
app.queue_embedder_events_for_winit_event(event);
}
let animating = app.is_animating();
// Block until the window gets an event
if !animating || app.suspended.get() {
control_flow.set_wait();
} else {
control_flow.set_poll();
}
// Consume and handle any events from the Minibrowser.
if let Some(minibrowser) = app.minibrowser() {
let webviews = &mut app.webviews.borrow_mut();
let app_event_queue = &mut app.event_queue.borrow_mut();
minibrowser.queue_embedder_events_for_minibrowser_events(webviews, app_event_queue);
}
match app.handle_events() {
PumpResult::Shutdown => {
control_flow.set_exit();
app.servo.take().unwrap().deinit();
if let Some(mut minibrowser) = app.minibrowser() {
minibrowser.context.destroy();
}
},
PumpResult::Continue { update, present } => {
if update {
if let Some(mut minibrowser) = app.minibrowser() {
let webviews = &mut app.webviews.borrow_mut();
if minibrowser.update_webview_data(webviews) {
// Update the minibrowser immediately. While we could update by requesting a
// redraw, doing so would delay the location update by two frames.
minibrowser.update(
window.winit_window().unwrap(),
webviews,
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"update_location_in_toolbar",
);
}
}
}
match present {
Present::Immediate => {
// The window was resized.
trace!("PumpResult::Present::Immediate");
// If we had resized any of the viewports in response to this, we would need to
// call Servo::repaint_synchronously. At the moment we dont, so there wont be
// any paint scheduled, and calling it would hang the compositor forever.
if let Some(mut minibrowser) = app.minibrowser() {
minibrowser.update(
window.winit_window().unwrap(),
&mut app.webviews.borrow_mut(),
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"PumpResult::Present::Immediate",
);
minibrowser.paint(window.winit_window().unwrap());
}
app.servo.as_mut().unwrap().present();
},
Present::Deferred => {
// The compositor has painted to this frame.
trace!("PumpResult::Present::Deferred");
// Request a winit redraw event, so we can paint the minibrowser and present.
// Otherwise, it's in headless mode and we present directly.
if let Some(window) = window.winit_window() {
window.request_redraw();
} else {
app.servo.as_mut().unwrap().present();
}
},
Present::None => {},
}
},
}
});
app
}
fn is_animating(&self) -> bool {
/// Initialize Application once event loop start running.
pub fn init(&mut self) {
self.suspended.set(false);
self.event_queue.borrow_mut().push(EmbedderEvent::Idle);
let (_, window) = self.windows.iter().next().unwrap();
let surfman = window.rendering_context();
let openxr_discovery = if pref!(dom.webxr.openxr.enabled) && !opts::get().headless {
#[cfg(target_os = "windows")]
let openxr = {
let app_info = AppInfo::new("Servoshell", 0, "Servo", 0);
Some(XrDiscovery::OpenXr(OpenXrDiscovery::new(None, app_info)))
};
#[cfg(not(target_os = "windows"))]
let openxr = None;
openxr
} else {
None
};
let glwindow_discovery = if pref!(dom.webxr.glwindow.enabled) && !opts::get().headless {
let window = window.clone();
let factory = Box::new(move || {
with_current_event_loop(|w| Ok(window.new_glwindow(w)))
.expect("An event loop should always be active in headed mode")
});
Some(XrDiscovery::GlWindow(GlWindowDiscovery::new(
surfman.connection(),
surfman.adapter(),
surfman.context_attributes(),
factory,
)))
} else {
None
};
let xr_discovery = openxr_discovery.or(glwindow_discovery);
let window = window.clone();
// Implements embedder methods, used by libservo and constellation.
let embedder = Box::new(EmbedderCallbacks::new(self.waker.clone(), xr_discovery));
let composite_target = if self.minibrowser.is_some() {
CompositeTarget::Fbo
} else {
CompositeTarget::Window
};
let servo_data = Servo::new(
embedder,
window.clone(),
self.user_agent.clone(),
composite_target,
);
let mut servo = servo_data.servo;
servo.handle_events(vec![EmbedderEvent::NewWebView(
self.initial_url.to_owned(),
servo_data.browser_id,
)]);
servo.setup_logging();
self.servo = Some(servo);
}
pub fn is_animating(&self) -> bool {
self.windows.iter().any(|(_, window)| window.is_animating())
}
@ -382,46 +226,6 @@ impl App {
std::mem::take(&mut *self.event_queue.borrow_mut())
}
/// Processes the given winit Event, possibly converting it to an [EmbedderEvent] and
/// routing that to the App or relevant Window event queues.
fn queue_embedder_events_for_winit_event(&self, event: winit::event::Event<WakerEvent>) {
match event {
// App level events
winit::event::Event::Suspended => {
self.suspended.set(true);
},
winit::event::Event::Resumed => {
self.suspended.set(false);
self.event_queue.borrow_mut().push(EmbedderEvent::Idle);
},
winit::event::Event::UserEvent(_) => {
self.event_queue.borrow_mut().push(EmbedderEvent::Idle);
},
winit::event::Event::DeviceEvent { .. } => {},
// Window level events
winit::event::Event::WindowEvent {
window_id, event, ..
} => match self.windows.get(&window_id) {
None => {
warn!("Got an event from unknown window");
},
Some(window) => {
if event == winit::event::WindowEvent::RedrawRequested {
self.event_queue.borrow_mut().push(EmbedderEvent::Idle);
}
window.queue_embedder_events_for_winit_event(event);
},
},
winit::event::Event::LoopExiting |
winit::event::Event::AboutToWait |
winit::event::Event::MemoryWarning |
winit::event::Event::NewEvents(..) => {},
}
}
/// Pumps events and messages between the embedder and Servo, where embedder events flow
/// towards Servo and embedder messages flow away from Servo, and also runs the compositor.
///
@ -491,7 +295,292 @@ impl App {
}
}
/// Handle events with winit contexts
pub fn handle_events_with_winit(
&mut self,
event_loop: &ActiveEventLoop,
window: Rc<dyn WindowPortsMethods>,
) {
match self.handle_events() {
PumpResult::Shutdown => {
event_loop.exit();
self.servo.take().unwrap().deinit();
if let Some(mut minibrowser) = self.minibrowser() {
minibrowser.context.destroy();
}
},
PumpResult::Continue { update, present } => {
if update {
if let Some(mut minibrowser) = self.minibrowser() {
let webviews = &mut self.webviews.borrow_mut();
if minibrowser.update_webview_data(webviews) {
// Update the minibrowser immediately. While we could update by requesting a
// redraw, doing so would delay the location update by two frames.
minibrowser.update(
window.winit_window().unwrap(),
webviews,
self.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"update_location_in_toolbar",
);
}
}
}
match present {
Present::Immediate => {
// The window was resized.
trace!("PumpResult::Present::Immediate");
// If we had resized any of the viewports in response to this, we would need to
// call Servo::repaint_synchronously. At the moment we dont, so there wont be
// any paint scheduled, and calling it would hang the compositor forever.
if let Some(mut minibrowser) = self.minibrowser() {
minibrowser.update(
window.winit_window().unwrap(),
&mut self.webviews.borrow_mut(),
self.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"PumpResult::Present::Immediate",
);
minibrowser.paint(window.winit_window().unwrap());
}
self.servo.as_mut().unwrap().present();
},
Present::Deferred => {
// The compositor has painted to this frame.
trace!("PumpResult::Present::Deferred");
// Request a winit redraw event, so we can paint the minibrowser and present.
// Otherwise, it's in headless mode and we present directly.
if let Some(window) = window.winit_window() {
window.request_redraw();
} else {
self.servo.as_mut().unwrap().present();
}
},
Present::None => {},
}
},
}
}
/// Handle all servo events with headless mode. Return true if servo request to shutdown.
pub fn handle_events_with_headless(&mut self) -> bool {
let now = Instant::now();
let event = winit::event::Event::UserEvent(WakerEvent);
trace_winit_event!(
event,
"@{:?} (+{:?}) {event:?}",
now - self.t_start,
now - self.t
);
self.t = now;
// If self.servo is None here, it means that we're in the process of shutting down,
// let's ignore events.
if self.servo.is_none() {
return false;
}
self.event_queue.borrow_mut().push(EmbedderEvent::Idle);
let mut exit = false;
match self.handle_events() {
PumpResult::Shutdown => {
exit = true;
self.servo.take().unwrap().deinit();
if let Some(mut minibrowser) = self.minibrowser() {
minibrowser.context.destroy();
}
},
PumpResult::Continue { present, .. } => {
match present {
Present::Immediate => {
// The window was resized.
trace!("PumpResult::Present::Immediate");
self.servo.as_mut().unwrap().present();
},
Present::Deferred => {
// The compositor has painted to this frame.
trace!("PumpResult::Present::Deferred");
// In headless mode, we present directly.
self.servo.as_mut().unwrap().present();
},
Present::None => {},
}
},
}
exit
}
fn minibrowser(&self) -> Option<RefMut<Minibrowser>> {
self.minibrowser.as_ref().map(|x| x.borrow_mut())
}
}
impl ApplicationHandler<WakerEvent> for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
let _guard = EventLoopGuard::new(event_loop);
self.init();
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
window_id: WindowId,
event: WindowEvent,
) {
let now = Instant::now();
trace_winit_event!(
event,
"@{:?} (+{:?}) {event:?}",
now - self.t_start,
now - self.t
);
self.t = now;
// If self.servo is None here, it means that we're in the process of shutting down,
// let's ignore events.
if self.servo.is_none() {
return;
}
let Some(window) = self.windows.get(&window_id) else {
return;
};
let window = window.clone();
if event == winit::event::WindowEvent::RedrawRequested {
// We need to redraw the window for some reason.
trace!("RedrawRequested");
// WARNING: do not defer painting or presenting to some later tick of the event
// loop or servoshell may become unresponsive! (servo#30312)
if let Some(mut minibrowser) = self.minibrowser() {
minibrowser.update(
window.winit_window().unwrap(),
&mut self.webviews.borrow_mut(),
self.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"RedrawRequested",
);
minibrowser.paint(window.winit_window().unwrap());
}
self.servo.as_mut().unwrap().present();
}
// Handle the event
let mut consumed = false;
if let Some(mut minibrowser) = self.minibrowser() {
match event {
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
// Intercept any ScaleFactorChanged events away from EguiGlow::on_window_event, so
// we can use our own logic for calculating the scale factor and set eguis
// scale factor to that value manually.
let desired_scale_factor = window.hidpi_factor().get();
let effective_egui_zoom_factor = desired_scale_factor / scale_factor as f32;
info!(
"window scale factor changed to {}, setting egui zoom factor to {}",
scale_factor, effective_egui_zoom_factor
);
minibrowser
.context
.egui_ctx
.set_zoom_factor(effective_egui_zoom_factor);
// Request a winit redraw event, so we can recomposite, update and paint
// the minibrowser, and present the new frame.
window.winit_window().unwrap().request_redraw();
},
ref event => {
let response =
minibrowser.on_window_event(window.winit_window().unwrap(), event);
// Update minibrowser if there's resize event to sync up with window.
if let WindowEvent::Resized(_) = event {
minibrowser.update(
window.winit_window().unwrap(),
&mut self.webviews.borrow_mut(),
self.servo.as_ref().unwrap().offscreen_framebuffer_id(),
"Sync WebView size with Window Resize event",
);
}
if response.repaint && *event != winit::event::WindowEvent::RedrawRequested {
// Request a winit redraw event, so we can recomposite, update and paint
// the minibrowser, and present the new frame.
window.winit_window().unwrap().request_redraw();
}
// TODO how do we handle the tab key? (see doc for consumed)
// Note that servo doesnt yet support tabbing through links and inputs
consumed = response.consumed;
},
}
}
if !consumed {
if event == winit::event::WindowEvent::RedrawRequested {
self.event_queue.borrow_mut().push(EmbedderEvent::Idle);
}
window.queue_embedder_events_for_winit_event(event);
}
let animating = self.is_animating();
// Block until the window gets an event
if !animating || self.suspended.get() {
event_loop.set_control_flow(ControlFlow::Wait);
} else {
event_loop.set_control_flow(ControlFlow::Poll);
}
// Consume and handle any events from the Minibrowser.
if let Some(minibrowser) = self.minibrowser() {
let webviews = &mut self.webviews.borrow_mut();
let app_event_queue = &mut self.event_queue.borrow_mut();
minibrowser.queue_embedder_events_for_minibrowser_events(webviews, app_event_queue);
}
self.handle_events_with_winit(event_loop, window);
}
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: WakerEvent) {
let now = Instant::now();
let event = winit::event::Event::UserEvent(event);
trace_winit_event!(
event,
"@{:?} (+{:?}) {event:?}",
now - self.t_start,
now - self.t
);
self.t = now;
// If self.servo is None here, it means that we're in the process of shutting down,
// let's ignore events.
if self.servo.is_none() {
return;
}
self.event_queue.borrow_mut().push(EmbedderEvent::Idle);
let Some(window) = self.windows.values().next() else {
return;
};
let window = window.clone();
let animating = self.is_animating();
// Block until the window gets an event
if !animating || self.suspended.get() {
event_loop.set_control_flow(ControlFlow::Wait);
} else {
event_loop.set_control_flow(ControlFlow::Poll);
}
// Consume and handle any events from the Minibrowser.
if let Some(minibrowser) = self.minibrowser() {
let webviews = &mut self.webviews.borrow_mut();
let app_event_queue = &mut self.event_queue.borrow_mut();
minibrowser.queue_embedder_events_for_minibrowser_events(webviews, app_event_queue);
}
self.handle_events_with_winit(event_loop, window);
}
fn suspended(&mut self, _: &ActiveEventLoop) {
self.suspended.set(true);
}
}

View file

@ -9,6 +9,7 @@ use log::error;
use servo::config::opts::{self, ArgumentParsingResult};
use servo::servo_config::pref;
use super::events_loop::EventsLoop;
use crate::desktop::app::App;
use crate::panic_hook;
@ -99,12 +100,18 @@ pub fn main() {
None
};
App::run(
let event_loop = EventsLoop::new(opts::get().headless, opts::get().output_file.is_some())
.expect("Failed to create events loop");
let mut app = App::new(
&event_loop,
do_not_use_native_titlebar,
device_pixel_ratio_override,
user_agent,
url_opt.map(|s| s.to_string()),
);
event_loop.run_app(&mut app);
crate::platform::deinit(clean_shutdown)
}

View file

@ -11,11 +11,12 @@ use std::time;
use log::warn;
use servo::embedder_traits::EventLoopWaker;
use winit::error::EventLoopError;
use winit::event::{Event, StartCause};
use winit::event_loop::{ActiveEventLoop, EventLoop as WinitEventLoop};
#[cfg(target_os = "macos")]
use winit::platform::macos::{ActivationPolicy, EventLoopBuilderExtMacOS};
use super::app::App;
/// Another process or thread has kicked the OS event loop with EventLoopWaker.
#[derive(Debug)]
pub struct WakerEvent;
@ -86,40 +87,25 @@ impl EventsLoop {
},
}
}
pub fn run_forever<F>(self, mut callback: F)
where
F: 'static + FnMut(Event<WakerEvent>, &mut ControlFlow),
{
pub fn run_app(self, app: &mut App) {
match self.0 {
EventLoop::Winit(events_loop) => {
let events_loop = events_loop.expect("Can't run an unavailable event loop.");
#[allow(deprecated)]
events_loop
.run(move |e, window_target| {
let mut control_flow = ControlFlow::default();
let _guard = EventLoopGuard::new(window_target);
callback(e, &mut control_flow);
control_flow.apply_to(window_target);
})
.run_app(app)
.expect("Failed while running events loop");
},
EventLoop::Headless(ref data) => {
let (flag, condvar) = &**data;
let mut event = Event::NewEvents(StartCause::Init);
app.init();
loop {
self.sleep(flag, condvar);
let mut control_flow = ControlFlow::Poll;
callback(event, &mut control_flow);
event = Event::<WakerEvent>::UserEvent(WakerEvent);
if control_flow != ControlFlow::Poll {
*flag.lock().unwrap() = false;
}
if control_flow == ControlFlow::Exit {
if app.handle_events_with_headless() {
break;
}
if !app.is_animating() {
*flag.lock().unwrap() = false;
}
}
},
}
@ -140,63 +126,6 @@ impl EventsLoop {
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum ControlFlow {
Poll,
#[default]
Wait,
WaitUntil(std::time::Instant),
/// winit removed their ControlFlow::Exit variant in 0.29.2
Exit,
}
impl ControlFlow {
fn apply_to(self, window_target: &ActiveEventLoop) {
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>>>,
}
@ -241,10 +170,10 @@ thread_local! {
static CURRENT_EVENT_LOOP: Cell<Option<*const ActiveEventLoop>> = const { Cell::new(None) };
}
struct EventLoopGuard;
pub struct EventLoopGuard;
impl EventLoopGuard {
fn new(event_loop: &ActiveEventLoop) -> Self {
pub fn new(event_loop: &ActiveEventLoop) -> Self {
CURRENT_EVENT_LOOP.with(|cell| {
assert!(
cell.get().is_none(),