event_loop: remove deprecated run APIs

The APIs are not well suited for the `&dyn ApplicationHandler` model and
`Box<dyn EventLoop>` structure, thus remove them.
This commit is contained in:
Kirill Chibisov 2024-05-20 20:27:36 +04:00 committed by GitHub
parent 2b1c8cea1b
commit 3e8fa41073
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 544 additions and 587 deletions

View file

@ -3,50 +3,45 @@
fn main() -> Result<(), impl std::error::Error> { fn main() -> Result<(), impl std::error::Error> {
use std::collections::HashMap; use std::collections::HashMap;
use winit::application::ApplicationHandler;
use winit::dpi::{LogicalPosition, LogicalSize, Position}; 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::event_loop::{ActiveEventLoop, EventLoop};
use winit::raw_window_handle::HasRawWindowHandle; use winit::raw_window_handle::HasRawWindowHandle;
use winit::window::Window; use winit::window::{Window, WindowId};
#[path = "util/fill.rs"] #[path = "util/fill.rs"]
mod fill; mod fill;
fn spawn_child_window(parent: &Window, event_loop: &ActiveEventLoop) -> Window { #[derive(Default)]
let parent = parent.raw_window_handle().unwrap(); struct Application {
let mut window_attributes = Window::default_attributes() parent_window_id: Option<WindowId>,
.with_title("child window") windows: HashMap<WindowId, 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 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(); println!("Parent window id: {:?})", window.id());
let mut parent_window_id = None; self.parent_window_id = Some(window.id());
event_loop.run(move |event: Event<()>, event_loop| { self.windows.insert(window.id(), window);
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();
parent_window_id = Some(window.id()); fn window_event(
&mut self,
println!("Parent window id: {parent_window_id:?})"); event_loop: &ActiveEventLoop,
windows.insert(window.id(), window); window_id: winit::window::WindowId,
}, event: WindowEvent,
Event::WindowEvent { window_id, event } => match event { ) {
match event {
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
windows.clear(); self.windows.clear();
event_loop.exit(); event_loop.exit();
}, },
WindowEvent::CursorEntered { device_id: _ } => { WindowEvent::CursorEntered { device_id: _ } => {
@ -61,22 +56,38 @@ fn main() -> Result<(), impl std::error::Error> {
event: KeyEvent { state: ElementState::Pressed, .. }, 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_window = spawn_child_window(parent_window, event_loop);
let child_id = child_window.id(); let child_id = child_window.id();
println!("Child window created with id: {child_id:?}"); println!("Child window created with id: {child_id:?}");
windows.insert(child_id, child_window); self.windows.insert(child_id, child_window);
}, },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
if let Some(window) = windows.get(&window_id) { if let Some(window) = self.windows.get(&window_id) {
fill::fill_window(window); 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))))] #[cfg(all(feature = "rwh_06", not(any(x11_platform, macos_platform, windows_platform))))]

View file

@ -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`. - 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 ### Fixed
- On macOS, fix panic on exit when dropping windows outside the event loop. - On macOS, fix panic on exit when dropping windows outside the event loop.

View file

@ -65,7 +65,7 @@
`Fn`. The semantics are mostly the same, given that the capture list of the `Fn`. The semantics are mostly the same, given that the capture list of the
closure is your new `State`. Consider the following code: closure is your new `State`. Consider the following code:
```rust,no_run ```rust,no_run,ignore
use winit::event::Event; use winit::event::Event;
use winit::event_loop::EventLoop; use winit::event_loop::EventLoop;
use winit::window::Window; use winit::window::Window;

View file

@ -20,7 +20,6 @@ use web_time::{Duration, Instant};
use crate::application::ApplicationHandler; use crate::application::ApplicationHandler;
use crate::error::{EventLoopError, OsError}; use crate::error::{EventLoopError, OsError};
use crate::event::Event;
use crate::monitor::MonitorHandle; use crate::monitor::MonitorHandle;
use crate::platform_impl; use crate::platform_impl;
use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes}; use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
@ -152,6 +151,7 @@ impl fmt::Debug for ActiveEventLoop {
/// Defaults to [`Wait`]. /// Defaults to [`Wait`].
/// ///
/// [`Wait`]: Self::Wait /// [`Wait`]: Self::Wait
/// [`Event::AboutToWait`]: crate::event::Event::AboutToWait
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum ControlFlow { pub enum ControlFlow {
/// When the current loop iteration finishes, immediately begin a new iteration regardless of /// When the current loop iteration finishes, immediately begin a new iteration regardless of
@ -216,21 +216,6 @@ impl<T> EventLoop<T> {
EventLoopBuilder { platform_specific: Default::default(), _p: PhantomData } 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<F>(self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &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. /// 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. /// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
@ -262,7 +247,7 @@ impl<T> EventLoop<T> {
#[inline] #[inline]
#[cfg(not(all(web_platform, target_feature = "exception-handling")))] #[cfg(not(all(web_platform, target_feature = "exception-handling")))]
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> { pub fn run_app<A: ApplicationHandler<T>>(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 /// Creates an [`EventLoopProxy`] that can be used to dispatch user events
@ -449,7 +434,7 @@ impl ActiveEventLoop {
/// This exits the event loop. /// This exits the event loop.
/// ///
/// See [`LoopExiting`][Event::LoopExiting]. /// See [`LoopExiting`][crate::event::Event::LoopExiting].
pub fn exit(&self) { pub fn exit(&self) {
let _span = tracing::debug_span!("winit::ActiveEventLoop::exit",).entered(); let _span = tracing::debug_span!("winit::ActiveEventLoop::exit",).entered();
@ -618,23 +603,3 @@ impl AsyncRequestSerial {
Self { serial } Self { serial }
} }
} }
/// Shim for various run APIs.
#[inline(always)]
pub(crate) fn dispatch_event_for_app<T: 'static, A: ApplicationHandler<T>>(
app: &mut A,
event_loop: &ActiveEventLoop,
event: Event<T>,
) {
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),
}
}

View file

@ -1,12 +1,13 @@
use std::time::Duration; use std::time::Duration;
use crate::application::ApplicationHandler; use crate::application::ApplicationHandler;
use crate::event::Event; use crate::event_loop::EventLoop;
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
/// Additional methods on [`EventLoop`] for pumping events within an external event loop /// Additional methods on [`EventLoop`] for pumping events within an external event loop
pub trait EventLoopExtPumpEvents { pub trait EventLoopExtPumpEvents {
/// 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; type UserEvent: 'static;
/// Pump the `EventLoop` to check for and dispatch pending events. /// Pump the `EventLoop` to check for and dispatch pending events.
@ -107,30 +108,18 @@ pub trait EventLoopExtPumpEvents {
&mut self, &mut self,
timeout: Option<Duration>, timeout: Option<Duration>,
app: &mut A, app: &mut A,
) -> PumpStatus { ) -> 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<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
where
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
} }
impl<T> EventLoopExtPumpEvents for EventLoop<T> { impl<T> EventLoopExtPumpEvents for EventLoop<T> {
type UserEvent = T; type UserEvent = T;
fn pump_events<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>(
where &mut self,
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop), timeout: Option<Duration>,
{ app: &mut A,
self.event_loop.pump_events(timeout, event_handler) ) -> PumpStatus {
self.event_loop.pump_app_events(timeout, app)
} }
} }

View file

@ -1,7 +1,6 @@
use crate::application::ApplicationHandler; use crate::application::ApplicationHandler;
use crate::error::EventLoopError; use crate::error::EventLoopError;
use crate::event::Event; use crate::event_loop::{ActiveEventLoop, EventLoop};
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
#[cfg(doc)] #[cfg(doc)]
use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window}; 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. /// Additional methods on [`EventLoop`] to return control flow to the caller.
pub trait EventLoopExtRunOnDemand { pub trait EventLoopExtRunOnDemand {
/// 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`].
type UserEvent: 'static;
/// See [`run_app_on_demand`].
/// ///
/// [`run_app_on_demand`]: Self::run_app_on_demand /// [`Event::UserEvent`]: crate::event::Event::UserEvent
#[deprecated = "use EventLoopExtRunOnDemand::run_app_on_demand"] type UserEvent: 'static;
fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
/// Run the application with the event loop on the calling thread. /// Run the application with the event loop on the calling thread.
/// ///
@ -68,23 +61,18 @@ pub trait EventLoopExtRunOnDemand {
fn run_app_on_demand<A: ApplicationHandler<Self::UserEvent>>( fn run_app_on_demand<A: ApplicationHandler<Self::UserEvent>>(
&mut self, &mut self,
app: &mut A, app: &mut A,
) -> Result<(), EventLoopError> { ) -> Result<(), EventLoopError>;
#[allow(deprecated)]
self.run_on_demand(|event, event_loop| {
event_loop::dispatch_event_for_app(app, event_loop, event)
})
}
} }
impl<T> EventLoopExtRunOnDemand for EventLoop<T> { impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
type UserEvent = T; type UserEvent = T;
fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError> fn run_app_on_demand<A: ApplicationHandler<Self::UserEvent>>(
where &mut self,
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop), app: &mut A,
{ ) -> Result<(), EventLoopError> {
self.event_loop.window_target().clear_exit(); self.event_loop.window_target().clear_exit();
self.event_loop.run_on_demand(event_handler) self.event_loop.run_app_on_demand(app)
} }
} }

View file

@ -55,8 +55,7 @@ use web_sys::HtmlCanvasElement;
use crate::application::ApplicationHandler; use crate::application::ApplicationHandler;
use crate::cursor::CustomCursorSource; use crate::cursor::CustomCursorSource;
use crate::event::Event; use crate::event_loop::{ActiveEventLoop, EventLoop};
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
#[cfg(web_platform)] #[cfg(web_platform)]
use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture; use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture;
use crate::platform_impl::PlatformCustomCursorSource; use crate::platform_impl::PlatformCustomCursorSource;
@ -156,7 +155,9 @@ impl WindowAttributesExtWebSys for WindowAttributes {
/// Additional methods on `EventLoop` that are specific to the web. /// Additional methods on `EventLoop` that are specific to the web.
pub trait EventLoopExtWebSys { 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; type UserEvent: 'static;
/// Initializes the winit event loop. /// 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`. /// [^1]: `run_app()` is _not_ available on WASM when the target supports `exception-handling`.
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, app: A); fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, app: A);
/// See [`spawn_app`].
///
/// [`spawn_app`]: Self::spawn_app
#[deprecated = "use EventLoopExtWebSys::spawn_app"]
fn spawn<F>(self, event_handler: F)
where
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
} }
impl<T> EventLoopExtWebSys for EventLoop<T> { impl<T> EventLoopExtWebSys for EventLoop<T> {
type UserEvent = T; type UserEvent = T;
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, mut app: A) { fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, app: A) {
self.event_loop.spawn(move |event, event_loop| { self.event_loop.spawn_app(app);
event_loop::dispatch_event_for_app(&mut app, event_loop, event)
});
}
fn spawn<F>(self, event_handler: F)
where
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop),
{
self.event_loop.spawn(event_handler)
} }
} }

View file

@ -14,12 +14,13 @@ use android_activity::{
}; };
use tracing::{debug, trace, warn}; use tracing::{debug, trace, warn};
use crate::application::ApplicationHandler;
use crate::cursor::Cursor; use crate::cursor::Cursor;
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
use crate::error; use crate::error;
use crate::error::EventLoopError; use crate::error::EventLoopError;
use crate::event::{self, Force, InnerSizeWriter, StartCause}; 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::pump_events::PumpStatus;
use crate::platform_impl::Fullscreen; use crate::platform_impl::Fullscreen;
use crate::window::{ use crate::window::{
@ -197,27 +198,28 @@ impl<T: 'static> EventLoop<T> {
}) })
} }
fn single_iteration<F>(&mut self, main_event: Option<MainEvent<'_>>, callback: &mut F) fn single_iteration<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(event::Event<T>, &RootAEL), main_event: Option<MainEvent<'_>>,
{ app: &mut A,
) {
trace!("Mainloop iteration"); trace!("Mainloop iteration");
let cause = self.cause; let cause = self.cause;
let mut pending_redraw = self.pending_redraw; let mut pending_redraw = self.pending_redraw;
let mut resized = false; 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 { if let Some(event) = main_event {
trace!("Handling main event {:?}", event); trace!("Handling main event {:?}", event);
match event { match event {
MainEvent::InitWindow { .. } => { MainEvent::InitWindow { .. } => {
callback(event::Event::Resumed, self.window_target()); app.resumed(self.window_target());
}, },
MainEvent::TerminateWindow { .. } => { MainEvent::TerminateWindow { .. } => {
callback(event::Event::Suspended, self.window_target()); app.suspended(self.window_target());
}, },
MainEvent::WindowResized { .. } => resized = true, MainEvent::WindowResized { .. } => resized = true,
MainEvent::RedrawNeeded { .. } => pending_redraw = true, MainEvent::RedrawNeeded { .. } => pending_redraw = true,
@ -226,23 +228,15 @@ impl<T: 'static> EventLoop<T> {
}, },
MainEvent::GainedFocus => { MainEvent::GainedFocus => {
HAS_FOCUS.store(true, Ordering::Relaxed); HAS_FOCUS.store(true, Ordering::Relaxed);
callback( let window_id = window::WindowId(WindowId);
event::Event::WindowEvent { let event = event::WindowEvent::Focused(true);
window_id: window::WindowId(WindowId), app.window_event(self.window_target(), window_id, event);
event: event::WindowEvent::Focused(true),
},
self.window_target(),
);
}, },
MainEvent::LostFocus => { MainEvent::LostFocus => {
HAS_FOCUS.store(false, Ordering::Relaxed); HAS_FOCUS.store(false, Ordering::Relaxed);
callback( let window_id = window::WindowId(WindowId);
event::Event::WindowEvent { let event = event::WindowEvent::Focused(false);
window_id: window::WindowId(WindowId), app.window_event(self.window_target(), window_id, event);
event: event::WindowEvent::Focused(false),
},
self.window_target(),
);
}, },
MainEvent::ConfigChanged { .. } => { MainEvent::ConfigChanged { .. } => {
let monitor = MonitorHandle::new(self.android_app.clone()); let monitor = MonitorHandle::new(self.android_app.clone());
@ -252,20 +246,19 @@ impl<T: 'static> EventLoop<T> {
let new_inner_size = Arc::new(Mutex::new( let new_inner_size = Arc::new(Mutex::new(
MonitorHandle::new(self.android_app.clone()).size(), MonitorHandle::new(self.android_app.clone()).size(),
)); ));
let event = event::Event::WindowEvent { let window_id = window::WindowId(WindowId);
window_id: window::WindowId(WindowId), let event = event::WindowEvent::ScaleFactorChanged {
event: event::WindowEvent::ScaleFactorChanged { inner_size_writer: InnerSizeWriter::new(Arc::downgrade(
inner_size_writer: InnerSizeWriter::new(Arc::downgrade( &new_inner_size,
&new_inner_size, )),
)), scale_factor,
scale_factor,
},
}; };
callback(event, self.window_target());
app.window_event(self.window_target(), window_id, event);
} }
}, },
MainEvent::LowMemory => { MainEvent::LowMemory => {
callback(event::Event::MemoryWarning, self.window_target()); app.memory_warning(self.window_target());
}, },
MainEvent::Start => { MainEvent::Start => {
// XXX: how to forward this state to applications? // XXX: how to forward this state to applications?
@ -313,7 +306,7 @@ impl<T: 'static> EventLoop<T> {
match android_app.input_events_iter() { match android_app.input_events_iter() {
Ok(mut input_iter) => loop { Ok(mut input_iter) => loop {
let read_event = 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 { if !read_event {
break; break;
@ -327,7 +320,7 @@ impl<T: 'static> EventLoop<T> {
// Empty the user event buffer // Empty the user event buffer
{ {
while let Ok(event) = self.user_events_receiver.try_recv() { 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<T: 'static> EventLoop<T> {
} else { } else {
PhysicalSize::new(0, 0) PhysicalSize::new(0, 0)
}; };
let event = event::Event::WindowEvent { let window_id = window::WindowId(WindowId);
window_id: window::WindowId(WindowId), let event = event::WindowEvent::Resized(size);
event: event::WindowEvent::Resized(size), app.window_event(self.window_target(), window_id, event);
};
callback(event, self.window_target());
} }
pending_redraw |= self.redraw_flag.get_and_reset(); pending_redraw |= self.redraw_flag.get_and_reset();
if pending_redraw { if pending_redraw {
pending_redraw = false; pending_redraw = false;
let event = event::Event::WindowEvent { let window_id = window::WindowId(WindowId);
window_id: window::WindowId(WindowId), let event = event::WindowEvent::RedrawRequested;
event: event::WindowEvent::RedrawRequested, app.window_event(self.window_target(), window_id, event);
};
callback(event, self.window_target());
} }
} }
// This is always the last event we dispatch before poll again // 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; self.pending_redraw = pending_redraw;
} }
fn handle_input_event<F>( fn handle_input_event<A: ApplicationHandler<T>>(
&mut self, &mut self,
android_app: &AndroidApp, android_app: &AndroidApp,
event: &InputEvent<'_>, event: &InputEvent<'_>,
callback: &mut F, app: &mut A,
) -> InputStatus ) -> InputStatus {
where
F: FnMut(event::Event<T>, &RootAEL),
{
let mut input_status = InputStatus::Handled; let mut input_status = InputStatus::Handled;
match event { match event {
InputEvent::MotionEvent(motion_event) => { InputEvent::MotionEvent(motion_event) => {
@ -410,17 +396,16 @@ impl<T: 'static> EventLoop<T> {
"Input event {device_id:?}, {phase:?}, loc={location:?}, \ "Input event {device_id:?}, {phase:?}, loc={location:?}, \
pointer={pointer:?}" pointer={pointer:?}"
); );
let event = event::Event::WindowEvent {
window_id, let event = event::WindowEvent::Touch(event::Touch {
event: event::WindowEvent::Touch(event::Touch { device_id,
device_id, phase,
phase, location,
location, id: pointer.pointer_id() as u64,
id: pointer.pointer_id() as u64, force: Some(Force::Normalized(pointer.pressure() as f64)),
force: Some(Force::Normalized(pointer.pressure() as f64)), });
}),
}; app.window_event(self.window_target(), window_id, event);
callback(event, self.window_target());
} }
} }
}, },
@ -448,23 +433,22 @@ impl<T: 'static> EventLoop<T> {
&mut self.combining_accent, &mut self.combining_accent,
); );
let event = event::Event::WindowEvent { let window_id = window::WindowId(WindowId);
window_id: window::WindowId(WindowId), let event = event::WindowEvent::KeyboardInput {
event: event::WindowEvent::KeyboardInput { device_id: event::DeviceId(DeviceId(key.device_id())),
device_id: event::DeviceId(DeviceId(key.device_id())), event: event::KeyEvent {
event: event::KeyEvent { state,
state, physical_key: keycodes::to_physical_key(keycode),
physical_key: keycodes::to_physical_key(keycode), logical_key: keycodes::to_logical(key_char, keycode),
logical_key: keycodes::to_logical(key_char, keycode), location: keycodes::to_location(keycode),
location: keycodes::to_location(keycode), repeat: key.repeat_count() > 0,
repeat: key.repeat_count() > 0, text: None,
text: None, platform_specific: KeyEventExtra {},
platform_specific: KeyEventExtra {},
},
is_synthetic: false,
}, },
is_synthetic: false,
}; };
callback(event, self.window_target());
app.window_event(self.window_target(), window_id, event);
}, },
} }
}, },
@ -476,19 +460,16 @@ impl<T: 'static> EventLoop<T> {
input_status input_status
} }
pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError> pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
where self.run_app_on_demand(app)
F: FnMut(event::Event<T>, &event_loop::ActiveEventLoop),
{
self.run_on_demand(event_handler)
} }
pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError> pub fn run_app_on_demand<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(event::Event<T>, &event_loop::ActiveEventLoop), app: &mut A,
{ ) -> Result<(), EventLoopError> {
loop { loop {
match self.pump_events(None, &mut event_handler) { match self.pump_app_events(None, app) {
PumpStatus::Exit(0) => { PumpStatus::Exit(0) => {
break Ok(()); break Ok(());
}, },
@ -502,10 +483,11 @@ impl<T: 'static> EventLoop<T> {
} }
} }
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus pub fn pump_app_events<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(event::Event<T>, &RootAEL), timeout: Option<Duration>,
{ app: &mut A,
) -> PumpStatus {
if !self.loop_running { if !self.loop_running {
self.loop_running = true; self.loop_running = true;
@ -516,18 +498,18 @@ impl<T: 'static> EventLoop<T> {
self.cause = StartCause::Init; self.cause = StartCause::Init;
// run the initial loop iteration // 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 // Consider the possibility that the `StartCause::Init` iteration could
// request to Exit // request to Exit
if !self.exiting() { if !self.exiting() {
self.poll_events_with_timeout(timeout, &mut callback); self.poll_events_with_timeout(timeout, app);
} }
if self.exiting() { if self.exiting() {
self.loop_running = false; self.loop_running = false;
callback(event::Event::LoopExiting, self.window_target()); app.exiting(self.window_target());
PumpStatus::Exit(0) PumpStatus::Exit(0)
} else { } else {
@ -535,10 +517,11 @@ impl<T: 'static> EventLoop<T> {
} }
} }
fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F) fn poll_events_with_timeout<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(event::Event<T>, &RootAEL), mut timeout: Option<Duration>,
{ app: &mut A,
) {
let start = Instant::now(); let start = Instant::now();
self.pending_redraw |= self.redraw_flag.get_and_reset(); self.pending_redraw |= self.redraw_flag.get_and_reset();
@ -559,8 +542,8 @@ impl<T: 'static> EventLoop<T> {
min_timeout(control_flow_timeout, timeout) min_timeout(control_flow_timeout, timeout)
}; };
let app = self.android_app.clone(); // Don't borrow self as part of poll expression let android_app = self.android_app.clone(); // Don't borrow self as part of poll expression
app.poll_events(timeout, |poll_event| { android_app.poll_events(timeout, |poll_event| {
let mut main_event = None; let mut main_event = None;
match poll_event { match poll_event {
@ -601,7 +584,7 @@ impl<T: 'static> EventLoop<T> {
}, },
}; };
self.single_iteration(main_event, &mut callback); self.single_iteration(main_event, app);
}); });
} }

View file

@ -14,6 +14,7 @@ use core_foundation::runloop::{
use objc2::ClassType; use objc2::ClassType;
use objc2_foundation::{MainThreadMarker, NSString}; use objc2_foundation::{MainThreadMarker, NSString};
use crate::application::ApplicationHandler;
use crate::error::EventLoopError; use crate::error::EventLoopError;
use crate::event::Event; use crate::event::Event;
use crate::event_loop::{ use crate::event_loop::{
@ -106,17 +107,28 @@ impl OwnedDisplayHandle {
} }
} }
fn map_user_event<T: 'static>( fn map_user_event<T: 'static, A: ApplicationHandler<T>>(
mut handler: impl FnMut(Event<T>, &RootActiveEventLoop), app: &mut A,
receiver: mpsc::Receiver<T>, receiver: mpsc::Receiver<T>,
) -> impl FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop) { ) -> impl FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop) + '_ {
move |event, window_target| match event.map_nonuser_event() { move |event, window_target| match event {
Ok(event) => (handler)(event, window_target), Event::NewEvents(cause) => app.new_events(window_target, cause),
Err(_) => { 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() { 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<T: 'static> EventLoop<T> {
}) })
} }
pub fn run<F>(self, handler: F) -> ! pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> ! {
where
F: FnMut(Event<T>, &RootActiveEventLoop),
{
let application = UIApplication::shared(self.mtm); let application = UIApplication::shared(self.mtm);
assert!( assert!(
application.is_none(), application.is_none(),
@ -171,7 +180,7 @@ impl<T: 'static> EventLoop<T> {
`EventLoop::run_app` calls `UIApplicationMain` on iOS", `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 { let handler = unsafe {
std::mem::transmute::< std::mem::transmute::<

View file

@ -11,6 +11,8 @@ use std::{env, fmt};
#[cfg(x11_platform)] #[cfg(x11_platform)]
use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex}; use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex};
use crate::application::ApplicationHandler;
use crate::platform::pump_events::PumpStatus;
#[cfg(x11_platform)] #[cfg(x11_platform)]
use crate::utils::Lazy; use crate::utils::Lazy;
use smol_str::SmolStr; use smol_str::SmolStr;
@ -19,12 +21,9 @@ use smol_str::SmolStr;
use self::x11::{X11Error, XConnection, XError, XNotSupported}; use self::x11::{X11Error, XConnection, XError, XNotSupported};
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError}; use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError};
use crate::event_loop::{ use crate::event_loop::{AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed};
ActiveEventLoop as RootELW, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
};
use crate::icon::Icon; use crate::icon::Icon;
use crate::keyboard::Key; use crate::keyboard::Key;
use crate::platform::pump_events::PumpStatus;
#[cfg(x11_platform)] #[cfg(x11_platform)]
use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook}; use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook};
use crate::window::{ use crate::window::{
@ -789,25 +788,23 @@ impl<T: 'static> EventLoop<T> {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy) x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
} }
pub fn run<F>(mut self, callback: F) -> Result<(), EventLoopError> pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> {
where x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app))
F: FnMut(crate::event::Event<T>, &RootELW),
{
self.run_on_demand(callback)
} }
pub fn run_on_demand<F>(&mut self, callback: F) -> Result<(), EventLoopError> pub fn run_app_on_demand<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(crate::event::Event<T>, &RootELW), app: &mut A,
{ ) -> Result<(), EventLoopError> {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_on_demand(callback)) x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app_on_demand(app))
} }
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, callback: F) -> PumpStatus pub fn pump_app_events<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(crate::event::Event<T>, &RootELW), timeout: Option<Duration>,
{ app: &mut A,
x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(timeout, callback)) ) -> PumpStatus {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_app_events(timeout, app))
} }
pub fn window_target(&self) -> &crate::event_loop::ActiveEventLoop { pub fn window_target(&self) -> &crate::event_loop::ActiveEventLoop {

View file

@ -14,6 +14,7 @@ use sctk::reexports::calloop::Error as CalloopError;
use sctk::reexports::calloop_wayland_source::WaylandSource; use sctk::reexports::calloop_wayland_source::WaylandSource;
use sctk::reexports::client::{globals, Connection, QueueHandle}; use sctk::reexports::client::{globals, Connection, QueueHandle};
use crate::application::ApplicationHandler;
use crate::cursor::OnlyCursorImage; use crate::cursor::OnlyCursorImage;
use crate::dpi::LogicalSize; use crate::dpi::LogicalSize;
use crate::error::{EventLoopError, OsError as RootOsError}; use crate::error::{EventLoopError, OsError as RootOsError};
@ -173,12 +174,16 @@ impl<T: 'static> EventLoop<T> {
Ok(event_loop) Ok(event_loop)
} }
pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError> pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
where self.run_app_on_demand(app)
F: FnMut(Event<T>, &RootActiveEventLoop), }
{
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
&mut self,
app: &mut A,
) -> Result<(), EventLoopError> {
let exit = loop { let exit = loop {
match self.pump_events(None, &mut event_handler) { match self.pump_app_events(None, app) {
PumpStatus::Exit(0) => { PumpStatus::Exit(0) => {
break Ok(()); break Ok(());
}, },
@ -200,26 +205,27 @@ impl<T: 'static> EventLoop<T> {
exit exit
} }
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus pub fn pump_app_events<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootActiveEventLoop), timeout: Option<Duration>,
{ app: &mut A,
) -> PumpStatus {
if !self.loop_running { if !self.loop_running {
self.loop_running = true; self.loop_running = true;
// Run the initial loop iteration. // 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 // Consider the possibility that the `StartCause::Init` iteration could
// request to Exit. // request to Exit.
if !self.exiting() { 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() { if let Some(code) = self.exit_code() {
self.loop_running = false; self.loop_running = false;
callback(Event::LoopExiting, self.window_target()); app.exiting(&self.window_target);
PumpStatus::Exit(code) PumpStatus::Exit(code)
} else { } else {
@ -227,10 +233,11 @@ impl<T: 'static> EventLoop<T> {
} }
} }
pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F) pub fn poll_events_with_timeout<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootActiveEventLoop), mut timeout: Option<Duration>,
{ app: &mut A,
) {
let cause = loop { let cause = loop {
let start = Instant::now(); let start = Instant::now();
@ -292,13 +299,10 @@ impl<T: 'static> EventLoop<T> {
break cause; break cause;
}; };
self.single_iteration(&mut callback, cause); self.single_iteration(app, cause);
} }
fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause) fn single_iteration<A: ApplicationHandler<T>>(&mut self, app: &mut A, cause: StartCause) {
where
F: FnMut(Event<T>, &RootActiveEventLoop),
{
// NOTE currently just indented to simplify the diff // NOTE currently just indented to simplify the diff
// We retain these grow-only scratch buffers as part of the EventLoop // We retain these grow-only scratch buffers as part of the EventLoop
@ -309,18 +313,18 @@ impl<T: 'static> EventLoop<T> {
let mut buffer_sink = std::mem::take(&mut self.buffer_sink); let mut buffer_sink = std::mem::take(&mut self.buffer_sink);
let mut window_ids = std::mem::take(&mut self.window_ids); 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 // NB: For consistency all platforms must emit a 'resumed' event even though Wayland
// applications don't themselves have a formal suspend/resume lifecycle. // applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init { 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 // Handle pending user events. We don't need back buffer, since we can't dispatch
// user events indirectly via callback to the user. // user events indirectly via callback to the user.
for user_event in self.pending_user_events.borrow_mut().drain(..) { 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. // Drain the pending compositor updates.
@ -341,18 +345,13 @@ impl<T: 'static> EventLoop<T> {
let old_physical_size = physical_size; let old_physical_size = physical_size;
let new_inner_size = Arc::new(Mutex::new(physical_size)); let new_inner_size = Arc::new(Mutex::new(physical_size));
callback( let root_window_id = crate::window::WindowId(window_id);
Event::WindowEvent { let event = WindowEvent::ScaleFactorChanged {
window_id: crate::window::WindowId(window_id), scale_factor,
event: WindowEvent::ScaleFactorChanged { inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)),
scale_factor, };
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(
&new_inner_size, app.window_event(&self.window_target, root_window_id, event);
)),
},
},
&self.window_target,
);
let physical_size = *new_inner_size.lock().unwrap(); let physical_size = *new_inner_size.lock().unwrap();
drop(new_inner_size); drop(new_inner_size);
@ -395,23 +394,14 @@ impl<T: 'static> EventLoop<T> {
size size
}); });
callback( let window_id = crate::window::WindowId(window_id);
Event::WindowEvent { let event = WindowEvent::Resized(physical_size);
window_id: crate::window::WindowId(window_id), app.window_event(&self.window_target, window_id, event);
event: WindowEvent::Resized(physical_size),
},
&self.window_target,
);
} }
if compositor_update.close_window { if compositor_update.close_window {
callback( let window_id = crate::window::WindowId(window_id);
Event::WindowEvent { app.window_event(&self.window_target, window_id, WindowEvent::CloseRequested);
window_id: crate::window::WindowId(window_id),
event: WindowEvent::CloseRequested,
},
&self.window_target,
);
} }
} }
@ -420,8 +410,15 @@ impl<T: 'static> EventLoop<T> {
buffer_sink.append(&mut state.window_events_sink.lock().unwrap()); buffer_sink.append(&mut state.window_events_sink.lock().unwrap());
}); });
for event in buffer_sink.drain() { for event in buffer_sink.drain() {
let event = event.map_nonuser_event().unwrap(); match event {
callback(event, &self.window_target); 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. // Handle non-synthetic events.
@ -429,8 +426,15 @@ impl<T: 'static> EventLoop<T> {
buffer_sink.append(&mut state.events_sink); buffer_sink.append(&mut state.events_sink);
}); });
for event in buffer_sink.drain() { for event in buffer_sink.drain() {
let event = event.map_nonuser_event().unwrap(); match event {
callback(event, &self.window_target); 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 // Collect the window ids
@ -466,10 +470,8 @@ impl<T: 'static> EventLoop<T> {
}); });
if let Some(event) = event { if let Some(event) = event {
callback( let window_id = crate::window::WindowId(*window_id);
Event::WindowEvent { window_id: crate::window::WindowId(*window_id), event }, app.window_event(&self.window_target, window_id, event);
&self.window_target,
);
} }
} }
@ -479,7 +481,7 @@ impl<T: 'static> EventLoop<T> {
}); });
// This is always the last event we dispatch before poll again // 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. // Update the window frames and schedule redraws.
let mut wake_up = false; let mut wake_up = false;

View file

@ -27,6 +27,7 @@ use x11rb::protocol::xproto::{self, ConnectionExt as _};
use x11rb::x11_utils::X11Error as LogicalError; use x11rb::x11_utils::X11Error as LogicalError;
use x11rb::xcb_ffi::ReplyOrIdError; use x11rb::xcb_ffi::ReplyOrIdError;
use crate::application::ApplicationHandler;
use crate::error::{EventLoopError, OsError as RootOsError}; use crate::error::{EventLoopError, OsError as RootOsError};
use crate::event::{Event, StartCause, WindowEvent}; use crate::event::{Event, StartCause, WindowEvent};
use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed}; use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed};
@ -379,12 +380,16 @@ impl<T: 'static> EventLoop<T> {
&self.event_processor.target &self.event_processor.target
} }
pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError> pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
where self.run_app_on_demand(app)
F: FnMut(Event<T>, &RootAEL), }
{
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
&mut self,
app: &mut A,
) -> Result<(), EventLoopError> {
let exit = loop { let exit = loop {
match self.pump_events(None, &mut event_handler) { match self.pump_app_events(None, app) {
PumpStatus::Exit(0) => { PumpStatus::Exit(0) => {
break Ok(()); break Ok(());
}, },
@ -409,26 +414,27 @@ impl<T: 'static> EventLoop<T> {
exit exit
} }
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus pub fn pump_app_events<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootAEL), timeout: Option<Duration>,
{ app: &mut A,
) -> PumpStatus {
if !self.loop_running { if !self.loop_running {
self.loop_running = true; self.loop_running = true;
// run the initial loop iteration // 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 // Consider the possibility that the `StartCause::Init` iteration could
// request to Exit. // request to Exit.
if !self.exiting() { 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() { if let Some(code) = self.exit_code() {
self.loop_running = false; self.loop_running = false;
callback(Event::LoopExiting, self.window_target()); app.exiting(self.window_target());
PumpStatus::Exit(code) PumpStatus::Exit(code)
} else { } else {
@ -442,10 +448,11 @@ impl<T: 'static> EventLoop<T> {
|| self.redraw_receiver.has_incoming() || self.redraw_receiver.has_incoming()
} }
pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F) pub fn poll_events_with_timeout<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootAEL), mut timeout: Option<Duration>,
{ app: &mut A,
) {
let start = Instant::now(); let start = Instant::now();
let has_pending = self.has_pending(); let has_pending = self.has_pending();
@ -503,23 +510,20 @@ impl<T: 'static> EventLoop<T> {
return; return;
} }
self.single_iteration(&mut callback, cause); self.single_iteration(app, cause);
} }
fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause) fn single_iteration<A: ApplicationHandler<T>>(&mut self, app: &mut A, cause: StartCause) {
where app.new_events(&self.event_processor.target, cause);
F: FnMut(Event<T>, &RootAEL),
{
callback(Event::NewEvents(cause), &self.event_processor.target);
// NB: For consistency all platforms must emit a 'resumed' event even though X11 // NB: For consistency all platforms must emit a 'resumed' event even though X11
// applications don't themselves have a formal suspend/resume lifecycle. // applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init { if cause == StartCause::Init {
callback(Event::Resumed, &self.event_processor.target); app.resumed(&self.event_processor.target)
} }
// Process all pending events // Process all pending events
self.drain_events(callback); self.drain_events(app);
// Empty activation tokens. // Empty activation tokens.
while let Ok((window_id, serial)) = self.activation_receiver.try_recv() { while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
@ -529,14 +533,12 @@ impl<T: 'static> EventLoop<T> {
match token { match token {
Some(Ok(token)) => { Some(Ok(token)) => {
let event = Event::WindowEvent { let window_id = crate::window::WindowId(window_id);
window_id: crate::window::WindowId(window_id), let event = WindowEvent::ActivationTokenDone {
event: WindowEvent::ActivationTokenDone { serial,
serial, token: crate::window::ActivationToken::_new(token),
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)) => { Some(Err(e)) => {
tracing::error!("Failed to get activation token: {}", e); tracing::error!("Failed to get activation token: {}", e);
@ -548,7 +550,7 @@ impl<T: 'static> EventLoop<T> {
// Empty the user event buffer // Empty the user event buffer
{ {
while let Ok(event) = self.user_receiver.try_recv() { 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<T: 'static> EventLoop<T> {
for window_id in windows { for window_id in windows {
let window_id = crate::window::WindowId(window_id); let window_id = crate::window::WindowId(window_id);
callback( app.window_event(
Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested },
&self.event_processor.target, &self.event_processor.target,
window_id,
WindowEvent::RedrawRequested,
); );
} }
} }
// This is always the last event we dispatch before poll again // This is always the last event we dispatch before poll again
{ app.about_to_wait(&self.event_processor.target);
callback(Event::AboutToWait, &self.event_processor.target);
}
} }
fn drain_events<F>(&mut self, callback: &mut F) fn drain_events<A: ApplicationHandler<T>>(&mut self, app: &mut A) {
where
F: FnMut(Event<T>, &RootAEL),
{
let mut xev = MaybeUninit::uninit(); let mut xev = MaybeUninit::uninit();
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } { while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
let mut xev = unsafe { xev.assume_init() }; 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<T>| {
if let Event::WindowEvent { if let Event::WindowEvent {
window_id: crate::window::WindowId(wid), window_id: crate::window::WindowId(wid),
event: WindowEvent::RedrawRequested, event: WindowEvent::RedrawRequested,
@ -592,7 +590,15 @@ impl<T: 'static> EventLoop<T> {
let window_target = EventProcessor::window_target(window_target); let window_target = EventProcessor::window_target(window_target);
window_target.redraw_sender.send(wid).unwrap(); window_target.redraw_sender.send(wid).unwrap();
} else { } 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."),
}
} }
}); });
} }

View file

@ -25,6 +25,7 @@ use super::app_delegate::{ApplicationDelegate, HandlePendingUserEvents};
use super::event::dummy_event; use super::event::dummy_event;
use super::monitor::{self, MonitorHandle}; use super::monitor::{self, MonitorHandle};
use super::observer::setup_control_flow_observers; use super::observer::setup_control_flow_observers;
use crate::application::ApplicationHandler;
use crate::error::EventLoopError; use crate::error::EventLoopError;
use crate::event::Event; use crate::event::Event;
use crate::event_loop::{ use crate::event_loop::{
@ -155,17 +156,28 @@ impl ActiveEventLoop {
} }
} }
fn map_user_event<T: 'static>( fn map_user_event<T: 'static, A: ApplicationHandler<T>>(
mut handler: impl FnMut(Event<T>, &RootWindowTarget), app: &mut A,
receiver: Rc<mpsc::Receiver<T>>, receiver: Rc<mpsc::Receiver<T>>,
) -> impl FnMut(Event<HandlePendingUserEvents>, &RootWindowTarget) { ) -> impl FnMut(Event<HandlePendingUserEvents>, &RootWindowTarget) + '_ {
move |event, window_target| match event.map_nonuser_event() { move |event, window_target| match event {
Ok(event) => (handler)(event, window_target), Event::NewEvents(cause) => app.new_events(window_target, cause),
Err(_) => { 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() { 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<T> EventLoop<T> {
&self.window_target &self.window_target
} }
pub fn run<F>(mut self, handler: F) -> Result<(), EventLoopError> pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
where self.run_app_on_demand(app)
F: FnMut(Event<T>, &RootWindowTarget),
{
self.run_on_demand(handler)
} }
// NB: we don't base this on `pump_events` because for `MacOs` we can't support // 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 // `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 // time and so a layered implementation would end up using a lot of CPU due to
// redundant wake ups. // redundant wake ups.
pub fn run_on_demand<F>(&mut self, handler: F) -> Result<(), EventLoopError> pub fn run_app_on_demand<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootWindowTarget), app: &mut A,
{ ) -> Result<(), EventLoopError> {
let handler = map_user_event(handler, self.receiver.clone()); let handler = map_user_event(app, self.receiver.clone());
self.delegate.set_event_handler(handler, || { self.delegate.set_event_handler(handler, || {
autoreleasepool(|_| { autoreleasepool(|_| {
@ -310,11 +319,12 @@ impl<T> EventLoop<T> {
Ok(()) Ok(())
} }
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, handler: F) -> PumpStatus pub fn pump_app_events<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootWindowTarget), timeout: Option<Duration>,
{ app: &mut A,
let handler = map_user_event(handler, self.receiver.clone()); ) -> PumpStatus {
let handler = map_user_event(app, self.receiver.clone());
self.delegate.set_event_handler(handler, || { self.delegate.set_event_handler(handler, || {
autoreleasepool(|_| { autoreleasepool(|_| {

View file

@ -12,6 +12,7 @@ use orbclient::{
}; };
use smol_str::SmolStr; use smol_str::SmolStr;
use crate::application::ApplicationHandler;
use crate::error::EventLoopError; use crate::error::EventLoopError;
use crate::event::{self, Ime, Modifiers, StartCause}; use crate::event::{self, Ime, Modifiers, StartCause};
use crate::event_loop::{self, ControlFlow, DeviceEvents}; use crate::event_loop::{self, ControlFlow, DeviceEvents};
@ -322,14 +323,13 @@ impl<T: 'static> EventLoop<T> {
}) })
} }
fn process_event<F>( fn process_event<A: ApplicationHandler<T>>(
window_id: WindowId, window_id: WindowId,
event_option: EventOption, event_option: EventOption,
event_state: &mut EventState, event_state: &mut EventState,
mut event_handler: F, window_target: &event_loop::ActiveEventLoop,
) where app: &mut A,
F: FnMut(event::Event<T>), ) {
{
match event_option { match event_option {
EventOption::Key(KeyEvent { character, scancode, pressed }) => { EventOption::Key(KeyEvent { character, scancode, pressed }) => {
// Convert scancode // Convert scancode
@ -371,125 +371,128 @@ impl<T: 'static> EventLoop<T> {
key_without_modifiers = logical_key.clone(); key_without_modifiers = logical_key.clone();
} }
event_handler(event::Event::WindowEvent { let window_id = RootWindowId(window_id);
window_id: RootWindowId(window_id), let event = event::WindowEvent::KeyboardInput {
event: event::WindowEvent::KeyboardInput { device_id: event::DeviceId(DeviceId),
device_id: event::DeviceId(DeviceId), event: event::KeyEvent {
event: event::KeyEvent { logical_key,
logical_key, physical_key,
physical_key, location: KeyLocation::Standard,
location: KeyLocation::Standard, state: element_state(pressed),
state: element_state(pressed), repeat: false,
repeat: false, text,
text, platform_specific: KeyEventExtra {
platform_specific: KeyEventExtra { key_without_modifiers,
key_without_modifiers, text_with_all_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 the state of the modifiers has changed, send the event.
if modifiers_before != event_state.keyboard { if modifiers_before != event_state.keyboard {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::ModifiersChanged(event_state.modifiers()), window_id,
}) event::WindowEvent::ModifiersChanged(event_state.modifiers()),
);
} }
}, },
EventOption::TextInput(TextInputEvent { character }) => { EventOption::TextInput(TextInputEvent { character }) => {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::Ime(Ime::Preedit("".into(), None)), RootWindowId(window_id),
}); event::WindowEvent::Ime(Ime::Preedit("".into(), None)),
event_handler(event::Event::WindowEvent { );
window_id: RootWindowId(window_id), app.window_event(
event: event::WindowEvent::Ime(Ime::Commit(character.into())), window_target,
}); RootWindowId(window_id),
event::WindowEvent::Ime(Ime::Commit(character.into())),
);
}, },
EventOption::Mouse(MouseEvent { x, y }) => { EventOption::Mouse(MouseEvent { x, y }) => {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::CursorMoved { RootWindowId(window_id),
event::WindowEvent::CursorMoved {
device_id: event::DeviceId(DeviceId), device_id: event::DeviceId(DeviceId),
position: (x, y).into(), position: (x, y).into(),
}, },
}); );
}, },
EventOption::MouseRelative(MouseRelativeEvent { dx, dy }) => { EventOption::MouseRelative(MouseRelativeEvent { dx, dy }) => {
event_handler(event::Event::DeviceEvent { app.device_event(
device_id: event::DeviceId(DeviceId), window_target,
event: event::DeviceEvent::MouseMotion { delta: (dx as f64, dy as f64) }, event::DeviceId(DeviceId),
}); event::DeviceEvent::MouseMotion { delta: (dx as f64, dy as f64) },
);
}, },
EventOption::Button(ButtonEvent { left, middle, right }) => { EventOption::Button(ButtonEvent { left, middle, right }) => {
while let Some((button, state)) = event_state.mouse(left, middle, right) { while let Some((button, state)) = event_state.mouse(left, middle, right) {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::MouseInput { RootWindowId(window_id),
event::WindowEvent::MouseInput {
device_id: event::DeviceId(DeviceId), device_id: event::DeviceId(DeviceId),
state, state,
button, button,
}, },
}); );
} }
}, },
EventOption::Scroll(ScrollEvent { x, y }) => { EventOption::Scroll(ScrollEvent { x, y }) => {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::MouseWheel { RootWindowId(window_id),
event::WindowEvent::MouseWheel {
device_id: event::DeviceId(DeviceId), device_id: event::DeviceId(DeviceId),
delta: event::MouseScrollDelta::LineDelta(x as f32, y as f32), delta: event::MouseScrollDelta::LineDelta(x as f32, y as f32),
phase: event::TouchPhase::Moved, phase: event::TouchPhase::Moved,
}, },
}); );
}, },
EventOption::Quit(QuitEvent {}) => { EventOption::Quit(QuitEvent {}) => {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::CloseRequested, RootWindowId(window_id),
}); event::WindowEvent::CloseRequested,
);
}, },
EventOption::Focus(FocusEvent { focused }) => { EventOption::Focus(FocusEvent { focused }) => {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::Focused(focused), RootWindowId(window_id),
}); event::WindowEvent::Focused(focused),
);
}, },
EventOption::Move(MoveEvent { x, y }) => { EventOption::Move(MoveEvent { x, y }) => {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::Moved((x, y).into()), RootWindowId(window_id),
}); event::WindowEvent::Moved((x, y).into()),
);
}, },
EventOption::Resize(ResizeEvent { width, height }) => { EventOption::Resize(ResizeEvent { width, height }) => {
event_handler(event::Event::WindowEvent { app.window_event(
window_id: RootWindowId(window_id), window_target,
event: event::WindowEvent::Resized((width, height).into()), RootWindowId(window_id),
}); event::WindowEvent::Resized((width, height).into()),
);
// Acknowledge resize after event loop. // Acknowledge resize after event loop.
event_state.resize_opt = Some((width, height)); event_state.resize_opt = Some((width, height));
}, },
// TODO: Screen, Clipboard, Drop // TODO: Screen, Clipboard, Drop
EventOption::Hover(HoverEvent { entered }) => { EventOption::Hover(HoverEvent { entered }) => {
if entered { let event = if entered {
event_handler(event::Event::WindowEvent { event::WindowEvent::CursorEntered { device_id: event::DeviceId(DeviceId) }
window_id: RootWindowId(window_id),
event: event::WindowEvent::CursorEntered {
device_id: event::DeviceId(DeviceId),
},
});
} else { } else {
event_handler(event::Event::WindowEvent { event::WindowEvent::CursorLeft { device_id: event::DeviceId(DeviceId) }
window_id: RootWindowId(window_id), };
event: event::WindowEvent::CursorLeft {
device_id: event::DeviceId(DeviceId), app.window_event(window_target, RootWindowId(window_id), event);
},
});
}
}, },
other => { other => {
tracing::warn!("unhandled event: {:?}", other); tracing::warn!("unhandled event: {:?}", other);
@ -497,22 +500,13 @@ impl<T: 'static> EventLoop<T> {
} }
} }
pub fn run<F>(mut self, mut event_handler_inner: F) -> Result<(), EventLoopError> pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
where
F: FnMut(event::Event<T>, &event_loop::ActiveEventLoop),
{
let mut event_handler =
move |event: event::Event<T>, window_target: &event_loop::ActiveEventLoop| {
event_handler_inner(event, window_target);
};
let mut start_cause = StartCause::Init; let mut start_cause = StartCause::Init;
loop { loop {
event_handler(event::Event::NewEvents(start_cause), &self.window_target); app.new_events(&self.window_target, start_cause);
if start_cause == StartCause::Init { if start_cause == StartCause::Init {
event_handler(event::Event::Resumed, &self.window_target); app.resumed(&self.window_target);
} }
// Handle window creates. // Handle window creates.
@ -528,23 +522,15 @@ impl<T: 'static> EventLoop<T> {
self.windows.push((window, EventState::default())); self.windows.push((window, EventState::default()));
// Send resize event on create to indicate first size. let window_id = RootWindowId(window_id);
event_handler(
event::Event::WindowEvent {
window_id: RootWindowId(window_id),
event: event::WindowEvent::Resized((properties.w, properties.h).into()),
},
&self.window_target,
);
// Send resize event on create to indicate first position. // Send resize event on create to indicate first size.
event_handler( let event = event::WindowEvent::Resized((properties.w, properties.h).into());
event::Event::WindowEvent { app.window_event(&self.window_target, window_id, event);
window_id: RootWindowId(window_id),
event: event::WindowEvent::Moved((properties.x, properties.y).into()), // Send moved event on create to indicate first position.
}, let event = event::WindowEvent::Moved((properties.x, properties.y).into());
&self.window_target, app.window_event(&self.window_target, window_id, event);
);
} }
// Handle window destroys. // Handle window destroys.
@ -552,14 +538,8 @@ impl<T: 'static> EventLoop<T> {
let mut destroys = self.window_target.p.destroys.lock().unwrap(); let mut destroys = self.window_target.p.destroys.lock().unwrap();
destroys.pop_front() destroys.pop_front()
} { } {
event_handler( let window_id = RootWindowId(destroy_id);
event::Event::WindowEvent { app.window_event(&self.window_target, window_id, event::WindowEvent::Destroyed);
window_id: RootWindowId(destroy_id),
event: event::WindowEvent::Destroyed,
},
&self.window_target,
);
self.windows.retain(|(window, _event_state)| window.fd as u64 != destroy_id.fd); self.windows.retain(|(window, _event_state)| window.fd as u64 != destroy_id.fd);
} }
@ -586,7 +566,8 @@ impl<T: 'static> EventLoop<T> {
window_id, window_id,
orbital_event.to_option(), orbital_event.to_option(),
event_state, event_state,
|event| event_handler(event, &self.window_target), &self.window_target,
app,
); );
} }
@ -614,7 +595,7 @@ impl<T: 'static> EventLoop<T> {
} }
while let Ok(event) = self.user_events_receiver.try_recv() { 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. // To avoid deadlocks the redraws lock is not held during event processing.
@ -622,16 +603,14 @@ impl<T: 'static> EventLoop<T> {
let mut redraws = self.window_target.p.redraws.lock().unwrap(); let mut redraws = self.window_target.p.redraws.lock().unwrap();
redraws.pop_front() redraws.pop_front()
} { } {
event_handler( app.window_event(
event::Event::WindowEvent {
window_id: RootWindowId(window_id),
event: event::WindowEvent::RedrawRequested,
},
&self.window_target, &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() { if self.window_target.p.exiting() {
break; break;
@ -695,7 +674,7 @@ impl<T: 'static> EventLoop<T> {
} }
} }
event_handler(event::Event::LoopExiting, &self.window_target); app.exiting(&self.window_target);
Ok(()) Ok(())
} }

View file

@ -1,6 +1,7 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::mpsc::{self, Receiver, Sender}; use std::sync::mpsc::{self, Receiver, Sender};
use crate::application::ApplicationHandler;
use crate::error::EventLoopError; use crate::error::EventLoopError;
use crate::event::Event; use crate::event::Event;
use crate::event_loop::ActiveEventLoop as RootActiveEventLoop; use crate::event_loop::ActiveEventLoop as RootActiveEventLoop;
@ -31,25 +32,13 @@ impl<T> EventLoop<T> {
Ok(EventLoop { elw, user_event_sender, user_event_receiver }) Ok(EventLoop { elw, user_event_sender, user_event_receiver })
} }
pub fn run<F>(self, mut event_handler: F) -> ! pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> ! {
where
F: FnMut(Event<T>, &RootActiveEventLoop),
{
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData }; 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`. // SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`.
let handler: Box<dyn FnMut(Event<()>)> = Box::new(|event| { let handler: Box<dyn FnMut(Event<()>)> =
let event = match event.map_nonuser_event() { Box::new(|event| handle_event(app, &target, &self.user_event_receiver, 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)
});
// SAFETY: The `transmute` is necessary because `run()` requires `'static`. This is safe // 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 // because this function will never return and all resources not cleaned up by the point we
// `throw` will leak, making this actually `'static`. // `throw` will leak, making this actually `'static`.
@ -65,24 +54,12 @@ impl<T> EventLoop<T> {
unreachable!(); unreachable!();
} }
pub fn spawn<F>(self, mut event_handler: F) pub fn spawn_app<A: ApplicationHandler<T> + 'static>(self, mut app: A) {
where
F: 'static + FnMut(Event<T>, &RootActiveEventLoop),
{
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData }; let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
self.elw.p.run( self.elw.p.run(
Box::new(move |event| { Box::new(move |event| {
let event = match event.map_nonuser_event() { handle_event(&mut app, &target, &self.user_event_receiver, 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)
}), }),
true, true,
); );
@ -96,3 +73,26 @@ impl<T> EventLoop<T> {
&self.elw &self.elw
} }
} }
fn handle_event<T: 'static, A: ApplicationHandler<T>>(
app: &mut A,
target: &RootActiveEventLoop,
user_event_receiver: &Receiver<T>,
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),
}
}

View file

@ -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, 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::dpi::{PhysicalPosition, PhysicalSize};
use crate::error::EventLoopError; use crate::error::EventLoopError;
use crate::event::{ use crate::event::{
@ -215,17 +216,14 @@ impl<T: 'static> EventLoop<T> {
&self.window_target &self.window_target
} }
pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError> pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
where self.run_app_on_demand(app)
F: FnMut(Event<T>, &RootAEL),
{
self.run_on_demand(event_handler)
} }
pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError> pub fn run_app_on_demand<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootAEL), app: &mut A,
{ ) -> Result<(), EventLoopError> {
{ {
let runner = &self.window_target.p.runner_shared; let runner = &self.window_target.p.runner_shared;
@ -236,21 +234,32 @@ impl<T: 'static> EventLoop<T> {
// returning // returning
unsafe { unsafe {
runner.set_event_handler(move |event| { runner.set_event_handler(move |event| {
// the shared `EventLoopRunner` is not parameterized match event {
// `EventLoopProxy::send_event()` calls `PostMessage` Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause),
// to wakeup and dispatch a placeholder `UserEvent`, Event::WindowEvent { window_id, event } => {
// when we received the placeholder event here, the app.window_event(event_loop_windows_ref, window_id, event)
// real UserEvent(T) should already be put in the },
// mpsc channel and ready to be pulled Event::DeviceEvent { device_id, event } => {
let event = match event.map_nonuser_event() { app.device_event(event_loop_windows_ref, device_id, event)
Ok(non_user_event) => non_user_event, },
Err(_user_event_placeholder) => Event::UserEvent( // The shared `EventLoopRunner` is not parameterized
user_event_receiver // `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() .try_recv()
.expect("user event signaled but not received"), .expect("user event signaled but not received");
), app.user_event(event_loop_windows_ref, event);
}; },
event_handler(event, event_loop_windows_ref) 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<T: 'static> EventLoop<T> {
} }
} }
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut event_handler: F) -> PumpStatus pub fn pump_app_events<A: ApplicationHandler<T>>(
where &mut self,
F: FnMut(Event<T>, &RootAEL), timeout: Option<Duration>,
{ app: &mut A,
) -> PumpStatus {
{ {
let runner = &self.window_target.p.runner_shared; let runner = &self.window_target.p.runner_shared;
let event_loop_windows_ref = &self.window_target; let event_loop_windows_ref = &self.window_target;
@ -302,16 +312,34 @@ impl<T: 'static> EventLoop<T> {
// event handler. // event handler.
unsafe { unsafe {
runner.set_event_handler(move |event| { runner.set_event_handler(move |event| {
let event = match event.map_nonuser_event() { match event {
Ok(non_user_event) => non_user_event, Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause),
Err(_user_event_placeholder) => Event::UserEvent( Event::WindowEvent { window_id, event } => {
user_event_receiver app.window_event(event_loop_windows_ref, window_id, event)
.recv() },
.expect("user event signaled but not received"), Event::DeviceEvent { device_id, event } => {
), app.device_event(event_loop_windows_ref, device_id, event)
}; },
event_handler(event, event_loop_windows_ref) // 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(); runner.wakeup();
} }
} }