Skip to content

Commit

Permalink
iOS implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Aug 28, 2023
1 parent 9e6b297 commit b28ec78
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 46 deletions.
48 changes: 20 additions & 28 deletions src/platform_impl/ios/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ use objc2::runtime::AnyObject;
use objc2::{msg_send, sel};
use once_cell::sync::Lazy;

use super::event_loop::{EventHandler, Never};
use super::event_loop::{ControlFlow, EventHandler, Never};
use super::uikit::UIView;
use super::view::WinitUIWindow;
use crate::{
dpi::PhysicalSize,
event::{Event, InnerSizeWriter, StartCause, WindowEvent},
event_loop::ControlFlow,
window::WindowId as RootWindowId,
};

Expand Down Expand Up @@ -121,15 +120,15 @@ enum AppStateImpl {
Terminated,
}

struct AppState {
pub(crate) struct AppState {
// This should never be `None`, except for briefly during a state transition.
app_state: Option<AppStateImpl>,
control_flow: ControlFlow,
waker: EventLoopWaker,
}

impl AppState {
fn get_mut(_mtm: MainThreadMarker) -> RefMut<'static, AppState> {
pub(crate) fn get_mut(_mtm: MainThreadMarker) -> RefMut<'static, AppState> {
// basically everything in UIKit requires the main thread, so it's pointless to use the
// std::sync APIs.
// must be mut because plain `static` requires `Sync`
Expand Down Expand Up @@ -290,7 +289,7 @@ impl AppState {
};
(waiting_event_handler, event)
}
(ControlFlow::ExitWithCode(_), _) => bug!("unexpected `ControlFlow` `Exit`"),
(ControlFlow::Exit, _) => bug!("unexpected `ControlFlow` `Exit`"),
s => bug!("`EventHandler` unexpectedly woke up {:?}", s),
};

Expand Down Expand Up @@ -443,7 +442,7 @@ impl AppState {
});
self.waker.start()
}
(_, ControlFlow::ExitWithCode(_)) => {
(_, ControlFlow::Exit) => {
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
// it is not possible to quit an iOS app gracefully and programatically
warn!("`ControlFlow::Exit` ignored on iOS");
Expand All @@ -458,6 +457,10 @@ impl AppState {
s => bug!("`LoopExiting` happened while not processing events {:?}", s),
}
}

pub(crate) fn set_control_flow(&mut self, control_flow: ControlFlow) {
self.control_flow = control_flow;
}
}

pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Id<WinitUIWindow>) {
Expand Down Expand Up @@ -602,7 +605,6 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
processing_redraws,
} => (event_handler, active_control_flow, processing_redraws),
};
let mut control_flow = this.control_flow;
drop(this);

for wrapper in events {
Expand All @@ -616,10 +618,10 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
event
);
}
event_handler.handle_nonuser_event(event, &mut control_flow)
event_handler.handle_nonuser_event(event)
}
EventWrapper::ScaleFactorChanged(event) => {
handle_hidpi_proxy(&mut event_handler, control_flow, event)
handle_hidpi_proxy(&mut event_handler, event)
}
}
}
Expand Down Expand Up @@ -657,7 +659,6 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
active_control_flow,
}
});
this.control_flow = control_flow;
break;
}
drop(this);
Expand All @@ -673,10 +674,10 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
event
);
}
event_handler.handle_nonuser_event(event, &mut control_flow)
event_handler.handle_nonuser_event(event)
}
EventWrapper::ScaleFactorChanged(event) => {
handle_hidpi_proxy(&mut event_handler, control_flow, event)
handle_hidpi_proxy(&mut event_handler, event)
}
}
}
Expand All @@ -685,7 +686,6 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(

fn handle_user_events(mtm: MainThreadMarker) {
let mut this = AppState::get_mut(mtm);
let mut control_flow = this.control_flow;
let (mut event_handler, active_control_flow, processing_redraws) =
match this.try_user_callback_transition() {
UserCallbackTransitionResult::ReentrancyPrevented { .. } => {
Expand All @@ -702,7 +702,7 @@ fn handle_user_events(mtm: MainThreadMarker) {
}
drop(this);

event_handler.handle_user_events(&mut control_flow);
event_handler.handle_user_events();

loop {
let mut this = AppState::get_mut(mtm);
Expand All @@ -726,22 +726,19 @@ fn handle_user_events(mtm: MainThreadMarker) {
queued_gpu_redraws,
active_control_flow,
});
this.control_flow = control_flow;
break;
}
drop(this);

for wrapper in queued_events {
match wrapper {
EventWrapper::StaticEvent(event) => {
event_handler.handle_nonuser_event(event, &mut control_flow)
}
EventWrapper::StaticEvent(event) => event_handler.handle_nonuser_event(event),
EventWrapper::ScaleFactorChanged(event) => {
handle_hidpi_proxy(&mut event_handler, control_flow, event)
handle_hidpi_proxy(&mut event_handler, event)
}
}
}
event_handler.handle_user_events(&mut control_flow);
event_handler.handle_user_events();
}
}

Expand Down Expand Up @@ -782,17 +779,12 @@ pub fn handle_events_cleared(mtm: MainThreadMarker) {
pub fn terminated(mtm: MainThreadMarker) {
let mut this = AppState::get_mut(mtm);
let mut event_handler = this.terminated_transition();
let mut control_flow = this.control_flow;
drop(this);

event_handler.handle_nonuser_event(Event::LoopExiting, &mut control_flow)
event_handler.handle_nonuser_event(Event::LoopExiting)
}

fn handle_hidpi_proxy(
event_handler: &mut Box<dyn EventHandler>,
mut control_flow: ControlFlow,
event: ScaleFactorChanged,
) {
fn handle_hidpi_proxy(event_handler: &mut Box<dyn EventHandler>, event: ScaleFactorChanged) {
let ScaleFactorChanged {
suggested_size,
scale_factor,
Expand All @@ -806,7 +798,7 @@ fn handle_hidpi_proxy(
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)),
},
};
event_handler.handle_nonuser_event(event, &mut control_flow);
event_handler.handle_nonuser_event(event);
let (view, screen_frame) = get_view_and_screen_frame(&window);
let physical_size = *new_inner_size.lock().unwrap();
drop(new_inner_size);
Expand Down
64 changes: 46 additions & 18 deletions src/platform_impl/ios/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{
marker::PhantomData,
ptr,
sync::mpsc::{self, Receiver, Sender},
time::Instant,
};

use core_foundation::base::{CFIndex, CFRelease};
Expand All @@ -21,14 +22,15 @@ use raw_window_handle::{RawDisplayHandle, UiKitDisplayHandle};
use crate::{
error::EventLoopError,
event::Event,
event_loop::{
ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget,
},
event_loop::{EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget},
platform::ios::Idiom,
};

use super::uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen};
use super::{app_state, monitor, view, MonitorHandle};
use super::{
app_state::AppState,
uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen},
};

#[derive(Debug)]
pub struct EventLoopWindowTarget<T: 'static> {
Expand All @@ -48,6 +50,22 @@ impl<T: 'static> EventLoopWindowTarget<T> {
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::UiKit(UiKitDisplayHandle::empty())
}

pub(crate) fn set_poll(&self) {
AppState::get_mut(self.mtm).set_control_flow(ControlFlow::Poll)
}

pub(crate) fn set_wait(&self) {
AppState::get_mut(self.mtm).set_control_flow(ControlFlow::Wait)
}

pub(crate) fn set_wait_until(&self, instant: Instant) {
AppState::get_mut(self.mtm).set_control_flow(ControlFlow::WaitUntil(instant))
}

pub(crate) fn set_exit(&self) {
AppState::get_mut(self.mtm).set_control_flow(ControlFlow::Exit)
}
}

pub struct EventLoop<T: 'static> {
Expand Down Expand Up @@ -98,7 +116,7 @@ impl<T: 'static> EventLoop<T> {

pub fn run<F>(self, event_handler: F) -> !
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
unsafe {
let application = UIApplication::shared(self.mtm);
Expand All @@ -110,7 +128,7 @@ impl<T: 'static> EventLoop<T> {
);

let event_handler = std::mem::transmute::<
Box<dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>)>,
Box<EventHandlerCallback<T>>,
>(Box::new(event_handler));

Expand Down Expand Up @@ -217,6 +235,21 @@ impl<T> EventLoopProxy<T> {
}
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum ControlFlow {
Poll,
Wait,
WaitUntil(Instant),
Exit,
}

impl Default for ControlFlow {
#[inline(always)]
fn default() -> Self {
Self::Poll
}
}

fn setup_control_flow_observers() {
unsafe {
// begin is queued with the highest priority to ensure it is processed before other observers
Expand Down Expand Up @@ -310,12 +343,11 @@ fn setup_control_flow_observers() {
#[derive(Debug)]
pub enum Never {}

type EventHandlerCallback<T> =
dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static;
type EventHandlerCallback<T> = dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>) + 'static;

pub trait EventHandler: Debug {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
fn handle_nonuser_event(&mut self, event: Event<Never>);
fn handle_user_events(&mut self);
}

struct EventLoopHandler<T: 'static> {
Expand All @@ -333,17 +365,13 @@ impl<T: 'static> Debug for EventLoopHandler<T> {
}

impl<T: 'static> EventHandler for EventLoopHandler<T> {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
(self.f)(
event.map_nonuser_event().unwrap(),
&self.event_loop,
control_flow,
);
fn handle_nonuser_event(&mut self, event: Event<Never>) {
(self.f)(event.map_nonuser_event().unwrap(), &self.event_loop);
}

fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
fn handle_user_events(&mut self) {
for event in self.receiver.try_iter() {
(self.f)(Event::UserEvent(event), &self.event_loop, control_flow);
(self.f)(Event::UserEvent(event), &self.event_loop);
}
}
}

0 comments on commit b28ec78

Please sign in to comment.