Skip to content

Commit

Permalink
Android implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Aug 27, 2023
1 parent 6096c72 commit 91df56e
Showing 1 changed file with 76 additions and 66 deletions.
142 changes: 76 additions & 66 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![cfg(android_platform)]

use std::{
cell::Cell,
collections::VecDeque,
hash::Hash,
sync::{
Expand All @@ -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,
Expand Down Expand Up @@ -147,7 +148,6 @@ pub struct EventLoop<T: 'static> {
loop_running: bool, // Dispatched `NewEvents<Init>`
running: bool,
pending_redraw: bool,
control_flow: ControlFlow,
cause: StartCause,
ignore_volume_keys: bool,
combining_accent: Option<char>,
Expand All @@ -168,20 +168,20 @@ impl Default for PlatformSpecificEventLoopAttributes {
}
}

fn sticky_exit_callback<T, F>(
evt: event::Event<T>,
target: &RootELW<T>,
control_flow: &mut ControlFlow,
callback: &mut F,
) where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
fn sticky_exit_callback<T, F>(evt: event::Event<T>, target: &RootELW<T>, callback: &mut F)
where
F: FnMut(event::Event<T>, &RootELW<T>),
{
// 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))
}
}

Expand All @@ -199,6 +199,7 @@ impl<T: 'static> EventLoop<T> {
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(),
Expand All @@ -213,7 +214,6 @@ impl<T: 'static> EventLoop<T> {
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,
Expand All @@ -222,19 +222,17 @@ impl<T: 'static> EventLoop<T> {

fn single_iteration<F>(&mut self, main_event: Option<MainEvent<'_>>, callback: &mut F)
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
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,
);

Expand All @@ -243,20 +241,10 @@ impl<T: 'static> EventLoop<T> {

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,
Expand All @@ -271,7 +259,6 @@ impl<T: 'static> EventLoop<T> {
event: event::WindowEvent::Focused(true),
},
self.window_target(),
&mut control_flow,
callback,
);
}
Expand All @@ -283,7 +270,6 @@ impl<T: 'static> EventLoop<T> {
event: event::WindowEvent::Focused(false),
},
self.window_target(),
&mut control_flow,
callback,
);
}
Expand All @@ -304,12 +290,7 @@ impl<T: 'static> EventLoop<T> {
scale_factor,
},
};
sticky_exit_callback(
event,
self.window_target(),
&mut control_flow,
callback,
);
sticky_exit_callback(event, self.window_target(), callback);
}
}
MainEvent::LowMemory => {
Expand Down Expand Up @@ -363,9 +344,8 @@ impl<T: 'static> EventLoop<T> {
// 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;
Expand All @@ -382,7 +362,6 @@ impl<T: 'static> EventLoop<T> {
sticky_exit_callback(
crate::event::Event::UserEvent(event),
self.window_target(),
&mut control_flow,
callback,
);
}
Expand All @@ -401,7 +380,7 @@ impl<T: 'static> EventLoop<T> {
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();
Expand All @@ -411,31 +390,24 @@ impl<T: 'static> EventLoop<T> {
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;
}

fn handle_input_event<F>(
&mut self,
android_app: &AndroidApp,
event: &InputEvent<'_>,
control_flow: &mut ControlFlow,
callback: &mut F,
) -> InputStatus
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
let mut input_status = InputStatus::Handled;
match event {
Expand Down Expand Up @@ -483,7 +455,7 @@ impl<T: 'static> EventLoop<T> {
force: None,
}),
};
sticky_exit_callback(event, self.window_target(), control_flow, callback);
sticky_exit_callback(event, self.window_target(), callback);
}
}
}
Expand Down Expand Up @@ -526,7 +498,7 @@ impl<T: 'static> EventLoop<T> {
is_synthetic: false,
},
};
sticky_exit_callback(event, self.window_target(), control_flow, callback);
sticky_exit_callback(event, self.window_target(), callback);
}
}
}
Expand All @@ -540,14 +512,14 @@ impl<T: 'static> EventLoop<T> {

pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>),
{
self.run_ondemand(event_handler)
}

pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>),
{
if self.loop_running {
return Err(EventLoopError::AlreadyRunning);
Expand All @@ -570,7 +542,7 @@ impl<T: 'static> EventLoop<T> {

pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
if !self.loop_running {
self.loop_running = true;
Expand All @@ -580,25 +552,23 @@ impl<T: 'static> EventLoop<T> {
// 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);
}

// 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,
);

Expand All @@ -610,7 +580,7 @@ impl<T: 'static> EventLoop<T> {

fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
let start = Instant::now();

Expand All @@ -621,7 +591,7 @@ impl<T: 'static> EventLoop<T> {
// 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) => {
Expand Down Expand Up @@ -663,7 +633,7 @@ impl<T: 'static> EventLoop<T> {
}
}

self.cause = match self.control_flow {
self.cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled {
start,
Expand Down Expand Up @@ -700,6 +670,14 @@ impl<T: 'static> EventLoop<T> {
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<T: 'static> {
Expand Down Expand Up @@ -728,6 +706,7 @@ impl<T> EventLoopProxy<T> {

pub struct EventLoopWindowTarget<T: 'static> {
app: AndroidApp,
control_flow: Cell<ControlFlow>,
redraw_requester: RedrawRequester,
_marker: std::marker::PhantomData<T>,
}
Expand All @@ -746,6 +725,37 @@ impl<T: 'static> EventLoopWindowTarget<T> {
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)]
Expand Down

0 comments on commit 91df56e

Please sign in to comment.