2019-06-21 11:33:15 -04:00
|
|
|
use std::{
|
|
|
|
|
collections::VecDeque,
|
|
|
|
|
ffi::c_void,
|
2019-07-07 22:12:39 +02:00
|
|
|
fmt::{self, Debug},
|
2019-06-21 11:33:15 -04:00
|
|
|
marker::PhantomData,
|
2022-09-08 21:03:25 +02:00
|
|
|
ptr,
|
2019-06-21 11:33:15 -04:00
|
|
|
sync::mpsc::{self, Receiver, Sender},
|
2019-05-25 18:10:41 -07:00
|
|
|
};
|
2019-06-21 11:33:15 -04:00
|
|
|
|
2022-09-08 21:03:25 +02:00
|
|
|
use core_foundation::base::{CFIndex, CFRelease};
|
|
|
|
|
use core_foundation::runloop::{
|
|
|
|
|
kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes, kCFRunLoopDefaultMode,
|
2022-09-08 21:56:53 +02:00
|
|
|
kCFRunLoopExit, CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddSource, CFRunLoopGetMain,
|
|
|
|
|
CFRunLoopObserverCreate, CFRunLoopObserverRef, CFRunLoopSourceContext, CFRunLoopSourceCreate,
|
|
|
|
|
CFRunLoopSourceInvalidate, CFRunLoopSourceRef, CFRunLoopSourceSignal, CFRunLoopWakeUp,
|
2022-09-08 21:03:25 +02:00
|
|
|
};
|
2023-07-29 00:33:03 +02:00
|
|
|
use icrate::Foundation::{MainThreadMarker, NSString};
|
2022-12-28 18:36:32 +01:00
|
|
|
use objc2::ClassType;
|
2022-07-21 22:22:36 +03:00
|
|
|
use raw_window_handle::{RawDisplayHandle, UiKitDisplayHandle};
|
|
|
|
|
|
2019-06-21 11:33:15 -04:00
|
|
|
use crate::{
|
2023-08-13 23:20:09 +04:00
|
|
|
error::EventLoopError,
|
2019-06-21 11:33:15 -04:00
|
|
|
event::Event,
|
|
|
|
|
event_loop::{
|
|
|
|
|
ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget,
|
|
|
|
|
},
|
|
|
|
|
platform::ios::Idiom,
|
|
|
|
|
};
|
|
|
|
|
|
2023-08-13 23:20:09 +04:00
|
|
|
use super::uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen};
|
|
|
|
|
use super::{app_state, monitor, view, MonitorHandle};
|
|
|
|
|
|
2019-10-18 18:31:26 +03:00
|
|
|
#[derive(Debug)]
|
2019-05-25 18:10:41 -07:00
|
|
|
pub struct EventLoopWindowTarget<T: 'static> {
|
2023-08-27 17:04:39 +02:00
|
|
|
pub(super) mtm: MainThreadMarker,
|
|
|
|
|
p: PhantomData<T>,
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2020-07-04 15:46:41 -04:00
|
|
|
impl<T: 'static> EventLoopWindowTarget<T> {
|
|
|
|
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
2023-08-27 17:04:39 +02:00
|
|
|
monitor::uiscreens(self.mtm)
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-21 10:04:28 +02:00
|
|
|
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
2023-08-27 17:04:39 +02:00
|
|
|
Some(MonitorHandle::new(UIScreen::main(self.mtm)))
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
2022-07-21 22:22:36 +03:00
|
|
|
|
|
|
|
|
pub fn raw_display_handle(&self) -> RawDisplayHandle {
|
|
|
|
|
RawDisplayHandle::UiKit(UiKitDisplayHandle::empty())
|
|
|
|
|
}
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
pub struct EventLoop<T: 'static> {
|
2023-08-27 17:04:39 +02:00
|
|
|
mtm: MainThreadMarker,
|
|
|
|
|
sender: Sender<T>,
|
|
|
|
|
receiver: Receiver<T>,
|
2019-05-25 18:10:41 -07:00
|
|
|
window_target: RootEventLoopWindowTarget<T>,
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-10 13:43:33 +03:00
|
|
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
2022-02-16 22:09:03 +01:00
|
|
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
impl<T: 'static> EventLoop<T> {
|
2023-08-13 23:20:09 +04:00
|
|
|
pub(crate) fn new(
|
|
|
|
|
_: &PlatformSpecificEventLoopAttributes,
|
|
|
|
|
) -> Result<EventLoop<T>, EventLoopError> {
|
2023-08-27 17:04:39 +02:00
|
|
|
let mtm = MainThreadMarker::new()
|
|
|
|
|
.expect("On iOS, `EventLoop` must be created on the main thread");
|
2022-09-02 15:48:02 +02:00
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
static mut SINGLETON_INIT: bool = false;
|
|
|
|
|
unsafe {
|
2019-06-21 11:33:15 -04:00
|
|
|
assert!(
|
|
|
|
|
!SINGLETON_INIT,
|
|
|
|
|
"Only one `EventLoop` is supported on iOS. \
|
|
|
|
|
`EventLoopProxy` might be helpful"
|
|
|
|
|
);
|
2019-05-25 18:10:41 -07:00
|
|
|
SINGLETON_INIT = true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 17:04:39 +02:00
|
|
|
let (sender, receiver) = mpsc::channel();
|
2019-05-25 18:10:41 -07:00
|
|
|
|
|
|
|
|
// this line sets up the main run loop before `UIApplicationMain`
|
|
|
|
|
setup_control_flow_observers();
|
|
|
|
|
|
2023-08-13 23:20:09 +04:00
|
|
|
Ok(EventLoop {
|
2023-08-27 17:04:39 +02:00
|
|
|
mtm,
|
|
|
|
|
sender,
|
|
|
|
|
receiver,
|
2019-05-25 18:10:41 -07:00
|
|
|
window_target: RootEventLoopWindowTarget {
|
|
|
|
|
p: EventLoopWindowTarget {
|
2023-08-27 17:04:39 +02:00
|
|
|
mtm,
|
|
|
|
|
p: PhantomData,
|
2019-05-25 18:10:41 -07:00
|
|
|
},
|
|
|
|
|
_marker: PhantomData,
|
2019-06-21 11:33:15 -04:00
|
|
|
},
|
2023-08-13 23:20:09 +04:00
|
|
|
})
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn run<F>(self, event_handler: F) -> !
|
|
|
|
|
where
|
2023-08-06 01:56:56 +04:00
|
|
|
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
|
2019-05-25 18:10:41 -07:00
|
|
|
{
|
|
|
|
|
unsafe {
|
2023-08-27 17:04:39 +02:00
|
|
|
let application = UIApplication::shared(self.mtm);
|
2023-01-14 01:40:24 +03:00
|
|
|
assert!(
|
|
|
|
|
application.is_none(),
|
2019-06-21 11:33:15 -04:00
|
|
|
"\
|
2022-12-28 18:36:32 +01:00
|
|
|
`EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\n\
|
|
|
|
|
Note: `EventLoop::run` calls `UIApplicationMain` on iOS",
|
2019-06-21 11:33:15 -04:00
|
|
|
);
|
2023-08-06 01:56:56 +04:00
|
|
|
|
|
|
|
|
let event_handler = std::mem::transmute::<
|
|
|
|
|
Box<dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow)>,
|
|
|
|
|
Box<EventHandlerCallback<T>>,
|
|
|
|
|
>(Box::new(event_handler));
|
|
|
|
|
|
|
|
|
|
let handler = EventLoopHandler {
|
2019-05-25 18:10:41 -07:00
|
|
|
f: event_handler,
|
2023-08-27 17:04:39 +02:00
|
|
|
receiver: self.receiver,
|
2019-05-25 18:10:41 -07:00
|
|
|
event_loop: self.window_target,
|
2023-08-06 01:56:56 +04:00
|
|
|
};
|
|
|
|
|
|
2023-08-27 17:04:39 +02:00
|
|
|
app_state::will_launch(self.mtm, Box::new(handler));
|
2019-05-25 18:10:41 -07:00
|
|
|
|
2022-09-08 20:30:34 +02:00
|
|
|
// Ensure application delegate is initialized
|
|
|
|
|
view::WinitApplicationDelegate::class();
|
|
|
|
|
|
2019-06-21 11:33:15 -04:00
|
|
|
UIApplicationMain(
|
|
|
|
|
0,
|
|
|
|
|
ptr::null(),
|
2023-01-23 00:01:45 +01:00
|
|
|
None,
|
|
|
|
|
Some(&NSString::from_str("WinitApplicationDelegate")),
|
2019-06-21 11:33:15 -04:00
|
|
|
);
|
2019-05-25 18:10:41 -07:00
|
|
|
unreachable!()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
2023-08-27 17:04:39 +02:00
|
|
|
EventLoopProxy::new(self.sender.clone())
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> {
|
|
|
|
|
&self.window_target
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EventLoopExtIOS
|
|
|
|
|
impl<T: 'static> EventLoop<T> {
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn idiom(&self) -> Idiom {
|
2023-08-27 17:04:39 +02:00
|
|
|
UIDevice::current(self.mtm).userInterfaceIdiom().into()
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct EventLoopProxy<T> {
|
|
|
|
|
sender: Sender<T>,
|
|
|
|
|
source: CFRunLoopSourceRef,
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-09 09:13:14 +09:00
|
|
|
unsafe impl<T: Send> Send for EventLoopProxy<T> {}
|
2019-05-25 18:10:41 -07:00
|
|
|
|
|
|
|
|
impl<T> Clone for EventLoopProxy<T> {
|
|
|
|
|
fn clone(&self) -> EventLoopProxy<T> {
|
|
|
|
|
EventLoopProxy::new(self.sender.clone())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> Drop for EventLoopProxy<T> {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
unsafe {
|
|
|
|
|
CFRunLoopSourceInvalidate(self.source);
|
|
|
|
|
CFRelease(self.source as _);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> EventLoopProxy<T> {
|
|
|
|
|
fn new(sender: Sender<T>) -> EventLoopProxy<T> {
|
|
|
|
|
unsafe {
|
2019-07-13 01:05:07 +02:00
|
|
|
// just wake up the eventloop
|
2022-09-08 21:03:25 +02:00
|
|
|
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
|
2019-05-25 18:10:41 -07:00
|
|
|
|
|
|
|
|
// adding a Source to the main CFRunLoop lets us wake it up and
|
|
|
|
|
// process user events through the normal OS EventLoop mechanisms.
|
|
|
|
|
let rl = CFRunLoopGetMain();
|
2022-09-08 21:03:25 +02:00
|
|
|
let mut context = CFRunLoopSourceContext {
|
|
|
|
|
version: 0,
|
|
|
|
|
info: ptr::null_mut(),
|
|
|
|
|
retain: None,
|
|
|
|
|
release: None,
|
|
|
|
|
copyDescription: None,
|
|
|
|
|
equal: None,
|
|
|
|
|
hash: None,
|
|
|
|
|
schedule: None,
|
|
|
|
|
cancel: None,
|
|
|
|
|
perform: event_loop_proxy_handler,
|
|
|
|
|
};
|
2019-06-21 11:33:15 -04:00
|
|
|
let source =
|
|
|
|
|
CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context);
|
2019-05-25 18:10:41 -07:00
|
|
|
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
|
|
|
|
CFRunLoopWakeUp(rl);
|
|
|
|
|
|
2019-06-21 11:33:15 -04:00
|
|
|
EventLoopProxy { sender, source }
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-07 18:22:03 +01:00
|
|
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
|
|
|
|
self.sender
|
|
|
|
|
.send(event)
|
|
|
|
|
.map_err(|::std::sync::mpsc::SendError(x)| EventLoopClosed(x))?;
|
2019-05-25 18:10:41 -07:00
|
|
|
unsafe {
|
|
|
|
|
// let the main thread know there's a new event
|
|
|
|
|
CFRunLoopSourceSignal(self.source);
|
|
|
|
|
let rl = CFRunLoopGetMain();
|
|
|
|
|
CFRunLoopWakeUp(rl);
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn setup_control_flow_observers() {
|
|
|
|
|
unsafe {
|
|
|
|
|
// begin is queued with the highest priority to ensure it is processed before other observers
|
2019-06-21 11:33:15 -04:00
|
|
|
extern "C" fn control_flow_begin_handler(
|
2019-05-25 18:10:41 -07:00
|
|
|
_: CFRunLoopObserverRef,
|
|
|
|
|
activity: CFRunLoopActivity,
|
|
|
|
|
_: *mut c_void,
|
|
|
|
|
) {
|
2023-08-27 17:04:39 +02:00
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
|
match activity {
|
|
|
|
|
kCFRunLoopAfterWaiting => app_state::handle_wakeup_transition(mtm),
|
|
|
|
|
_ => unreachable!(),
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 14:23:11 -07:00
|
|
|
// Core Animation registers its `CFRunLoopObserver` that performs drawing operations in
|
|
|
|
|
// `CA::Transaction::ensure_implicit` with a priority of `0x1e8480`. We set the main_end
|
2023-07-28 17:37:56 +01:00
|
|
|
// priority to be 0, in order to send AboutToWait before RedrawRequested. This value was
|
2019-09-04 14:23:11 -07:00
|
|
|
// chosen conservatively to guard against apple using different priorities for their redraw
|
|
|
|
|
// observers in different OS's or on different devices. If it so happens that it's too
|
2023-07-28 17:37:56 +01:00
|
|
|
// conservative, the main symptom would be non-redraw events coming in after `AboutToWait`.
|
2019-09-04 14:23:11 -07:00
|
|
|
//
|
|
|
|
|
// The value of `0x1e8480` was determined by inspecting stack traces and the associated
|
|
|
|
|
// registers for every `CFRunLoopAddObserver` call on an iPad Air 2 running iOS 11.4.
|
|
|
|
|
//
|
|
|
|
|
// Also tested to be `0x1e8480` on iPhone 8, iOS 13 beta 4.
|
|
|
|
|
extern "C" fn control_flow_main_end_handler(
|
|
|
|
|
_: CFRunLoopObserverRef,
|
|
|
|
|
activity: CFRunLoopActivity,
|
|
|
|
|
_: *mut c_void,
|
|
|
|
|
) {
|
2023-08-27 17:04:39 +02:00
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
|
match activity {
|
|
|
|
|
kCFRunLoopBeforeWaiting => app_state::handle_main_events_cleared(mtm),
|
|
|
|
|
kCFRunLoopExit => unimplemented!(), // not expected to ever happen
|
|
|
|
|
_ => unreachable!(),
|
2019-09-04 14:23:11 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
// end is queued with the lowest priority to ensure it is processed after other observers
|
2019-06-21 11:33:15 -04:00
|
|
|
extern "C" fn control_flow_end_handler(
|
2019-05-25 18:10:41 -07:00
|
|
|
_: CFRunLoopObserverRef,
|
|
|
|
|
activity: CFRunLoopActivity,
|
|
|
|
|
_: *mut c_void,
|
|
|
|
|
) {
|
2023-08-27 17:04:39 +02:00
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
|
match activity {
|
|
|
|
|
kCFRunLoopBeforeWaiting => app_state::handle_events_cleared(mtm),
|
|
|
|
|
kCFRunLoopExit => unimplemented!(), // not expected to ever happen
|
|
|
|
|
_ => unreachable!(),
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let main_loop = CFRunLoopGetMain();
|
2019-09-04 14:23:11 -07:00
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
let begin_observer = CFRunLoopObserverCreate(
|
|
|
|
|
ptr::null_mut(),
|
2022-09-08 21:56:53 +02:00
|
|
|
kCFRunLoopAfterWaiting,
|
2019-05-25 18:10:41 -07:00
|
|
|
1, // repeat = true
|
|
|
|
|
CFIndex::min_value(),
|
|
|
|
|
control_flow_begin_handler,
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
);
|
|
|
|
|
CFRunLoopAddObserver(main_loop, begin_observer, kCFRunLoopDefaultMode);
|
2019-09-04 14:23:11 -07:00
|
|
|
|
|
|
|
|
let main_end_observer = CFRunLoopObserverCreate(
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
kCFRunLoopExit | kCFRunLoopBeforeWaiting,
|
|
|
|
|
1, // repeat = true
|
|
|
|
|
0, // see comment on `control_flow_main_end_handler`
|
|
|
|
|
control_flow_main_end_handler,
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
);
|
|
|
|
|
CFRunLoopAddObserver(main_loop, main_end_observer, kCFRunLoopDefaultMode);
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
let end_observer = CFRunLoopObserverCreate(
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
kCFRunLoopExit | kCFRunLoopBeforeWaiting,
|
|
|
|
|
1, // repeat = true
|
|
|
|
|
CFIndex::max_value(),
|
|
|
|
|
control_flow_end_handler,
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
);
|
|
|
|
|
CFRunLoopAddObserver(main_loop, end_observer, kCFRunLoopDefaultMode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum Never {}
|
|
|
|
|
|
2023-08-06 01:56:56 +04:00
|
|
|
type EventHandlerCallback<T> =
|
|
|
|
|
dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static;
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
pub trait EventHandler: Debug {
|
2023-07-31 00:39:01 +04:00
|
|
|
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
|
2019-05-25 18:10:41 -07:00
|
|
|
fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-06 01:56:56 +04:00
|
|
|
struct EventLoopHandler<T: 'static> {
|
|
|
|
|
f: Box<EventHandlerCallback<T>>,
|
2023-08-27 17:04:39 +02:00
|
|
|
receiver: Receiver<T>,
|
2019-05-25 18:10:41 -07:00
|
|
|
event_loop: RootEventLoopWindowTarget<T>,
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-06 01:56:56 +04:00
|
|
|
impl<T: 'static> Debug for EventLoopHandler<T> {
|
2019-07-09 23:49:07 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("EventLoopHandler")
|
2019-05-25 18:10:41 -07:00
|
|
|
.field("event_loop", &self.event_loop)
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-06 01:56:56 +04:00
|
|
|
impl<T: 'static> EventHandler for EventLoopHandler<T> {
|
2023-07-31 00:39:01 +04:00
|
|
|
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
|
2019-05-25 18:10:41 -07:00
|
|
|
(self.f)(
|
|
|
|
|
event.map_nonuser_event().unwrap(),
|
|
|
|
|
&self.event_loop,
|
|
|
|
|
control_flow,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
|
2023-08-27 17:04:39 +02:00
|
|
|
for event in self.receiver.try_iter() {
|
2019-06-21 11:33:15 -04:00
|
|
|
(self.f)(Event::UserEvent(event), &self.event_loop, control_flow);
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|