Re-work event loop run() API so it can return a Result

This re-works the portable `run()` API that consumes the `EventLoop` and
runs the loop on the calling thread until the app exits.

This can be supported across _all_ platforms and compared to the
previous `run() -> !` API is now able to return a `Result` status on all
platforms except iOS and Web. Fixes: #2709

By moving away from `run() -> !` we stop calling `std::process::exit()`
internally as a means to kill the process without returning which means
it's possible to return an exit status and applications can return from
their `main()` function normally.

This also fixes Android support where an Activity runs in a thread but
we can't assume to have full ownership of the process (other services
could be running in separate threads).

Additionally all examples have generally been updated so that `main()`
returns a `Result` from `run()`

Fixes: #2709
This commit is contained in:
Robert Bragg 2023-04-11 12:50:52 +01:00 committed by Kirill Chibisov
parent a6f414d732
commit 0d366ffbda
39 changed files with 99 additions and 123 deletions

View file

@ -526,17 +526,12 @@ impl<T: 'static> EventLoop<T> {
self.pending_redraw = pending_redraw;
}
pub fn run<F>(mut self, event_handler: F) -> !
pub fn run<F>(mut self, event_handler: F) -> Result<(), RunLoopError>
where
F: 'static
+ FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
{
let exit_code = match self.run_ondemand(event_handler) {
Err(RunLoopError::ExitFailure(code)) => code,
Err(_err) => 1,
Ok(_) => 0,
};
::std::process::exit(exit_code);
self.run_ondemand(event_handler)
}
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), RunLoopError>

View file

@ -830,11 +830,11 @@ impl<T: 'static> EventLoop<T> {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
}
pub fn run<F>(self, callback: F) -> !
pub fn run<F>(mut self, callback: F) -> Result<(), RunLoopError>
where
F: 'static + FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
{
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run(callback))
self.run_ondemand(callback)
}
pub fn run_ondemand<F>(&mut self, callback: F) -> Result<(), RunLoopError>

View file

@ -145,18 +145,6 @@ impl<T: 'static> EventLoop<T> {
Ok(event_loop)
}
pub fn run<F>(mut self, callback: F) -> !
where
F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static,
{
let exit_code = match self.run_ondemand(callback) {
Err(RunLoopError::ExitFailure(code)) => code,
Err(_err) => 1,
Ok(_) => 0,
};
::std::process::exit(exit_code)
}
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), RunLoopError>
where
F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),

View file

@ -432,18 +432,6 @@ impl<T: 'static> EventLoop<T> {
&self.target
}
pub fn run<F>(mut self, callback: F) -> !
where
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow) + 'static,
{
let exit_code = match self.run_ondemand(callback) {
Err(RunLoopError::ExitFailure(code)) => code,
Err(_err) => 1,
Ok(_) => 0,
};
::std::process::exit(exit_code)
}
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), RunLoopError>
where
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),

View file

@ -6,7 +6,7 @@ use std::{
mem,
os::raw::c_void,
panic::{catch_unwind, resume_unwind, AssertUnwindSafe, RefUnwindSafe, UnwindSafe},
process, ptr,
ptr,
rc::{Rc, Weak},
sync::mpsc,
};
@ -192,16 +192,11 @@ impl<T> EventLoop<T> {
&self.window_target
}
pub fn run<F>(mut self, callback: F) -> !
pub fn run<F>(mut self, callback: F) -> Result<(), RunLoopError>
where
F: 'static + FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
{
let exit_code = match self.run_ondemand(callback) {
Err(RunLoopError::ExitFailure(code)) => code,
Err(_err) => 1,
Ok(_) => 0,
};
process::exit(exit_code);
self.run_ondemand(callback)
}
// NB: we don't base this on `pump_events` because for `MacOs` we can't support

View file

@ -12,6 +12,7 @@ use orbclient::{
use raw_window_handle::{OrbitalDisplayHandle, RawDisplayHandle};
use crate::{
error::RunLoopError,
event::{self, Ime, Modifiers, StartCause},
event_loop::{self, ControlFlow},
keyboard::{
@ -442,7 +443,7 @@ impl<T: 'static> EventLoop<T> {
}
}
pub fn run<F>(mut self, event_handler: F) -> !
pub fn run<F>(mut self, mut event_handler_inner: F) -> Result<(), RunLoopError>
where
F: 'static
+ FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
@ -688,7 +689,11 @@ impl<T: 'static> EventLoop<T> {
&mut control_flow,
);
::std::process::exit(code);
if code == 0 {
Ok(())
} else {
Err(RunLoopError::ExitFailure(code))
}
}
pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget<T> {

View file

@ -243,16 +243,11 @@ impl<T: 'static> EventLoop<T> {
&self.window_target
}
pub fn run<F>(mut self, event_handler: F) -> !
pub fn run<F>(mut self, event_handler: F) -> Result<(), RunLoopError>
where
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
{
let exit_code = match self.run_ondemand(event_handler) {
Err(RunLoopError::ExitFailure(code)) => code,
Err(_err) => 1,
Ok(_) => 0,
};
::std::process::exit(exit_code);
self.run_ondemand(event_handler)
}
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), RunLoopError>