diff --git a/src/platform_impl/ios/app_state.rs b/src/platform_impl/ios/app_state.rs index b486c2f624..eac89365f8 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -3,7 +3,7 @@ use std::{ cell::{RefCell, RefMut}, collections::HashSet, - mem, + fmt, mem, os::raw::c_void, ptr, sync::{Arc, Mutex}, @@ -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::uikit::UIView; use super::view::WinitUIWindow; use crate::{ dpi::PhysicalSize, event::{Event, InnerSizeWriter, StartCause, WindowEvent}, - event_loop::ControlFlow, + event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget}, window::WindowId as RootWindowId, }; @@ -47,8 +46,32 @@ macro_rules! bug_assert { } #[derive(Debug)] -pub enum EventWrapper { - StaticEvent(Event), +pub(crate) struct HandlePendingUserEvents; + +pub(crate) struct EventLoopHandler { + #[allow(clippy::type_complexity)] + pub(crate) handler: Box, &RootEventLoopWindowTarget)>, + pub(crate) event_loop: RootEventLoopWindowTarget, +} + +impl fmt::Debug for EventLoopHandler { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EventLoopHandler") + .field("handler", &"...") + .field("event_loop", &self.event_loop) + .finish() + } +} + +impl EventLoopHandler { + fn handle_event(&mut self, event: Event) { + (self.handler)(event, &self.event_loop) + } +} + +#[derive(Debug)] +pub(crate) enum EventWrapper { + StaticEvent(Event), ScaleFactorChanged(ScaleFactorChanged), } @@ -61,7 +84,7 @@ pub struct ScaleFactorChanged { enum UserCallbackTransitionResult<'a> { Success { - event_handler: Box, + handler: EventLoopHandler, active_control_flow: ControlFlow, processing_redraws: bool, }, @@ -70,7 +93,7 @@ enum UserCallbackTransitionResult<'a> { }, } -impl Event { +impl Event { fn is_redraw(&self) -> bool { matches!( self, @@ -94,11 +117,11 @@ enum AppStateImpl { Launching { queued_windows: Vec>, queued_events: Vec, - queued_event_handler: Box, + queued_handler: EventLoopHandler, queued_gpu_redraws: HashSet>, }, ProcessingEvents { - event_handler: Box, + handler: EventLoopHandler, queued_gpu_redraws: HashSet>, active_control_flow: ControlFlow, }, @@ -108,15 +131,15 @@ enum AppStateImpl { queued_gpu_redraws: HashSet>, }, ProcessingRedraws { - event_handler: Box, + handler: EventLoopHandler, active_control_flow: ControlFlow, }, Waiting { - waiting_event_handler: Box, + waiting_handler: EventLoopHandler, start: Instant, }, PollFinished { - waiting_event_handler: Box, + waiting_handler: EventLoopHandler, }, Terminated, } @@ -204,7 +227,7 @@ impl AppState { matches!(self.state(), AppStateImpl::Terminated) } - fn will_launch_transition(&mut self, queued_event_handler: Box) { + fn will_launch_transition(&mut self, queued_handler: EventLoopHandler) { let (queued_windows, queued_events, queued_gpu_redraws) = match self.take_state() { AppStateImpl::NotLaunched { queued_windows, @@ -216,28 +239,28 @@ impl AppState { self.set_state(AppStateImpl::Launching { queued_windows, queued_events, - queued_event_handler, + queued_handler, queued_gpu_redraws, }); } fn did_finish_launching_transition(&mut self) -> (Vec>, Vec) { - let (windows, events, event_handler, queued_gpu_redraws) = match self.take_state() { + let (windows, events, handler, queued_gpu_redraws) = match self.take_state() { AppStateImpl::Launching { queued_windows, queued_events, - queued_event_handler, + queued_handler, queued_gpu_redraws, } => ( queued_windows, queued_events, - queued_event_handler, + queued_handler, queued_gpu_redraws, ), s => bug!("unexpected state {:?}", s), }; self.set_state(AppStateImpl::ProcessingEvents { - event_handler, + handler, active_control_flow: self.control_flow, queued_gpu_redraws, }); @@ -251,24 +274,19 @@ impl AppState { return None; } - let (event_handler, event) = match (self.control_flow, self.take_state()) { - ( - ControlFlow::Poll, - AppStateImpl::PollFinished { - waiting_event_handler, - }, - ) => ( - waiting_event_handler, + let (handler, event) = match (self.control_flow, self.take_state()) { + (ControlFlow::Poll, AppStateImpl::PollFinished { waiting_handler }) => ( + waiting_handler, EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll)), ), ( ControlFlow::Wait, AppStateImpl::Waiting { - waiting_event_handler, + waiting_handler, start, }, ) => ( - waiting_event_handler, + waiting_handler, EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled { start, requested_resume: None, @@ -277,7 +295,7 @@ impl AppState { ( ControlFlow::WaitUntil(requested_resume), AppStateImpl::Waiting { - waiting_event_handler, + waiting_handler, start, }, ) => { @@ -292,13 +310,13 @@ impl AppState { requested_resume: Some(requested_resume), })) }; - (waiting_event_handler, event) + (waiting_handler, event) } s => bug!("`EventHandler` unexpectedly woke up {:?}", s), }; self.set_state(AppStateImpl::ProcessingEvents { - event_handler, + handler, queued_gpu_redraws: Default::default(), active_control_flow: self.control_flow, }); @@ -343,25 +361,20 @@ impl AppState { } } - let (event_handler, queued_gpu_redraws, active_control_flow, processing_redraws) = + let (handler, queued_gpu_redraws, active_control_flow, processing_redraws) = match self.take_state() { AppStateImpl::Launching { .. } | AppStateImpl::NotLaunched { .. } | AppStateImpl::InUserCallback { .. } => unreachable!(), AppStateImpl::ProcessingEvents { - event_handler, - queued_gpu_redraws, - active_control_flow, - } => ( - event_handler, + handler, queued_gpu_redraws, active_control_flow, - false, - ), + } => (handler, queued_gpu_redraws, active_control_flow, false), AppStateImpl::ProcessingRedraws { - event_handler, + handler, active_control_flow, - } => (event_handler, Default::default(), active_control_flow, true), + } => (handler, Default::default(), active_control_flow, true), AppStateImpl::PollFinished { .. } | AppStateImpl::Waiting { .. } | AppStateImpl::Terminated => unreachable!(), @@ -371,23 +384,23 @@ impl AppState { queued_gpu_redraws, }); UserCallbackTransitionResult::Success { - event_handler, + handler, active_control_flow, processing_redraws, } } fn main_events_cleared_transition(&mut self) -> HashSet> { - let (event_handler, queued_gpu_redraws, active_control_flow) = match self.take_state() { + let (handler, queued_gpu_redraws, active_control_flow) = match self.take_state() { AppStateImpl::ProcessingEvents { - event_handler, + handler, queued_gpu_redraws, active_control_flow, - } => (event_handler, queued_gpu_redraws, active_control_flow), + } => (handler, queued_gpu_redraws, active_control_flow), s => bug!("unexpected state {:?}", s), }; self.set_state(AppStateImpl::ProcessingRedraws { - event_handler, + handler, active_control_flow, }); queued_gpu_redraws @@ -397,11 +410,11 @@ impl AppState { if !self.has_launched() || self.has_terminated() { return; } - let (waiting_event_handler, old) = match self.take_state() { + let (waiting_handler, old) = match self.take_state() { AppStateImpl::ProcessingRedraws { - event_handler, + handler, active_control_flow, - } => (event_handler, active_control_flow), + } => (handler, active_control_flow), s => bug!("unexpected state {:?}", s), }; @@ -410,7 +423,7 @@ impl AppState { (ControlFlow::Wait, ControlFlow::Wait) => { let start = Instant::now(); self.set_state(AppStateImpl::Waiting { - waiting_event_handler, + waiting_handler, start, }); } @@ -419,14 +432,14 @@ impl AppState { { let start = Instant::now(); self.set_state(AppStateImpl::Waiting { - waiting_event_handler, + waiting_handler, start, }); } (_, ControlFlow::Wait) => { let start = Instant::now(); self.set_state(AppStateImpl::Waiting { - waiting_event_handler, + waiting_handler, start, }); self.waker.stop() @@ -434,24 +447,22 @@ impl AppState { (_, ControlFlow::WaitUntil(new_instant)) => { let start = Instant::now(); self.set_state(AppStateImpl::Waiting { - waiting_event_handler, + waiting_handler, start, }); self.waker.start_at(new_instant) } // Unlike on macOS, handle Poll to Poll transition here to call the waker (_, ControlFlow::Poll) => { - self.set_state(AppStateImpl::PollFinished { - waiting_event_handler, - }); + self.set_state(AppStateImpl::PollFinished { waiting_handler }); self.waker.start() } } } - fn terminated_transition(&mut self) -> Box { + fn terminated_transition(&mut self) -> EventLoopHandler { match self.replace_state(AppStateImpl::Terminated) { - AppStateImpl::ProcessingEvents { event_handler, .. } => event_handler, + AppStateImpl::ProcessingEvents { handler, .. } => handler, s => bug!("`LoopExiting` happened while not processing events {:?}", s), } } @@ -516,8 +527,8 @@ pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Id) { - AppState::get_mut(mtm).will_launch_transition(queued_event_handler) +pub(crate) fn will_launch(mtm: MainThreadMarker, queued_handler: EventLoopHandler) { + AppState::get_mut(mtm).will_launch_transition(queued_handler) } pub fn did_finish_launching(mtm: MainThreadMarker) { @@ -594,17 +605,17 @@ pub(crate) fn handle_nonuser_events>( return; } - let (mut event_handler, active_control_flow, processing_redraws) = + let (mut handler, active_control_flow, processing_redraws) = match this.try_user_callback_transition() { UserCallbackTransitionResult::ReentrancyPrevented { queued_events } => { queued_events.extend(events); return; } UserCallbackTransitionResult::Success { - event_handler, + handler, active_control_flow, processing_redraws, - } => (event_handler, active_control_flow, processing_redraws), + } => (handler, active_control_flow, processing_redraws), }; drop(this); @@ -619,11 +630,9 @@ pub(crate) fn handle_nonuser_events>( event ); } - event_handler.handle_nonuser_event(event) - } - EventWrapper::ScaleFactorChanged(event) => { - handle_hidpi_proxy(&mut event_handler, event) + handler.handle_event(event) } + EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), } } @@ -650,12 +659,12 @@ pub(crate) fn handle_nonuser_events>( "redraw queued while processing redraws" ); AppStateImpl::ProcessingRedraws { - event_handler, + handler, active_control_flow, } } else { AppStateImpl::ProcessingEvents { - event_handler, + handler, queued_gpu_redraws, active_control_flow, } @@ -675,11 +684,9 @@ pub(crate) fn handle_nonuser_events>( event ); } - event_handler.handle_nonuser_event(event) - } - EventWrapper::ScaleFactorChanged(event) => { - handle_hidpi_proxy(&mut event_handler, event) + handler.handle_event(event) } + EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), } } } @@ -687,23 +694,23 @@ pub(crate) fn handle_nonuser_events>( fn handle_user_events(mtm: MainThreadMarker) { let mut this = AppState::get_mut(mtm); - let (mut event_handler, active_control_flow, processing_redraws) = + let (mut handler, active_control_flow, processing_redraws) = match this.try_user_callback_transition() { UserCallbackTransitionResult::ReentrancyPrevented { .. } => { bug!("unexpected attempted to process an event") } UserCallbackTransitionResult::Success { - event_handler, + handler, active_control_flow, processing_redraws, - } => (event_handler, active_control_flow, processing_redraws), + } => (handler, active_control_flow, processing_redraws), }; if processing_redraws { bug!("user events attempted to be sent out while `ProcessingRedraws`"); } drop(this); - event_handler.handle_user_events(); + handler.handle_event(Event::UserEvent(HandlePendingUserEvents)); loop { let mut this = AppState::get_mut(mtm); @@ -723,7 +730,7 @@ fn handle_user_events(mtm: MainThreadMarker) { _ => unreachable!(), }; this.app_state = Some(AppStateImpl::ProcessingEvents { - event_handler, + handler, queued_gpu_redraws, active_control_flow, }); @@ -733,13 +740,12 @@ fn handle_user_events(mtm: MainThreadMarker) { for wrapper in queued_events { match wrapper { - EventWrapper::StaticEvent(event) => event_handler.handle_nonuser_event(event), - EventWrapper::ScaleFactorChanged(event) => { - handle_hidpi_proxy(&mut event_handler, event) - } + EventWrapper::StaticEvent(event) => handler.handle_event(event), + EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), } } - event_handler.handle_user_events(); + + handler.handle_event(Event::UserEvent(HandlePendingUserEvents)); } } @@ -779,13 +785,13 @@ 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 handler = this.terminated_transition(); drop(this); - event_handler.handle_nonuser_event(Event::LoopExiting) + handler.handle_event(Event::LoopExiting) } -fn handle_hidpi_proxy(event_handler: &mut Box, event: ScaleFactorChanged) { +fn handle_hidpi_proxy(handler: &mut EventLoopHandler, event: ScaleFactorChanged) { let ScaleFactorChanged { suggested_size, scale_factor, @@ -799,7 +805,7 @@ fn handle_hidpi_proxy(event_handler: &mut Box, event: ScaleFac inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), }, }; - event_handler.handle_nonuser_event(event); + handler.handle_event(event); let (view, screen_frame) = get_view_and_screen_frame(&window); let physical_size = *new_inner_size.lock().unwrap(); drop(new_inner_size); diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index 78cc7021f8..cf69eec5a8 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -1,7 +1,6 @@ use std::{ collections::VecDeque, ffi::c_void, - fmt::{self, Debug}, marker::PhantomData, ptr, sync::mpsc::{self, Receiver, Sender}, @@ -25,6 +24,7 @@ use crate::{ EventLoopWindowTarget as RootEventLoopWindowTarget, }, platform::ios::Idiom, + platform_impl::platform::app_state::{EventLoopHandler, HandlePendingUserEvents}, }; use super::{app_state, monitor, view, MonitorHandle}; @@ -108,6 +108,20 @@ impl OwnedDisplayHandle { } } +fn map_user_event( + mut handler: impl FnMut(Event, &RootEventLoopWindowTarget), + receiver: mpsc::Receiver, +) -> impl FnMut(Event, &RootEventLoopWindowTarget) { + move |event, window_target| match event.map_nonuser_event() { + Ok(event) => (handler)(event, window_target), + Err(_) => { + for event in receiver.try_iter() { + (handler)(Event::UserEvent(event), window_target); + } + } + } +} + pub struct EventLoop { mtm: MainThreadMarker, sender: Sender, @@ -151,43 +165,46 @@ impl EventLoop { }) } - pub fn run(self, event_handler: F) -> ! + pub fn run(self, handler: F) -> ! where F: FnMut(Event, &RootEventLoopWindowTarget), { - unsafe { - let application = UIApplication::shared(self.mtm); - assert!( - application.is_none(), - "\ + let application = UIApplication::shared(self.mtm); + assert!( + application.is_none(), + "\ `EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\n\ Note: `EventLoop::run` calls `UIApplicationMain` on iOS", - ); + ); - let event_handler = std::mem::transmute::< - Box, &RootEventLoopWindowTarget)>, - Box>, - >(Box::new(event_handler)); + let handler = map_user_event(handler, self.receiver); - let handler = EventLoopHandler { - f: event_handler, - receiver: self.receiver, - event_loop: self.window_target, - }; + let handler = unsafe { + std::mem::transmute::< + Box, &RootEventLoopWindowTarget)>, + Box, &RootEventLoopWindowTarget)>, + >(Box::new(handler)) + }; - app_state::will_launch(self.mtm, Box::new(handler)); + let handler = EventLoopHandler { + handler, + event_loop: self.window_target, + }; - // Ensure application delegate is initialized - view::WinitApplicationDelegate::class(); + app_state::will_launch(self.mtm, handler); + // Ensure application delegate is initialized + view::WinitApplicationDelegate::class(); + + unsafe { UIApplicationMain( 0, ptr::null(), None, Some(&NSString::from_str("WinitApplicationDelegate")), - ); - unreachable!() - } + ) + }; + unreachable!() } pub fn create_proxy(&self) -> EventLoopProxy { @@ -361,39 +378,3 @@ fn setup_control_flow_observers() { CFRunLoopAddObserver(main_loop, end_observer, kCFRunLoopDefaultMode); } } - -#[derive(Debug)] -pub enum Never {} - -type EventHandlerCallback = dyn FnMut(Event, &RootEventLoopWindowTarget) + 'static; - -pub trait EventHandler: Debug { - fn handle_nonuser_event(&mut self, event: Event); - fn handle_user_events(&mut self); -} - -struct EventLoopHandler { - f: Box>, - receiver: Receiver, - event_loop: RootEventLoopWindowTarget, -} - -impl Debug for EventLoopHandler { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EventLoopHandler") - .field("event_loop", &self.event_loop) - .finish() - } -} - -impl EventHandler for EventLoopHandler { - fn handle_nonuser_event(&mut self, event: Event) { - (self.f)(event.map_nonuser_event().unwrap(), &self.event_loop); - } - - fn handle_user_events(&mut self) { - for event in self.receiver.try_iter() { - (self.f)(Event::UserEvent(event), &self.event_loop); - } - } -} diff --git a/src/platform_impl/macos/app_delegate.rs b/src/platform_impl/macos/app_delegate.rs index c6d239e02f..ee3ac878d3 100644 --- a/src/platform_impl/macos/app_delegate.rs +++ b/src/platform_impl/macos/app_delegate.rs @@ -1,9 +1,8 @@ -use std::cell::{Cell, RefCell, RefMut}; +use std::cell::{Cell, RefCell}; use std::collections::VecDeque; -use std::fmt; use std::mem; use std::rc::{Rc, Weak}; -use std::sync::{mpsc, Arc, Mutex}; +use std::sync::{Arc, Mutex}; use std::time::Instant; use icrate::AppKit::{NSApplication, NSApplicationActivationPolicy, NSApplicationDelegate}; @@ -14,7 +13,6 @@ use objc2::{declare_class, msg_send_id, mutability, ClassType, DeclaredClass}; use super::event_loop::{stop_app_immediately, PanicInfo}; use super::observer::{EventLoopWaker, RunLoop}; -use super::util::Never; use super::window::WinitWindow; use super::{menu, WindowId, DEVICE_ID}; use crate::dpi::PhysicalSize; @@ -30,7 +28,7 @@ pub(super) struct State { /// Whether the application is currently executing a callback. in_callback: Cell, /// The lifetime-erased callback. - callback: RefCell>>, + callback: RefCell>, stop_on_launch: Cell, stop_before_wait: Cell, stop_after_wait: Cell, @@ -158,17 +156,16 @@ impl ApplicationDelegate { /// All public APIs that take an event callback (`run`, `run_on_demand`, /// `pump_events`) _must_ pair a call to `set_callback` with /// a call to `clear_callback` before returning to avoid undefined behaviour. - pub unsafe fn set_callback( + #[allow(clippy::type_complexity)] + pub unsafe fn set_callback( &self, - callback: Weak>, + callback: Weak, &RootWindowTarget)>>, window_target: Rc, - receiver: Rc>, ) { - *self.ivars().callback.borrow_mut() = Some(Box::new(EventLoopHandler { + *self.ivars().callback.borrow_mut() = Some(EventLoopHandler { callback, window_target, - receiver, - })); + }); } pub fn clear_callback(&self) { @@ -208,7 +205,7 @@ impl ApplicationDelegate { /// and we won't need to re-launch the app if subsequent EventLoops are run. pub fn internal_exit(&self) { self.set_in_callback(true); - self.handle_nonuser_event(Event::LoopExiting); + self.handle_event(Event::LoopExiting); self.set_in_callback(false); self.set_is_running(false); @@ -290,7 +287,7 @@ impl ApplicationDelegate { // Redraw request might come out of order from the OS. // -> Don't go back into the callback when our callstack originates from there if !self.ivars().in_callback.get() { - self.handle_nonuser_event(Event::WindowEvent { + self.handle_event(Event::WindowEvent { window_id: RootWindowId(window_id), event: WindowEvent::RedrawRequested, }); @@ -313,19 +310,19 @@ impl ApplicationDelegate { unsafe { RunLoop::get() }.wakeup(); } - fn handle_nonuser_event(&self, event: Event) { + fn handle_event(&self, event: Event) { if let Some(ref mut callback) = *self.ivars().callback.borrow_mut() { - callback.handle_nonuser_event(event) + callback.handle_event(event) } } /// dispatch `NewEvents(Init)` + `Resumed` pub fn dispatch_init_events(&self) { self.set_in_callback(true); - self.handle_nonuser_event(Event::NewEvents(StartCause::Init)); + self.handle_event(Event::NewEvents(StartCause::Init)); // NB: For consistency all platforms must emit a 'resumed' event even though macOS // applications don't themselves have a formal suspend/resume lifecycle. - self.handle_nonuser_event(Event::Resumed); + self.handle_event(Event::Resumed); self.set_in_callback(false); } @@ -373,7 +370,7 @@ impl ApplicationDelegate { }; self.set_in_callback(true); - self.handle_nonuser_event(Event::NewEvents(cause)); + self.handle_event(Event::NewEvents(cause)); self.set_in_callback(false); } @@ -396,21 +393,19 @@ impl ApplicationDelegate { } self.set_in_callback(true); - if let Some(ref mut callback) = *self.ivars().callback.borrow_mut() { - callback.handle_user_events(); - } + self.handle_event(Event::UserEvent(HandlePendingUserEvents)); let events = mem::take(&mut *self.ivars().pending_events.borrow_mut()); for event in events { match event { QueuedEvent::WindowEvent(window_id, event) => { - self.handle_nonuser_event(Event::WindowEvent { + self.handle_event(Event::WindowEvent { window_id: RootWindowId(window_id), event, }); } QueuedEvent::DeviceEvent(event) => { - self.handle_nonuser_event(Event::DeviceEvent { + self.handle_event(Event::DeviceEvent { device_id: DEVICE_ID, event, }); @@ -432,7 +427,7 @@ impl ApplicationDelegate { }, }; - callback.handle_nonuser_event(scale_factor_changed_event); + callback.handle_event(scale_factor_changed_event); let physical_size = *new_inner_size.lock().unwrap(); drop(new_inner_size); @@ -444,7 +439,7 @@ impl ApplicationDelegate { window_id: RootWindowId(window.id()), event: WindowEvent::Resized(physical_size), }; - callback.handle_nonuser_event(resized_event); + callback.handle_event(resized_event); } } } @@ -452,13 +447,13 @@ impl ApplicationDelegate { let redraw = mem::take(&mut *self.ivars().pending_redraw.borrow_mut()); for window_id in redraw { - self.handle_nonuser_event(Event::WindowEvent { + self.handle_event(Event::WindowEvent { window_id: RootWindowId(window_id), event: WindowEvent::RedrawRequested, }); } - self.handle_nonuser_event(Event::AboutToWait); + self.handle_event(Event::AboutToWait); self.set_in_callback(false); if self.exiting() { @@ -495,34 +490,18 @@ pub(crate) enum QueuedEvent { }, } -trait EventHandler: fmt::Debug { - // Not sure probably it should accept Event<'static, Never> - fn handle_nonuser_event(&mut self, event: Event); - fn handle_user_events(&mut self); -} - -pub(super) type Callback = RefCell, &RootWindowTarget)>; +#[derive(Debug)] +pub(crate) struct HandlePendingUserEvents; -struct EventLoopHandler { - callback: Weak>, +#[derive(Debug)] +struct EventLoopHandler { + #[allow(clippy::type_complexity)] + callback: Weak, &RootWindowTarget)>>, window_target: Rc, - receiver: Rc>, -} - -impl fmt::Debug for EventLoopHandler { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter - .debug_struct("EventLoopHandler") - .field("window_target", &self.window_target) - .finish_non_exhaustive() - } } -impl EventLoopHandler { - fn with_callback(&mut self, f: F) - where - F: FnOnce(&mut EventLoopHandler, RefMut<'_, dyn FnMut(Event, &RootWindowTarget)>), - { +impl EventLoopHandler { + fn handle_event(&mut self, event: Event) { // `NSApplication` and our app delegate are global state and so it's possible // that we could get a delegate callback after the application has exit an // `EventLoop`. If the loop has been exit then our weak `self.callback` @@ -532,32 +511,12 @@ impl EventLoopHandler { // upgrade the weak reference since it might be valid that the application // re-starts the `NSApplication` after exiting a Winit `EventLoop` if let Some(callback) = self.callback.upgrade() { - let callback = callback.borrow_mut(); - (f)(self, callback); + let mut callback = callback.borrow_mut(); + (callback)(event, &self.window_target); } } } -impl EventHandler for EventLoopHandler { - fn handle_nonuser_event(&mut self, event: Event) { - // `Never` can't be constructed, so the `UserEvent` variant can't - // be present here. - let event = event.map_nonuser_event().unwrap_or_else(|_| unreachable!()); - - self.with_callback(|this, mut callback| { - (callback)(event, &this.window_target); - }); - } - - fn handle_user_events(&mut self) { - self.with_callback(|this, mut callback| { - for event in this.receiver.try_iter() { - (callback)(Event::UserEvent(event), &this.window_target); - } - }); - } -} - /// Returns the minimum `Option`, taking into account that `None` /// equates to an infinite timeout, not a zero timeout (so can't just use /// `Option::min`) diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 816e757154..0af4abe2c7 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -31,7 +31,7 @@ use objc2::{ use super::event::dummy_event; use super::{ app::WinitApplication, - app_delegate::{ApplicationDelegate, Callback}, + app_delegate::{ApplicationDelegate, HandlePendingUserEvents}, monitor::{self, MonitorHandle}, observer::setup_control_flow_observers, }; @@ -152,6 +152,20 @@ impl EventLoopWindowTarget { } } +fn map_user_event( + mut handler: impl FnMut(Event, &RootWindowTarget), + receiver: Rc>, +) -> impl FnMut(Event, &RootWindowTarget) { + move |event, window_target| match event.map_nonuser_event() { + Ok(event) => (handler)(event, window_target), + Err(_) => { + for event in receiver.try_iter() { + (handler)(Event::UserEvent(event), window_target); + } + } + } +} + pub struct EventLoop { /// Store a reference to the application for convenience. /// @@ -177,7 +191,8 @@ pub struct EventLoop { /// Every other reference should be a Weak reference which is only upgraded /// into a strong reference in order to call the callback but then the /// strong reference should be dropped as soon as possible. - _callback: Option>>, + #[allow(clippy::type_complexity)] + _callback: Option, &RootWindowTarget)>>>, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -268,6 +283,8 @@ impl EventLoop { return Err(EventLoopError::AlreadyRunning); } + let callback = map_user_event(callback, self.receiver.clone()); + // # Safety // We are erasing the lifetime of the application callback here so that we // can (temporarily) store it within 'static app delegate that's @@ -276,11 +293,10 @@ impl EventLoop { // The safety of this depends on on making sure to also clear the callback // from the app delegate before we return from here, ensuring that we don't // retain a reference beyond the real lifetime of the callback. - let callback = unsafe { mem::transmute::< - Rc, &RootWindowTarget)>>, - Rc, &RootWindowTarget)>>, + Rc, &RootWindowTarget)>>, + Rc, &RootWindowTarget)>>, >(Rc::new(RefCell::new(callback))) }; @@ -295,11 +311,8 @@ impl EventLoop { // # Safety // We make sure to call `delegate.clear_callback` before returning unsafe { - self.delegate.set_callback( - weak_cb, - Rc::clone(&self.window_target), - Rc::clone(&self.receiver), - ); + self.delegate + .set_callback(weak_cb, Rc::clone(&self.window_target)); } // catch panics to make sure we can't unwind without clearing the set callback @@ -348,6 +361,8 @@ impl EventLoop { where F: FnMut(Event, &RootWindowTarget), { + let callback = map_user_event(callback, self.receiver.clone()); + // # Safety // We are erasing the lifetime of the application callback here so that we // can (temporarily) store it within 'static global app delegate that's @@ -359,8 +374,8 @@ impl EventLoop { let callback = unsafe { mem::transmute::< - Rc, &RootWindowTarget)>>, - Rc, &RootWindowTarget)>>, + Rc, &RootWindowTarget)>>, + Rc, &RootWindowTarget)>>, >(Rc::new(RefCell::new(callback))) }; @@ -377,11 +392,8 @@ impl EventLoop { // to ensure that we don't hold on to the callback beyond its (erased) // lifetime unsafe { - self.delegate.set_callback( - weak_cb, - Rc::clone(&self.window_target), - Rc::clone(&self.receiver), - ); + self.delegate + .set_callback(weak_cb, Rc::clone(&self.window_target)); } // catch panics to make sure we can't unwind without clearing the set callback