diff --git a/examples/child_window.rs b/examples/child_window.rs index 715996eb..68e81308 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -3,50 +3,45 @@ fn main() -> Result<(), impl std::error::Error> { use std::collections::HashMap; + use winit::application::ApplicationHandler; use winit::dpi::{LogicalPosition, LogicalSize, Position}; - use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; + use winit::event::{ElementState, KeyEvent, WindowEvent}; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::raw_window_handle::HasRawWindowHandle; - use winit::window::Window; + use winit::window::{Window, WindowId}; #[path = "util/fill.rs"] mod fill; - fn spawn_child_window(parent: &Window, event_loop: &ActiveEventLoop) -> Window { - let parent = parent.raw_window_handle().unwrap(); - let mut window_attributes = Window::default_attributes() - .with_title("child window") - .with_inner_size(LogicalSize::new(200.0f32, 200.0f32)) - .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) - .with_visible(true); - // `with_parent_window` is unsafe. Parent window must be a valid window. - window_attributes = unsafe { window_attributes.with_parent_window(Some(parent)) }; - - event_loop.create_window(window_attributes).unwrap() + #[derive(Default)] + struct Application { + parent_window_id: Option, + windows: HashMap, } - let mut windows = HashMap::new(); + impl ApplicationHandler for Application { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let attributes = Window::default_attributes() + .with_title("parent window") + .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) + .with_inner_size(LogicalSize::new(640.0f32, 480.0f32)); + let window = event_loop.create_window(attributes).unwrap(); - let event_loop: EventLoop<()> = EventLoop::new().unwrap(); - let mut parent_window_id = None; + println!("Parent window id: {:?})", window.id()); + self.parent_window_id = Some(window.id()); - event_loop.run(move |event: Event<()>, event_loop| { - match event { - Event::Resumed => { - let attributes = Window::default_attributes() - .with_title("parent window") - .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) - .with_inner_size(LogicalSize::new(640.0f32, 480.0f32)); - let window = event_loop.create_window(attributes).unwrap(); + self.windows.insert(window.id(), window); + } - parent_window_id = Some(window.id()); - - println!("Parent window id: {parent_window_id:?})"); - windows.insert(window.id(), window); - }, - Event::WindowEvent { window_id, event } => match event { + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + window_id: winit::window::WindowId, + event: WindowEvent, + ) { + match event { WindowEvent::CloseRequested => { - windows.clear(); + self.windows.clear(); event_loop.exit(); }, WindowEvent::CursorEntered { device_id: _ } => { @@ -61,22 +56,38 @@ fn main() -> Result<(), impl std::error::Error> { event: KeyEvent { state: ElementState::Pressed, .. }, .. } => { - let parent_window = windows.get(&parent_window_id.unwrap()).unwrap(); + let parent_window = self.windows.get(&self.parent_window_id.unwrap()).unwrap(); let child_window = spawn_child_window(parent_window, event_loop); let child_id = child_window.id(); println!("Child window created with id: {child_id:?}"); - windows.insert(child_id, child_window); + self.windows.insert(child_id, child_window); }, WindowEvent::RedrawRequested => { - if let Some(window) = windows.get(&window_id) { + if let Some(window) = self.windows.get(&window_id) { fill::fill_window(window); } }, _ => (), - }, - _ => (), + } } - }) + } + + fn spawn_child_window(parent: &Window, event_loop: &ActiveEventLoop) -> Window { + let parent = parent.raw_window_handle().unwrap(); + let mut window_attributes = Window::default_attributes() + .with_title("child window") + .with_inner_size(LogicalSize::new(200.0f32, 200.0f32)) + .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) + .with_visible(true); + // `with_parent_window` is unsafe. Parent window must be a valid window. + window_attributes = unsafe { window_attributes.with_parent_window(Some(parent)) }; + + event_loop.create_window(window_attributes).unwrap() + } + + let event_loop: EventLoop<()> = EventLoop::new().unwrap(); + let mut app = Application::default(); + event_loop.run_app(&mut app) } #[cfg(all(feature = "rwh_06", not(any(x11_platform, macos_platform, windows_platform))))] diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 2385ab8a..9350bb2f 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -44,6 +44,12 @@ changelog entry. - Reexport `raw-window-handle` versions 0.4 and 0.5 as `raw_window_handle_04` and `raw_window_handle_05`. +### Removed + +- Remove `EventLoop::run`. +- Remove `EventLoopExtRunOnDemand::run_on_demand`. +- Remove `EventLoopExtPumpEvents::pump_events`. + ### Fixed - On macOS, fix panic on exit when dropping windows outside the event loop. diff --git a/src/changelog/v0.30.md b/src/changelog/v0.30.md index e82a162a..2fe59fe5 100644 --- a/src/changelog/v0.30.md +++ b/src/changelog/v0.30.md @@ -65,7 +65,7 @@ `Fn`. The semantics are mostly the same, given that the capture list of the closure is your new `State`. Consider the following code: - ```rust,no_run + ```rust,no_run,ignore use winit::event::Event; use winit::event_loop::EventLoop; use winit::window::Window; diff --git a/src/event_loop.rs b/src/event_loop.rs index 99e72040..9ee4b48c 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -20,7 +20,6 @@ use web_time::{Duration, Instant}; use crate::application::ApplicationHandler; use crate::error::{EventLoopError, OsError}; -use crate::event::Event; use crate::monitor::MonitorHandle; use crate::platform_impl; use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes}; @@ -152,6 +151,7 @@ impl fmt::Debug for ActiveEventLoop { /// Defaults to [`Wait`]. /// /// [`Wait`]: Self::Wait +/// [`Event::AboutToWait`]: crate::event::Event::AboutToWait #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum ControlFlow { /// When the current loop iteration finishes, immediately begin a new iteration regardless of @@ -216,21 +216,6 @@ impl EventLoop { EventLoopBuilder { platform_specific: Default::default(), _p: PhantomData } } - /// See [`run_app`]. - /// - /// [`run_app`]: Self::run_app - #[inline] - #[deprecated = "use `EventLoop::run_app` instead"] - #[cfg(not(all(web_platform, target_feature = "exception-handling")))] - pub fn run(self, event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &ActiveEventLoop), - { - let _span = tracing::debug_span!("winit::EventLoop::run").entered(); - - self.event_loop.run(event_handler) - } - /// Run the application with the event loop on the calling thread. /// /// See the [`set_control_flow()`] docs on how to change the event loop's behavior. @@ -262,7 +247,7 @@ impl EventLoop { #[inline] #[cfg(not(all(web_platform, target_feature = "exception-handling")))] pub fn run_app>(self, app: &mut A) -> Result<(), EventLoopError> { - self.event_loop.run(|event, event_loop| dispatch_event_for_app(app, event_loop, event)) + self.event_loop.run_app(app) } /// Creates an [`EventLoopProxy`] that can be used to dispatch user events @@ -449,7 +434,7 @@ impl ActiveEventLoop { /// This exits the event loop. /// - /// See [`LoopExiting`][Event::LoopExiting]. + /// See [`LoopExiting`][crate::event::Event::LoopExiting]. pub fn exit(&self) { let _span = tracing::debug_span!("winit::ActiveEventLoop::exit",).entered(); @@ -618,23 +603,3 @@ impl AsyncRequestSerial { Self { serial } } } - -/// Shim for various run APIs. -#[inline(always)] -pub(crate) fn dispatch_event_for_app>( - app: &mut A, - event_loop: &ActiveEventLoop, - event: Event, -) { - match event { - Event::NewEvents(cause) => app.new_events(event_loop, cause), - Event::WindowEvent { window_id, event } => app.window_event(event_loop, window_id, event), - Event::DeviceEvent { device_id, event } => app.device_event(event_loop, device_id, event), - Event::UserEvent(event) => app.user_event(event_loop, event), - Event::Suspended => app.suspended(event_loop), - Event::Resumed => app.resumed(event_loop), - Event::AboutToWait => app.about_to_wait(event_loop), - Event::LoopExiting => app.exiting(event_loop), - Event::MemoryWarning => app.memory_warning(event_loop), - } -} diff --git a/src/platform/pump_events.rs b/src/platform/pump_events.rs index 7eedda28..4140e8db 100644 --- a/src/platform/pump_events.rs +++ b/src/platform/pump_events.rs @@ -1,12 +1,13 @@ use std::time::Duration; use crate::application::ApplicationHandler; -use crate::event::Event; -use crate::event_loop::{self, ActiveEventLoop, EventLoop}; +use crate::event_loop::EventLoop; /// Additional methods on [`EventLoop`] for pumping events within an external event loop pub trait EventLoopExtPumpEvents { /// A type provided by the user that can be passed through [`Event::UserEvent`]. + /// + /// [`Event::UserEvent`]: crate::event::Event::UserEvent type UserEvent: 'static; /// Pump the `EventLoop` to check for and dispatch pending events. @@ -107,30 +108,18 @@ pub trait EventLoopExtPumpEvents { &mut self, timeout: Option, app: &mut A, - ) -> PumpStatus { - #[allow(deprecated)] - self.pump_events(timeout, |event, event_loop| { - event_loop::dispatch_event_for_app(app, event_loop, event) - }) - } - - /// See [`pump_app_events`]. - /// - /// [`pump_app_events`]: Self::pump_app_events - #[deprecated = "use EventLoopExtPumpEvents::pump_app_events"] - fn pump_events(&mut self, timeout: Option, event_handler: F) -> PumpStatus - where - F: FnMut(Event, &ActiveEventLoop); + ) -> PumpStatus; } impl EventLoopExtPumpEvents for EventLoop { type UserEvent = T; - fn pump_events(&mut self, timeout: Option, event_handler: F) -> PumpStatus - where - F: FnMut(Event, &ActiveEventLoop), - { - self.event_loop.pump_events(timeout, event_handler) + fn pump_app_events>( + &mut self, + timeout: Option, + app: &mut A, + ) -> PumpStatus { + self.event_loop.pump_app_events(timeout, app) } } diff --git a/src/platform/run_on_demand.rs b/src/platform/run_on_demand.rs index ecb22395..c80d4904 100644 --- a/src/platform/run_on_demand.rs +++ b/src/platform/run_on_demand.rs @@ -1,7 +1,6 @@ use crate::application::ApplicationHandler; use crate::error::EventLoopError; -use crate::event::Event; -use crate::event_loop::{self, ActiveEventLoop, EventLoop}; +use crate::event_loop::{ActiveEventLoop, EventLoop}; #[cfg(doc)] use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window}; @@ -9,15 +8,9 @@ use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window}; /// Additional methods on [`EventLoop`] to return control flow to the caller. pub trait EventLoopExtRunOnDemand { /// A type provided by the user that can be passed through [`Event::UserEvent`]. - type UserEvent: 'static; - - /// See [`run_app_on_demand`]. /// - /// [`run_app_on_demand`]: Self::run_app_on_demand - #[deprecated = "use EventLoopExtRunOnDemand::run_app_on_demand"] - fn run_on_demand(&mut self, event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &ActiveEventLoop); + /// [`Event::UserEvent`]: crate::event::Event::UserEvent + type UserEvent: 'static; /// Run the application with the event loop on the calling thread. /// @@ -68,23 +61,18 @@ pub trait EventLoopExtRunOnDemand { fn run_app_on_demand>( &mut self, app: &mut A, - ) -> Result<(), EventLoopError> { - #[allow(deprecated)] - self.run_on_demand(|event, event_loop| { - event_loop::dispatch_event_for_app(app, event_loop, event) - }) - } + ) -> Result<(), EventLoopError>; } impl EventLoopExtRunOnDemand for EventLoop { type UserEvent = T; - fn run_on_demand(&mut self, event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &ActiveEventLoop), - { + fn run_app_on_demand>( + &mut self, + app: &mut A, + ) -> Result<(), EventLoopError> { self.event_loop.window_target().clear_exit(); - self.event_loop.run_on_demand(event_handler) + self.event_loop.run_app_on_demand(app) } } diff --git a/src/platform/web.rs b/src/platform/web.rs index 25765ae8..9f9c797f 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -55,8 +55,7 @@ use web_sys::HtmlCanvasElement; use crate::application::ApplicationHandler; use crate::cursor::CustomCursorSource; -use crate::event::Event; -use crate::event_loop::{self, ActiveEventLoop, EventLoop}; +use crate::event_loop::{ActiveEventLoop, EventLoop}; #[cfg(web_platform)] use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture; use crate::platform_impl::PlatformCustomCursorSource; @@ -156,7 +155,9 @@ impl WindowAttributesExtWebSys for WindowAttributes { /// Additional methods on `EventLoop` that are specific to the web. pub trait EventLoopExtWebSys { - /// A type provided by the user that can be passed through `Event::UserEvent`. + /// A type provided by the user that can be passed through [`Event::UserEvent`]. + /// + /// [`Event::UserEvent`]: crate::event::Event::UserEvent type UserEvent: 'static; /// Initializes the winit event loop. @@ -182,30 +183,13 @@ pub trait EventLoopExtWebSys { )] /// [^1]: `run_app()` is _not_ available on WASM when the target supports `exception-handling`. fn spawn_app + 'static>(self, app: A); - - /// See [`spawn_app`]. - /// - /// [`spawn_app`]: Self::spawn_app - #[deprecated = "use EventLoopExtWebSys::spawn_app"] - fn spawn(self, event_handler: F) - where - F: 'static + FnMut(Event, &ActiveEventLoop); } impl EventLoopExtWebSys for EventLoop { type UserEvent = T; - fn spawn_app + 'static>(self, mut app: A) { - self.event_loop.spawn(move |event, event_loop| { - event_loop::dispatch_event_for_app(&mut app, event_loop, event) - }); - } - - fn spawn(self, event_handler: F) - where - F: 'static + FnMut(Event, &ActiveEventLoop), - { - self.event_loop.spawn(event_handler) + fn spawn_app + 'static>(self, app: A) { + self.event_loop.spawn_app(app); } } diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 31285b63..499ad67e 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -14,12 +14,13 @@ use android_activity::{ }; use tracing::{debug, trace, warn}; +use crate::application::ApplicationHandler; use crate::cursor::Cursor; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::error; use crate::error::EventLoopError; use crate::event::{self, Force, InnerSizeWriter, StartCause}; -use crate::event_loop::{self, ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents}; +use crate::event_loop::{self, ControlFlow, DeviceEvents}; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::Fullscreen; use crate::window::{ @@ -197,27 +198,28 @@ impl EventLoop { }) } - fn single_iteration(&mut self, main_event: Option>, callback: &mut F) - where - F: FnMut(event::Event, &RootAEL), - { + fn single_iteration>( + &mut self, + main_event: Option>, + app: &mut A, + ) { trace!("Mainloop iteration"); let cause = self.cause; let mut pending_redraw = self.pending_redraw; let mut resized = false; - callback(event::Event::NewEvents(cause), self.window_target()); + app.new_events(self.window_target(), cause); if let Some(event) = main_event { trace!("Handling main event {:?}", event); match event { MainEvent::InitWindow { .. } => { - callback(event::Event::Resumed, self.window_target()); + app.resumed(self.window_target()); }, MainEvent::TerminateWindow { .. } => { - callback(event::Event::Suspended, self.window_target()); + app.suspended(self.window_target()); }, MainEvent::WindowResized { .. } => resized = true, MainEvent::RedrawNeeded { .. } => pending_redraw = true, @@ -226,23 +228,15 @@ impl EventLoop { }, MainEvent::GainedFocus => { HAS_FOCUS.store(true, Ordering::Relaxed); - callback( - event::Event::WindowEvent { - window_id: window::WindowId(WindowId), - event: event::WindowEvent::Focused(true), - }, - self.window_target(), - ); + let window_id = window::WindowId(WindowId); + let event = event::WindowEvent::Focused(true); + app.window_event(self.window_target(), window_id, event); }, MainEvent::LostFocus => { HAS_FOCUS.store(false, Ordering::Relaxed); - callback( - event::Event::WindowEvent { - window_id: window::WindowId(WindowId), - event: event::WindowEvent::Focused(false), - }, - self.window_target(), - ); + let window_id = window::WindowId(WindowId); + let event = event::WindowEvent::Focused(false); + app.window_event(self.window_target(), window_id, event); }, MainEvent::ConfigChanged { .. } => { let monitor = MonitorHandle::new(self.android_app.clone()); @@ -252,20 +246,19 @@ impl EventLoop { let new_inner_size = Arc::new(Mutex::new( MonitorHandle::new(self.android_app.clone()).size(), )); - let event = event::Event::WindowEvent { - window_id: window::WindowId(WindowId), - event: event::WindowEvent::ScaleFactorChanged { - inner_size_writer: InnerSizeWriter::new(Arc::downgrade( - &new_inner_size, - )), - scale_factor, - }, + let window_id = window::WindowId(WindowId); + let event = event::WindowEvent::ScaleFactorChanged { + inner_size_writer: InnerSizeWriter::new(Arc::downgrade( + &new_inner_size, + )), + scale_factor, }; - callback(event, self.window_target()); + + app.window_event(self.window_target(), window_id, event); } }, MainEvent::LowMemory => { - callback(event::Event::MemoryWarning, self.window_target()); + app.memory_warning(self.window_target()); }, MainEvent::Start => { // XXX: how to forward this state to applications? @@ -313,7 +306,7 @@ impl EventLoop { 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, callback)); + input_iter.next(|event| self.handle_input_event(&android_app, event, app)); if !read_event { break; @@ -327,7 +320,7 @@ impl EventLoop { // Empty the user event buffer { while let Ok(event) = self.user_events_receiver.try_recv() { - callback(crate::event::Event::UserEvent(event), self.window_target()); + app.user_event(self.window_target(), event); } } @@ -340,39 +333,32 @@ impl EventLoop { } else { PhysicalSize::new(0, 0) }; - let event = event::Event::WindowEvent { - window_id: window::WindowId(WindowId), - event: event::WindowEvent::Resized(size), - }; - callback(event, self.window_target()); + let window_id = window::WindowId(WindowId); + let event = event::WindowEvent::Resized(size); + app.window_event(self.window_target(), window_id, event); } pending_redraw |= self.redraw_flag.get_and_reset(); if pending_redraw { pending_redraw = false; - let event = event::Event::WindowEvent { - window_id: window::WindowId(WindowId), - event: event::WindowEvent::RedrawRequested, - }; - callback(event, self.window_target()); + let window_id = window::WindowId(WindowId); + let event = event::WindowEvent::RedrawRequested; + app.window_event(self.window_target(), window_id, event); } } // This is always the last event we dispatch before poll again - callback(event::Event::AboutToWait, self.window_target()); + app.about_to_wait(self.window_target()); self.pending_redraw = pending_redraw; } - fn handle_input_event( + fn handle_input_event>( &mut self, android_app: &AndroidApp, event: &InputEvent<'_>, - callback: &mut F, - ) -> InputStatus - where - F: FnMut(event::Event, &RootAEL), - { + app: &mut A, + ) -> InputStatus { let mut input_status = InputStatus::Handled; match event { InputEvent::MotionEvent(motion_event) => { @@ -410,17 +396,16 @@ impl EventLoop { "Input event {device_id:?}, {phase:?}, loc={location:?}, \ pointer={pointer:?}" ); - let event = event::Event::WindowEvent { - window_id, - event: event::WindowEvent::Touch(event::Touch { - device_id, - phase, - location, - id: pointer.pointer_id() as u64, - force: Some(Force::Normalized(pointer.pressure() as f64)), - }), - }; - callback(event, self.window_target()); + + let event = event::WindowEvent::Touch(event::Touch { + device_id, + phase, + location, + id: pointer.pointer_id() as u64, + force: Some(Force::Normalized(pointer.pressure() as f64)), + }); + + app.window_event(self.window_target(), window_id, event); } } }, @@ -448,23 +433,22 @@ impl EventLoop { &mut self.combining_accent, ); - let event = event::Event::WindowEvent { - window_id: window::WindowId(WindowId), - event: event::WindowEvent::KeyboardInput { - device_id: event::DeviceId(DeviceId(key.device_id())), - event: event::KeyEvent { - state, - physical_key: keycodes::to_physical_key(keycode), - logical_key: keycodes::to_logical(key_char, keycode), - location: keycodes::to_location(keycode), - repeat: key.repeat_count() > 0, - text: None, - platform_specific: KeyEventExtra {}, - }, - is_synthetic: false, + let window_id = window::WindowId(WindowId); + let event = event::WindowEvent::KeyboardInput { + device_id: event::DeviceId(DeviceId(key.device_id())), + event: event::KeyEvent { + state, + physical_key: keycodes::to_physical_key(keycode), + logical_key: keycodes::to_logical(key_char, keycode), + location: keycodes::to_location(keycode), + repeat: key.repeat_count() > 0, + text: None, + platform_specific: KeyEventExtra {}, }, + is_synthetic: false, }; - callback(event, self.window_target()); + + app.window_event(self.window_target(), window_id, event); }, } }, @@ -476,19 +460,16 @@ impl EventLoop { input_status } - pub fn run(mut self, event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(event::Event, &event_loop::ActiveEventLoop), - { - self.run_on_demand(event_handler) + pub fn run_app>(mut self, app: &mut A) -> Result<(), EventLoopError> { + self.run_app_on_demand(app) } - pub fn run_on_demand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(event::Event, &event_loop::ActiveEventLoop), - { + pub fn run_app_on_demand>( + &mut self, + app: &mut A, + ) -> Result<(), EventLoopError> { loop { - match self.pump_events(None, &mut event_handler) { + match self.pump_app_events(None, app) { PumpStatus::Exit(0) => { break Ok(()); }, @@ -502,10 +483,11 @@ impl EventLoop { } } - pub fn pump_events(&mut self, timeout: Option, mut callback: F) -> PumpStatus - where - F: FnMut(event::Event, &RootAEL), - { + pub fn pump_app_events>( + &mut self, + timeout: Option, + app: &mut A, + ) -> PumpStatus { if !self.loop_running { self.loop_running = true; @@ -516,18 +498,18 @@ impl EventLoop { self.cause = StartCause::Init; // run the initial loop iteration - self.single_iteration(None, &mut callback); + self.single_iteration(None, app); } // Consider the possibility that the `StartCause::Init` iteration could // request to Exit if !self.exiting() { - self.poll_events_with_timeout(timeout, &mut callback); + self.poll_events_with_timeout(timeout, app); } if self.exiting() { self.loop_running = false; - callback(event::Event::LoopExiting, self.window_target()); + app.exiting(self.window_target()); PumpStatus::Exit(0) } else { @@ -535,10 +517,11 @@ impl EventLoop { } } - fn poll_events_with_timeout(&mut self, mut timeout: Option, mut callback: F) - where - F: FnMut(event::Event, &RootAEL), - { + fn poll_events_with_timeout>( + &mut self, + mut timeout: Option, + app: &mut A, + ) { let start = Instant::now(); self.pending_redraw |= self.redraw_flag.get_and_reset(); @@ -559,8 +542,8 @@ impl EventLoop { min_timeout(control_flow_timeout, timeout) }; - let app = self.android_app.clone(); // Don't borrow self as part of poll expression - app.poll_events(timeout, |poll_event| { + let android_app = self.android_app.clone(); // Don't borrow self as part of poll expression + android_app.poll_events(timeout, |poll_event| { let mut main_event = None; match poll_event { @@ -601,7 +584,7 @@ impl EventLoop { }, }; - self.single_iteration(main_event, &mut callback); + self.single_iteration(main_event, app); }); } diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index 40293d9f..665cb0a6 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -14,6 +14,7 @@ use core_foundation::runloop::{ use objc2::ClassType; use objc2_foundation::{MainThreadMarker, NSString}; +use crate::application::ApplicationHandler; use crate::error::EventLoopError; use crate::event::Event; use crate::event_loop::{ @@ -106,17 +107,28 @@ impl OwnedDisplayHandle { } } -fn map_user_event( - mut handler: impl FnMut(Event, &RootActiveEventLoop), +fn map_user_event>( + app: &mut A, receiver: mpsc::Receiver, -) -> impl FnMut(Event, &RootActiveEventLoop) { - move |event, window_target| match event.map_nonuser_event() { - Ok(event) => (handler)(event, window_target), - Err(_) => { +) -> impl FnMut(Event, &RootActiveEventLoop) + '_ { + move |event, window_target| match event { + Event::NewEvents(cause) => app.new_events(window_target, cause), + Event::WindowEvent { window_id, event } => { + app.window_event(window_target, window_id, event) + }, + Event::DeviceEvent { device_id, event } => { + app.device_event(window_target, device_id, event) + }, + Event::UserEvent(_) => { for event in receiver.try_iter() { - (handler)(Event::UserEvent(event), window_target); + app.user_event(window_target, event); } }, + Event::Suspended => app.suspended(window_target), + Event::Resumed => app.resumed(window_target), + Event::AboutToWait => app.about_to_wait(window_target), + Event::LoopExiting => app.exiting(window_target), + Event::MemoryWarning => app.memory_warning(window_target), } } @@ -159,10 +171,7 @@ impl EventLoop { }) } - pub fn run(self, handler: F) -> ! - where - F: FnMut(Event, &RootActiveEventLoop), - { + pub fn run_app>(self, app: &mut A) -> ! { let application = UIApplication::shared(self.mtm); assert!( application.is_none(), @@ -171,7 +180,7 @@ impl EventLoop { `EventLoop::run_app` calls `UIApplicationMain` on iOS", ); - let handler = map_user_event(handler, self.receiver); + let handler = map_user_event(app, self.receiver); let handler = unsafe { std::mem::transmute::< diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 7f0877f6..8abca557 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -11,6 +11,8 @@ use std::{env, fmt}; #[cfg(x11_platform)] use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex}; +use crate::application::ApplicationHandler; +use crate::platform::pump_events::PumpStatus; #[cfg(x11_platform)] use crate::utils::Lazy; use smol_str::SmolStr; @@ -19,12 +21,9 @@ use smol_str::SmolStr; use self::x11::{X11Error, XConnection, XError, XNotSupported}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError}; -use crate::event_loop::{ - ActiveEventLoop as RootELW, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed, -}; +use crate::event_loop::{AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed}; use crate::icon::Icon; use crate::keyboard::Key; -use crate::platform::pump_events::PumpStatus; #[cfg(x11_platform)] use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook}; use crate::window::{ @@ -789,25 +788,23 @@ impl EventLoop { x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy) } - pub fn run(mut self, callback: F) -> Result<(), EventLoopError> - where - F: FnMut(crate::event::Event, &RootELW), - { - self.run_on_demand(callback) + pub fn run_app>(self, app: &mut A) -> Result<(), EventLoopError> { + x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app)) } - pub fn run_on_demand(&mut self, callback: F) -> Result<(), EventLoopError> - where - F: FnMut(crate::event::Event, &RootELW), - { - x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_on_demand(callback)) + pub fn run_app_on_demand>( + &mut self, + app: &mut A, + ) -> Result<(), EventLoopError> { + x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app_on_demand(app)) } - pub fn pump_events(&mut self, timeout: Option, callback: F) -> PumpStatus - where - F: FnMut(crate::event::Event, &RootELW), - { - x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(timeout, callback)) + pub fn pump_app_events>( + &mut self, + timeout: Option, + app: &mut A, + ) -> PumpStatus { + x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_app_events(timeout, app)) } pub fn window_target(&self) -> &crate::event_loop::ActiveEventLoop { diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index f379841a..687d934e 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -14,6 +14,7 @@ use sctk::reexports::calloop::Error as CalloopError; use sctk::reexports::calloop_wayland_source::WaylandSource; use sctk::reexports::client::{globals, Connection, QueueHandle}; +use crate::application::ApplicationHandler; use crate::cursor::OnlyCursorImage; use crate::dpi::LogicalSize; use crate::error::{EventLoopError, OsError as RootOsError}; @@ -173,12 +174,16 @@ impl EventLoop { Ok(event_loop) } - pub fn run_on_demand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &RootActiveEventLoop), - { + pub fn run_app>(mut self, app: &mut A) -> Result<(), EventLoopError> { + self.run_app_on_demand(app) + } + + pub fn run_app_on_demand>( + &mut self, + app: &mut A, + ) -> Result<(), EventLoopError> { let exit = loop { - match self.pump_events(None, &mut event_handler) { + match self.pump_app_events(None, app) { PumpStatus::Exit(0) => { break Ok(()); }, @@ -200,26 +205,27 @@ impl EventLoop { exit } - pub fn pump_events(&mut self, timeout: Option, mut callback: F) -> PumpStatus - where - F: FnMut(Event, &RootActiveEventLoop), - { + pub fn pump_app_events>( + &mut self, + timeout: Option, + app: &mut A, + ) -> PumpStatus { if !self.loop_running { self.loop_running = true; // Run the initial loop iteration. - self.single_iteration(&mut callback, StartCause::Init); + self.single_iteration(app, StartCause::Init); } // Consider the possibility that the `StartCause::Init` iteration could // request to Exit. if !self.exiting() { - self.poll_events_with_timeout(timeout, &mut callback); + self.poll_events_with_timeout(timeout, app); } if let Some(code) = self.exit_code() { self.loop_running = false; - callback(Event::LoopExiting, self.window_target()); + app.exiting(&self.window_target); PumpStatus::Exit(code) } else { @@ -227,10 +233,11 @@ impl EventLoop { } } - pub fn poll_events_with_timeout(&mut self, mut timeout: Option, mut callback: F) - where - F: FnMut(Event, &RootActiveEventLoop), - { + pub fn poll_events_with_timeout>( + &mut self, + mut timeout: Option, + app: &mut A, + ) { let cause = loop { let start = Instant::now(); @@ -292,13 +299,10 @@ impl EventLoop { break cause; }; - self.single_iteration(&mut callback, cause); + self.single_iteration(app, cause); } - fn single_iteration(&mut self, callback: &mut F, cause: StartCause) - where - F: FnMut(Event, &RootActiveEventLoop), - { + fn single_iteration>(&mut self, app: &mut A, cause: StartCause) { // NOTE currently just indented to simplify the diff // We retain these grow-only scratch buffers as part of the EventLoop @@ -309,18 +313,18 @@ impl EventLoop { let mut buffer_sink = std::mem::take(&mut self.buffer_sink); let mut window_ids = std::mem::take(&mut self.window_ids); - callback(Event::NewEvents(cause), &self.window_target); + app.new_events(&self.window_target, cause); // NB: For consistency all platforms must emit a 'resumed' event even though Wayland // applications don't themselves have a formal suspend/resume lifecycle. if cause == StartCause::Init { - callback(Event::Resumed, &self.window_target); + app.resumed(&self.window_target); } // Handle pending user events. We don't need back buffer, since we can't dispatch // user events indirectly via callback to the user. for user_event in self.pending_user_events.borrow_mut().drain(..) { - callback(Event::UserEvent(user_event), &self.window_target); + app.user_event(&self.window_target, user_event); } // Drain the pending compositor updates. @@ -341,18 +345,13 @@ impl EventLoop { let old_physical_size = physical_size; let new_inner_size = Arc::new(Mutex::new(physical_size)); - callback( - Event::WindowEvent { - window_id: crate::window::WindowId(window_id), - event: WindowEvent::ScaleFactorChanged { - scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade( - &new_inner_size, - )), - }, - }, - &self.window_target, - ); + let root_window_id = crate::window::WindowId(window_id); + let event = WindowEvent::ScaleFactorChanged { + scale_factor, + inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), + }; + + app.window_event(&self.window_target, root_window_id, event); let physical_size = *new_inner_size.lock().unwrap(); drop(new_inner_size); @@ -395,23 +394,14 @@ impl EventLoop { size }); - callback( - Event::WindowEvent { - window_id: crate::window::WindowId(window_id), - event: WindowEvent::Resized(physical_size), - }, - &self.window_target, - ); + let window_id = crate::window::WindowId(window_id); + let event = WindowEvent::Resized(physical_size); + app.window_event(&self.window_target, window_id, event); } if compositor_update.close_window { - callback( - Event::WindowEvent { - window_id: crate::window::WindowId(window_id), - event: WindowEvent::CloseRequested, - }, - &self.window_target, - ); + let window_id = crate::window::WindowId(window_id); + app.window_event(&self.window_target, window_id, WindowEvent::CloseRequested); } } @@ -420,8 +410,15 @@ impl EventLoop { buffer_sink.append(&mut state.window_events_sink.lock().unwrap()); }); for event in buffer_sink.drain() { - let event = event.map_nonuser_event().unwrap(); - callback(event, &self.window_target); + match event { + Event::WindowEvent { window_id, event } => { + app.window_event(&self.window_target, window_id, event) + }, + Event::DeviceEvent { device_id, event } => { + app.device_event(&self.window_target, device_id, event) + }, + _ => unreachable!("event which is neither device nor window event."), + } } // Handle non-synthetic events. @@ -429,8 +426,15 @@ impl EventLoop { buffer_sink.append(&mut state.events_sink); }); for event in buffer_sink.drain() { - let event = event.map_nonuser_event().unwrap(); - callback(event, &self.window_target); + match event { + Event::WindowEvent { window_id, event } => { + app.window_event(&self.window_target, window_id, event) + }, + Event::DeviceEvent { device_id, event } => { + app.device_event(&self.window_target, device_id, event) + }, + _ => unreachable!("event which is neither device nor window event."), + } } // Collect the window ids @@ -466,10 +470,8 @@ impl EventLoop { }); if let Some(event) = event { - callback( - Event::WindowEvent { window_id: crate::window::WindowId(*window_id), event }, - &self.window_target, - ); + let window_id = crate::window::WindowId(*window_id); + app.window_event(&self.window_target, window_id, event); } } @@ -479,7 +481,7 @@ impl EventLoop { }); // This is always the last event we dispatch before poll again - callback(Event::AboutToWait, &self.window_target); + app.about_to_wait(&self.window_target); // Update the window frames and schedule redraws. let mut wake_up = false; diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 6a4708e7..e8f26337 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -27,6 +27,7 @@ use x11rb::protocol::xproto::{self, ConnectionExt as _}; use x11rb::x11_utils::X11Error as LogicalError; use x11rb::xcb_ffi::ReplyOrIdError; +use crate::application::ApplicationHandler; use crate::error::{EventLoopError, OsError as RootOsError}; use crate::event::{Event, StartCause, WindowEvent}; use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed}; @@ -379,12 +380,16 @@ impl EventLoop { &self.event_processor.target } - pub fn run_on_demand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &RootAEL), - { + pub fn run_app>(mut self, app: &mut A) -> Result<(), EventLoopError> { + self.run_app_on_demand(app) + } + + pub fn run_app_on_demand>( + &mut self, + app: &mut A, + ) -> Result<(), EventLoopError> { let exit = loop { - match self.pump_events(None, &mut event_handler) { + match self.pump_app_events(None, app) { PumpStatus::Exit(0) => { break Ok(()); }, @@ -409,26 +414,27 @@ impl EventLoop { exit } - pub fn pump_events(&mut self, timeout: Option, mut callback: F) -> PumpStatus - where - F: FnMut(Event, &RootAEL), - { + pub fn pump_app_events>( + &mut self, + timeout: Option, + app: &mut A, + ) -> PumpStatus { if !self.loop_running { self.loop_running = true; // run the initial loop iteration - self.single_iteration(&mut callback, StartCause::Init); + self.single_iteration(app, StartCause::Init); } // Consider the possibility that the `StartCause::Init` iteration could // request to Exit. if !self.exiting() { - self.poll_events_with_timeout(timeout, &mut callback); + self.poll_events_with_timeout(timeout, app); } if let Some(code) = self.exit_code() { self.loop_running = false; - callback(Event::LoopExiting, self.window_target()); + app.exiting(self.window_target()); PumpStatus::Exit(code) } else { @@ -442,10 +448,11 @@ impl EventLoop { || self.redraw_receiver.has_incoming() } - pub fn poll_events_with_timeout(&mut self, mut timeout: Option, mut callback: F) - where - F: FnMut(Event, &RootAEL), - { + pub fn poll_events_with_timeout>( + &mut self, + mut timeout: Option, + app: &mut A, + ) { let start = Instant::now(); let has_pending = self.has_pending(); @@ -503,23 +510,20 @@ impl EventLoop { return; } - self.single_iteration(&mut callback, cause); + self.single_iteration(app, cause); } - fn single_iteration(&mut self, callback: &mut F, cause: StartCause) - where - F: FnMut(Event, &RootAEL), - { - callback(Event::NewEvents(cause), &self.event_processor.target); + fn single_iteration>(&mut self, app: &mut A, cause: StartCause) { + app.new_events(&self.event_processor.target, cause); // NB: For consistency all platforms must emit a 'resumed' event even though X11 // applications don't themselves have a formal suspend/resume lifecycle. if cause == StartCause::Init { - callback(Event::Resumed, &self.event_processor.target); + app.resumed(&self.event_processor.target) } // Process all pending events - self.drain_events(callback); + self.drain_events(app); // Empty activation tokens. while let Ok((window_id, serial)) = self.activation_receiver.try_recv() { @@ -529,14 +533,12 @@ impl EventLoop { match token { Some(Ok(token)) => { - let event = Event::WindowEvent { - window_id: crate::window::WindowId(window_id), - event: WindowEvent::ActivationTokenDone { - serial, - token: crate::window::ActivationToken::_new(token), - }, + let window_id = crate::window::WindowId(window_id); + let event = WindowEvent::ActivationTokenDone { + serial, + token: crate::window::ActivationToken::_new(token), }; - callback(event, &self.event_processor.target) + app.window_event(&self.event_processor.target, window_id, event); }, Some(Err(e)) => { tracing::error!("Failed to get activation token: {}", e); @@ -548,7 +550,7 @@ impl EventLoop { // Empty the user event buffer { while let Ok(event) = self.user_receiver.try_recv() { - callback(Event::UserEvent(event), &self.event_processor.target); + app.user_event(&self.event_processor.target, event); } } @@ -562,28 +564,24 @@ impl EventLoop { for window_id in windows { let window_id = crate::window::WindowId(window_id); - callback( - Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested }, + app.window_event( &self.event_processor.target, + window_id, + WindowEvent::RedrawRequested, ); } } // This is always the last event we dispatch before poll again - { - callback(Event::AboutToWait, &self.event_processor.target); - } + app.about_to_wait(&self.event_processor.target); } - fn drain_events(&mut self, callback: &mut F) - where - F: FnMut(Event, &RootAEL), - { + fn drain_events>(&mut self, app: &mut A) { let mut xev = MaybeUninit::uninit(); while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } { let mut xev = unsafe { xev.assume_init() }; - self.event_processor.process_event(&mut xev, |window_target, event| { + self.event_processor.process_event(&mut xev, |window_target, event: Event| { if let Event::WindowEvent { window_id: crate::window::WindowId(wid), event: WindowEvent::RedrawRequested, @@ -592,7 +590,15 @@ impl EventLoop { let window_target = EventProcessor::window_target(window_target); window_target.redraw_sender.send(wid).unwrap(); } else { - callback(event, window_target); + match event { + Event::WindowEvent { window_id, event } => { + app.window_event(window_target, window_id, event) + }, + Event::DeviceEvent { device_id, event } => { + app.device_event(window_target, device_id, event) + }, + _ => unreachable!("event which is neither device nor window event."), + } } }); } diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index b5a35809..ccdc9da2 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -25,6 +25,7 @@ use super::app_delegate::{ApplicationDelegate, HandlePendingUserEvents}; use super::event::dummy_event; use super::monitor::{self, MonitorHandle}; use super::observer::setup_control_flow_observers; +use crate::application::ApplicationHandler; use crate::error::EventLoopError; use crate::event::Event; use crate::event_loop::{ @@ -155,17 +156,28 @@ impl ActiveEventLoop { } } -fn map_user_event( - mut handler: impl FnMut(Event, &RootWindowTarget), +fn map_user_event>( + app: &mut A, receiver: Rc>, -) -> impl FnMut(Event, &RootWindowTarget) { - move |event, window_target| match event.map_nonuser_event() { - Ok(event) => (handler)(event, window_target), - Err(_) => { +) -> impl FnMut(Event, &RootWindowTarget) + '_ { + move |event, window_target| match event { + Event::NewEvents(cause) => app.new_events(window_target, cause), + Event::WindowEvent { window_id, event } => { + app.window_event(window_target, window_id, event) + }, + Event::DeviceEvent { device_id, event } => { + app.device_event(window_target, device_id, event) + }, + Event::UserEvent(_) => { for event in receiver.try_iter() { - (handler)(Event::UserEvent(event), window_target); + app.user_event(window_target, event); } }, + Event::Suspended => app.suspended(window_target), + Event::Resumed => app.resumed(window_target), + Event::AboutToWait => app.about_to_wait(window_target), + Event::LoopExiting => app.exiting(window_target), + Event::MemoryWarning => app.memory_warning(window_target), } } @@ -260,22 +272,19 @@ impl EventLoop { &self.window_target } - pub fn run(mut self, handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &RootWindowTarget), - { - self.run_on_demand(handler) + pub fn run_app>(mut self, app: &mut A) -> Result<(), EventLoopError> { + self.run_app_on_demand(app) } // NB: we don't base this on `pump_events` because for `MacOs` we can't support // `pump_events` elegantly (we just ask to run the loop for a "short" amount of // time and so a layered implementation would end up using a lot of CPU due to // redundant wake ups. - pub fn run_on_demand(&mut self, handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &RootWindowTarget), - { - let handler = map_user_event(handler, self.receiver.clone()); + pub fn run_app_on_demand>( + &mut self, + app: &mut A, + ) -> Result<(), EventLoopError> { + let handler = map_user_event(app, self.receiver.clone()); self.delegate.set_event_handler(handler, || { autoreleasepool(|_| { @@ -310,11 +319,12 @@ impl EventLoop { Ok(()) } - pub fn pump_events(&mut self, timeout: Option, handler: F) -> PumpStatus - where - F: FnMut(Event, &RootWindowTarget), - { - let handler = map_user_event(handler, self.receiver.clone()); + pub fn pump_app_events>( + &mut self, + timeout: Option, + app: &mut A, + ) -> PumpStatus { + let handler = map_user_event(app, self.receiver.clone()); self.delegate.set_event_handler(handler, || { autoreleasepool(|_| { diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 59ba9e52..538920e3 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -12,6 +12,7 @@ use orbclient::{ }; use smol_str::SmolStr; +use crate::application::ApplicationHandler; use crate::error::EventLoopError; use crate::event::{self, Ime, Modifiers, StartCause}; use crate::event_loop::{self, ControlFlow, DeviceEvents}; @@ -322,14 +323,13 @@ impl EventLoop { }) } - fn process_event( + fn process_event>( window_id: WindowId, event_option: EventOption, event_state: &mut EventState, - mut event_handler: F, - ) where - F: FnMut(event::Event), - { + window_target: &event_loop::ActiveEventLoop, + app: &mut A, + ) { match event_option { EventOption::Key(KeyEvent { character, scancode, pressed }) => { // Convert scancode @@ -371,125 +371,128 @@ impl EventLoop { key_without_modifiers = logical_key.clone(); } - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::KeyboardInput { - device_id: event::DeviceId(DeviceId), - event: event::KeyEvent { - logical_key, - physical_key, - location: KeyLocation::Standard, - state: element_state(pressed), - repeat: false, - text, - platform_specific: KeyEventExtra { - key_without_modifiers, - text_with_all_modifiers, - }, + let window_id = RootWindowId(window_id); + let event = event::WindowEvent::KeyboardInput { + device_id: event::DeviceId(DeviceId), + event: event::KeyEvent { + logical_key, + physical_key, + location: KeyLocation::Standard, + state: element_state(pressed), + repeat: false, + text, + platform_specific: KeyEventExtra { + key_without_modifiers, + text_with_all_modifiers, }, - is_synthetic: false, }, - }); + is_synthetic: false, + }; + + app.window_event(window_target, window_id, event); // If the state of the modifiers has changed, send the event. if modifiers_before != event_state.keyboard { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::ModifiersChanged(event_state.modifiers()), - }) + app.window_event( + window_target, + window_id, + event::WindowEvent::ModifiersChanged(event_state.modifiers()), + ); } }, EventOption::TextInput(TextInputEvent { character }) => { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::Ime(Ime::Preedit("".into(), None)), - }); - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::Ime(Ime::Commit(character.into())), - }); + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::Ime(Ime::Preedit("".into(), None)), + ); + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::Ime(Ime::Commit(character.into())), + ); }, EventOption::Mouse(MouseEvent { x, y }) => { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::CursorMoved { + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::CursorMoved { device_id: event::DeviceId(DeviceId), position: (x, y).into(), }, - }); + ); }, EventOption::MouseRelative(MouseRelativeEvent { dx, dy }) => { - event_handler(event::Event::DeviceEvent { - device_id: event::DeviceId(DeviceId), - event: event::DeviceEvent::MouseMotion { delta: (dx as f64, dy as f64) }, - }); + app.device_event( + window_target, + event::DeviceId(DeviceId), + event::DeviceEvent::MouseMotion { delta: (dx as f64, dy as f64) }, + ); }, EventOption::Button(ButtonEvent { left, middle, right }) => { while let Some((button, state)) = event_state.mouse(left, middle, right) { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::MouseInput { + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::MouseInput { device_id: event::DeviceId(DeviceId), state, button, }, - }); + ); } }, EventOption::Scroll(ScrollEvent { x, y }) => { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::MouseWheel { + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::MouseWheel { device_id: event::DeviceId(DeviceId), delta: event::MouseScrollDelta::LineDelta(x as f32, y as f32), phase: event::TouchPhase::Moved, }, - }); + ); }, EventOption::Quit(QuitEvent {}) => { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::CloseRequested, - }); + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::CloseRequested, + ); }, EventOption::Focus(FocusEvent { focused }) => { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::Focused(focused), - }); + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::Focused(focused), + ); }, EventOption::Move(MoveEvent { x, y }) => { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::Moved((x, y).into()), - }); + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::Moved((x, y).into()), + ); }, EventOption::Resize(ResizeEvent { width, height }) => { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::Resized((width, height).into()), - }); + app.window_event( + window_target, + RootWindowId(window_id), + event::WindowEvent::Resized((width, height).into()), + ); // Acknowledge resize after event loop. event_state.resize_opt = Some((width, height)); }, // TODO: Screen, Clipboard, Drop EventOption::Hover(HoverEvent { entered }) => { - if entered { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::CursorEntered { - device_id: event::DeviceId(DeviceId), - }, - }); + let event = if entered { + event::WindowEvent::CursorEntered { device_id: event::DeviceId(DeviceId) } } else { - event_handler(event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::CursorLeft { - device_id: event::DeviceId(DeviceId), - }, - }); - } + event::WindowEvent::CursorLeft { device_id: event::DeviceId(DeviceId) } + }; + + app.window_event(window_target, RootWindowId(window_id), event); }, other => { tracing::warn!("unhandled event: {:?}", other); @@ -497,22 +500,13 @@ impl EventLoop { } } - pub fn run(mut self, mut event_handler_inner: F) -> Result<(), EventLoopError> - where - F: FnMut(event::Event, &event_loop::ActiveEventLoop), - { - let mut event_handler = - move |event: event::Event, window_target: &event_loop::ActiveEventLoop| { - event_handler_inner(event, window_target); - }; - + pub fn run_app>(mut self, app: &mut A) -> Result<(), EventLoopError> { let mut start_cause = StartCause::Init; - loop { - event_handler(event::Event::NewEvents(start_cause), &self.window_target); + app.new_events(&self.window_target, start_cause); if start_cause == StartCause::Init { - event_handler(event::Event::Resumed, &self.window_target); + app.resumed(&self.window_target); } // Handle window creates. @@ -528,23 +522,15 @@ impl EventLoop { self.windows.push((window, EventState::default())); - // Send resize event on create to indicate first size. - event_handler( - event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::Resized((properties.w, properties.h).into()), - }, - &self.window_target, - ); + let window_id = RootWindowId(window_id); - // Send resize event on create to indicate first position. - event_handler( - event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::Moved((properties.x, properties.y).into()), - }, - &self.window_target, - ); + // Send resize event on create to indicate first size. + let event = event::WindowEvent::Resized((properties.w, properties.h).into()); + app.window_event(&self.window_target, window_id, event); + + // Send moved event on create to indicate first position. + let event = event::WindowEvent::Moved((properties.x, properties.y).into()); + app.window_event(&self.window_target, window_id, event); } // Handle window destroys. @@ -552,14 +538,8 @@ impl EventLoop { let mut destroys = self.window_target.p.destroys.lock().unwrap(); destroys.pop_front() } { - event_handler( - event::Event::WindowEvent { - window_id: RootWindowId(destroy_id), - event: event::WindowEvent::Destroyed, - }, - &self.window_target, - ); - + let window_id = RootWindowId(destroy_id); + app.window_event(&self.window_target, window_id, event::WindowEvent::Destroyed); self.windows.retain(|(window, _event_state)| window.fd as u64 != destroy_id.fd); } @@ -586,7 +566,8 @@ impl EventLoop { window_id, orbital_event.to_option(), event_state, - |event| event_handler(event, &self.window_target), + &self.window_target, + app, ); } @@ -614,7 +595,7 @@ impl EventLoop { } while let Ok(event) = self.user_events_receiver.try_recv() { - event_handler(event::Event::UserEvent(event), &self.window_target); + app.user_event(&self.window_target, event); } // To avoid deadlocks the redraws lock is not held during event processing. @@ -622,16 +603,14 @@ impl EventLoop { let mut redraws = self.window_target.p.redraws.lock().unwrap(); redraws.pop_front() } { - event_handler( - event::Event::WindowEvent { - window_id: RootWindowId(window_id), - event: event::WindowEvent::RedrawRequested, - }, + app.window_event( &self.window_target, + RootWindowId(window_id), + event::WindowEvent::RedrawRequested, ); } - event_handler(event::Event::AboutToWait, &self.window_target); + app.about_to_wait(&self.window_target); if self.window_target.p.exiting() { break; @@ -695,7 +674,7 @@ impl EventLoop { } } - event_handler(event::Event::LoopExiting, &self.window_target); + app.exiting(&self.window_target); Ok(()) } diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index 263a5fd9..54214a99 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; use std::sync::mpsc::{self, Receiver, Sender}; +use crate::application::ApplicationHandler; use crate::error::EventLoopError; use crate::event::Event; use crate::event_loop::ActiveEventLoop as RootActiveEventLoop; @@ -31,25 +32,13 @@ impl EventLoop { Ok(EventLoop { elw, user_event_sender, user_event_receiver }) } - pub fn run(self, mut event_handler: F) -> ! - where - F: FnMut(Event, &RootActiveEventLoop), - { + pub fn run_app>(self, app: &mut A) -> ! { let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData }; // SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`. - let handler: Box)> = Box::new(|event| { - let event = match event.map_nonuser_event() { - Ok(event) => event, - Err(Event::UserEvent(())) => Event::UserEvent( - self.user_event_receiver - .try_recv() - .expect("handler woken up without user event"), - ), - Err(_) => unreachable!(), - }; - event_handler(event, &target) - }); + let handler: Box)> = + Box::new(|event| handle_event(app, &target, &self.user_event_receiver, event)); + // SAFETY: The `transmute` is necessary because `run()` requires `'static`. This is safe // because this function will never return and all resources not cleaned up by the point we // `throw` will leak, making this actually `'static`. @@ -65,24 +54,12 @@ impl EventLoop { unreachable!(); } - pub fn spawn(self, mut event_handler: F) - where - F: 'static + FnMut(Event, &RootActiveEventLoop), - { + pub fn spawn_app + 'static>(self, mut app: A) { let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData }; self.elw.p.run( Box::new(move |event| { - let event = match event.map_nonuser_event() { - Ok(event) => event, - Err(Event::UserEvent(())) => Event::UserEvent( - self.user_event_receiver - .try_recv() - .expect("handler woken up without user event"), - ), - Err(_) => unreachable!(), - }; - event_handler(event, &target) + handle_event(&mut app, &target, &self.user_event_receiver, event) }), true, ); @@ -96,3 +73,26 @@ impl EventLoop { &self.elw } } + +fn handle_event>( + app: &mut A, + target: &RootActiveEventLoop, + user_event_receiver: &Receiver, + event: Event<()>, +) { + match event { + Event::NewEvents(cause) => app.new_events(target, cause), + Event::WindowEvent { window_id, event } => app.window_event(target, window_id, event), + Event::DeviceEvent { device_id, event } => app.device_event(target, device_id, event), + Event::UserEvent(_) => { + let event = + user_event_receiver.try_recv().expect("user event signaled but not received"); + app.user_event(target, event); + }, + Event::Suspended => app.suspended(target), + Event::Resumed => app.resumed(target), + Event::AboutToWait => app.about_to_wait(target), + Event::LoopExiting => app.exiting(target), + Event::MemoryWarning => app.memory_warning(target), + } +} diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 4fc31553..4bc6499c 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -57,6 +57,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE, }; +use crate::application::ApplicationHandler; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::error::EventLoopError; use crate::event::{ @@ -215,17 +216,14 @@ impl EventLoop { &self.window_target } - pub fn run(mut self, event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &RootAEL), - { - self.run_on_demand(event_handler) + pub fn run_app>(mut self, app: &mut A) -> Result<(), EventLoopError> { + self.run_app_on_demand(app) } - pub fn run_on_demand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> - where - F: FnMut(Event, &RootAEL), - { + pub fn run_app_on_demand>( + &mut self, + app: &mut A, + ) -> Result<(), EventLoopError> { { let runner = &self.window_target.p.runner_shared; @@ -236,21 +234,32 @@ impl EventLoop { // returning unsafe { runner.set_event_handler(move |event| { - // the shared `EventLoopRunner` is not parameterized - // `EventLoopProxy::send_event()` calls `PostMessage` - // to wakeup and dispatch a placeholder `UserEvent`, - // when we received the placeholder event here, the - // real UserEvent(T) should already be put in the - // mpsc channel and ready to be pulled - let event = match event.map_nonuser_event() { - Ok(non_user_event) => non_user_event, - Err(_user_event_placeholder) => Event::UserEvent( - user_event_receiver + match event { + Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause), + Event::WindowEvent { window_id, event } => { + app.window_event(event_loop_windows_ref, window_id, event) + }, + Event::DeviceEvent { device_id, event } => { + app.device_event(event_loop_windows_ref, device_id, event) + }, + // The shared `EventLoopRunner` is not parameterized + // `EventLoopProxy::send_event()` calls `PostMessage` + // to wakeup and dispatch a placeholder `UserEvent`, + // when we received the placeholder event here, the + // real UserEvent(T) should already be put in the + // mpsc channel and ready to be pulled + Event::UserEvent(_) => { + let event = user_event_receiver .try_recv() - .expect("user event signaled but not received"), - ), - }; - event_handler(event, event_loop_windows_ref) + .expect("user event signaled but not received"); + app.user_event(event_loop_windows_ref, event); + }, + Event::Suspended => app.suspended(event_loop_windows_ref), + Event::Resumed => app.resumed(event_loop_windows_ref), + Event::AboutToWait => app.about_to_wait(event_loop_windows_ref), + Event::LoopExiting => app.exiting(event_loop_windows_ref), + Event::MemoryWarning => app.memory_warning(event_loop_windows_ref), + } }); } } @@ -284,10 +293,11 @@ impl EventLoop { } } - pub fn pump_events(&mut self, timeout: Option, mut event_handler: F) -> PumpStatus - where - F: FnMut(Event, &RootAEL), - { + pub fn pump_app_events>( + &mut self, + timeout: Option, + app: &mut A, + ) -> PumpStatus { { let runner = &self.window_target.p.runner_shared; let event_loop_windows_ref = &self.window_target; @@ -302,16 +312,34 @@ impl EventLoop { // event handler. unsafe { runner.set_event_handler(move |event| { - let event = match event.map_nonuser_event() { - Ok(non_user_event) => non_user_event, - Err(_user_event_placeholder) => Event::UserEvent( - user_event_receiver - .recv() - .expect("user event signaled but not received"), - ), - }; - event_handler(event, event_loop_windows_ref) + match event { + Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause), + Event::WindowEvent { window_id, event } => { + app.window_event(event_loop_windows_ref, window_id, event) + }, + Event::DeviceEvent { device_id, event } => { + app.device_event(event_loop_windows_ref, device_id, event) + }, + // The shared `EventLoopRunner` is not parameterized + // `EventLoopProxy::send_event()` calls `PostMessage` + // to wakeup and dispatch a placeholder `UserEvent`, + // when we received the placeholder event here, the + // real UserEvent(T) should already be put in the + // mpsc channel and ready to be pulled + Event::UserEvent(_) => { + let event = user_event_receiver + .try_recv() + .expect("user event signaled but not received"); + app.user_event(event_loop_windows_ref, event); + }, + Event::Suspended => app.suspended(event_loop_windows_ref), + Event::Resumed => app.resumed(event_loop_windows_ref), + Event::AboutToWait => app.about_to_wait(event_loop_windows_ref), + Event::LoopExiting => app.exiting(event_loop_windows_ref), + Event::MemoryWarning => app.memory_warning(event_loop_windows_ref), + } }); + runner.wakeup(); } }