diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 22f8cf9acd6..d494b48a11e 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -1,6 +1,7 @@ #![cfg(android_platform)] use std::{ + cell::Cell, collections::VecDeque, hash::Hash, sync::{ @@ -23,7 +24,7 @@ use crate::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, error, event::{self, InnerSizeWriter, StartCause}, - event_loop::{self, ControlFlow, EventLoopWindowTarget as RootELW}, + event_loop::{self, EventLoopWindowTarget as RootELW}, platform::pump_events::PumpStatus, window::{ self, CursorGrabMode, ImePurpose, ResizeDirection, Theme, WindowButtons, WindowLevel, @@ -147,7 +148,6 @@ pub struct EventLoop { loop_running: bool, // Dispatched `NewEvents` running: bool, pending_redraw: bool, - control_flow: ControlFlow, cause: StartCause, ignore_volume_keys: bool, combining_accent: Option, @@ -168,20 +168,20 @@ impl Default for PlatformSpecificEventLoopAttributes { } } -fn sticky_exit_callback( - evt: event::Event, - target: &RootELW, - control_flow: &mut ControlFlow, - callback: &mut F, -) where - F: FnMut(event::Event, &RootELW, &mut ControlFlow), +fn sticky_exit_callback(evt: event::Event, target: &RootELW, callback: &mut F) +where + F: FnMut(event::Event, &RootELW), { - // make ControlFlow::ExitWithCode sticky by providing a dummy - // control flow reference if it is already ExitWithCode. - if let ControlFlow::ExitWithCode(code) = *control_flow { - callback(evt, target, &mut ControlFlow::ExitWithCode(code)) + let is_exit = if let ControlFlow::ExitWithCode(code) = target.p.control_flow.get() { + Some(code) } else { - callback(evt, target, control_flow) + None + }; + + callback(evt, target); + + if let Some(code) = is_exit { + target.p.control_flow.set(ControlFlow::ExitWithCode(code)) } } @@ -199,6 +199,7 @@ impl EventLoop { window_target: event_loop::EventLoopWindowTarget { p: EventLoopWindowTarget { app: android_app.clone(), + control_flow: Cell::new(ControlFlow::default()), redraw_requester: RedrawRequester::new( &redraw_flag, android_app.create_waker(), @@ -213,7 +214,6 @@ impl EventLoop { loop_running: false, running: false, pending_redraw: false, - control_flow: Default::default(), cause: StartCause::Init, ignore_volume_keys: attributes.ignore_volume_keys, combining_accent: None, @@ -222,19 +222,17 @@ impl EventLoop { fn single_iteration(&mut self, main_event: Option>, callback: &mut F) where - F: FnMut(event::Event, &RootELW, &mut ControlFlow), + F: FnMut(event::Event, &RootELW), { trace!("Mainloop iteration"); let cause = self.cause; - let mut control_flow = self.control_flow; let mut pending_redraw = self.pending_redraw; let mut resized = false; sticky_exit_callback( event::Event::NewEvents(cause), self.window_target(), - &mut control_flow, callback, ); @@ -243,20 +241,10 @@ impl EventLoop { match event { MainEvent::InitWindow { .. } => { - sticky_exit_callback( - event::Event::Resumed, - self.window_target(), - &mut control_flow, - callback, - ); + sticky_exit_callback(event::Event::Resumed, self.window_target(), callback); } MainEvent::TerminateWindow { .. } => { - sticky_exit_callback( - event::Event::Suspended, - self.window_target(), - &mut control_flow, - callback, - ); + sticky_exit_callback(event::Event::Suspended, self.window_target(), callback); } MainEvent::WindowResized { .. } => resized = true, MainEvent::RedrawNeeded { .. } => pending_redraw = true, @@ -271,7 +259,6 @@ impl EventLoop { event: event::WindowEvent::Focused(true), }, self.window_target(), - &mut control_flow, callback, ); } @@ -283,7 +270,6 @@ impl EventLoop { event: event::WindowEvent::Focused(false), }, self.window_target(), - &mut control_flow, callback, ); } @@ -304,12 +290,7 @@ impl EventLoop { scale_factor, }, }; - sticky_exit_callback( - event, - self.window_target(), - &mut control_flow, - callback, - ); + sticky_exit_callback(event, self.window_target(), callback); } } MainEvent::LowMemory => { @@ -363,9 +344,8 @@ impl EventLoop { // Process input events match android_app.input_events_iter() { Ok(mut input_iter) => loop { - let read_event = input_iter.next(|event| { - self.handle_input_event(&android_app, event, &mut control_flow, callback) - }); + let read_event = + input_iter.next(|event| self.handle_input_event(&android_app, event, callback)); if !read_event { break; @@ -382,7 +362,6 @@ impl EventLoop { sticky_exit_callback( crate::event::Event::UserEvent(event), self.window_target(), - &mut control_flow, callback, ); } @@ -401,7 +380,7 @@ impl EventLoop { window_id: window::WindowId(WindowId), event: event::WindowEvent::Resized(size), }; - sticky_exit_callback(event, self.window_target(), &mut control_flow, callback); + sticky_exit_callback(event, self.window_target(), callback); } pending_redraw |= self.redraw_flag.get_and_reset(); @@ -411,19 +390,13 @@ impl EventLoop { window_id: window::WindowId(WindowId), event: event::WindowEvent::RedrawRequested, }; - sticky_exit_callback(event, self.window_target(), &mut control_flow, callback); + sticky_exit_callback(event, self.window_target(), callback); } } // This is always the last event we dispatch before poll again - sticky_exit_callback( - event::Event::AboutToWait, - self.window_target(), - &mut control_flow, - callback, - ); + sticky_exit_callback(event::Event::AboutToWait, self.window_target(), callback); - self.control_flow = control_flow; self.pending_redraw = pending_redraw; } @@ -431,11 +404,10 @@ impl EventLoop { &mut self, android_app: &AndroidApp, event: &InputEvent<'_>, - control_flow: &mut ControlFlow, callback: &mut F, ) -> InputStatus where - F: FnMut(event::Event, &RootELW, &mut ControlFlow), + F: FnMut(event::Event, &RootELW), { let mut input_status = InputStatus::Handled; match event { @@ -483,7 +455,7 @@ impl EventLoop { force: None, }), }; - sticky_exit_callback(event, self.window_target(), control_flow, callback); + sticky_exit_callback(event, self.window_target(), callback); } } } @@ -526,7 +498,7 @@ impl EventLoop { is_synthetic: false, }, }; - sticky_exit_callback(event, self.window_target(), control_flow, callback); + sticky_exit_callback(event, self.window_target(), callback); } } } @@ -540,14 +512,14 @@ impl EventLoop { pub fn run(mut self, event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(event::Event, &event_loop::EventLoopWindowTarget, &mut ControlFlow), + F: FnMut(event::Event, &event_loop::EventLoopWindowTarget), { self.run_ondemand(event_handler) } pub fn run_ondemand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> where - F: FnMut(event::Event, &event_loop::EventLoopWindowTarget, &mut ControlFlow), + F: FnMut(event::Event, &event_loop::EventLoopWindowTarget), { if self.loop_running { return Err(EventLoopError::AlreadyRunning); @@ -570,7 +542,7 @@ impl EventLoop { pub fn pump_events(&mut self, timeout: Option, mut callback: F) -> PumpStatus where - F: FnMut(event::Event, &RootELW, &mut ControlFlow), + F: FnMut(event::Event, &RootELW), { if !self.loop_running { self.loop_running = true; @@ -580,7 +552,7 @@ impl EventLoop { // than once self.pending_redraw = false; self.cause = StartCause::Init; - self.control_flow = ControlFlow::Poll; + self.set_control_flow(ControlFlow::default()); // run the initial loop iteration self.single_iteration(None, &mut callback); @@ -588,17 +560,15 @@ impl EventLoop { // Consider the possibility that the `StartCause::Init` iteration could // request to Exit - if !matches!(self.control_flow, ControlFlow::ExitWithCode(_)) { + if !matches!(self.control_flow(), ControlFlow::ExitWithCode(_)) { self.poll_events_with_timeout(timeout, &mut callback); } - if let ControlFlow::ExitWithCode(code) = self.control_flow { + if let ControlFlow::ExitWithCode(code) = self.control_flow() { self.loop_running = false; - let mut dummy = self.control_flow; sticky_exit_callback( event::Event::LoopExiting, self.window_target(), - &mut dummy, &mut callback, ); @@ -610,7 +580,7 @@ impl EventLoop { fn poll_events_with_timeout(&mut self, mut timeout: Option, mut callback: F) where - F: FnMut(event::Event, &RootELW, &mut ControlFlow), + F: FnMut(event::Event, &RootELW), { let start = Instant::now(); @@ -621,7 +591,7 @@ impl EventLoop { // If we already have work to do then we don't want to block on the next poll Some(Duration::ZERO) } else { - let control_flow_timeout = match self.control_flow { + let control_flow_timeout = match self.control_flow() { ControlFlow::Wait => None, ControlFlow::Poll => Some(Duration::ZERO), ControlFlow::WaitUntil(wait_deadline) => { @@ -663,7 +633,7 @@ impl EventLoop { } } - self.cause = match self.control_flow { + self.cause = match self.control_flow() { ControlFlow::Poll => StartCause::Poll, ControlFlow::Wait => StartCause::WaitCancelled { start, @@ -700,6 +670,14 @@ impl EventLoop { waker: self.android_app.create_waker(), } } + + fn control_flow(&self) -> ControlFlow { + self.window_target.p.control_flow.get() + } + + fn set_control_flow(&self, control_flow: ControlFlow) { + self.window_target.p.control_flow.set(control_flow) + } } pub struct EventLoopProxy { @@ -728,6 +706,7 @@ impl EventLoopProxy { pub struct EventLoopWindowTarget { app: AndroidApp, + control_flow: Cell, redraw_requester: RedrawRequester, _marker: std::marker::PhantomData, } @@ -746,6 +725,37 @@ impl EventLoopWindowTarget { pub fn raw_display_handle(&self) -> RawDisplayHandle { RawDisplayHandle::Android(AndroidDisplayHandle::empty()) } + + pub(crate) fn set_poll(&self) { + self.control_flow.set(ControlFlow::Poll) + } + + pub(crate) fn set_wait(&self) { + self.control_flow.set(ControlFlow::Wait) + } + + pub(crate) fn set_wait_until(&self, instant: Instant) { + self.control_flow.set(ControlFlow::WaitUntil(instant)) + } + + pub(crate) fn set_exit_with_code(&self, code: i32) { + self.control_flow.set(ControlFlow::ExitWithCode(code)) + } +} + +#[derive(Clone, Copy)] +pub(crate) enum ControlFlow { + Poll, + Wait, + WaitUntil(Instant), + ExitWithCode(i32), +} + +impl Default for ControlFlow { + #[inline(always)] + fn default() -> Self { + Self::Poll + } } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]