Skip to content
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
efb3af3
Introduce `run_return`
thomaseizinger Feb 10, 2025
fad231a
Fix compile error
thomaseizinger Feb 10, 2025
a65ec7f
Clone web_context
thomaseizinger Feb 10, 2025
0ee9182
Refactor to Result API
thomaseizinger Feb 11, 2025
7fced1a
Fix clippy
thomaseizinger Feb 11, 2025
8b9ee81
Impl mock runtime
thomaseizinger Feb 11, 2025
baec5c3
Make it desktop-only
thomaseizinger Feb 11, 2025
10efd0b
Add changelog entry
thomaseizinger Feb 11, 2025
8ccee7a
Fix compile error
thomaseizinger Feb 11, 2025
f8c6426
Make it semver compatible
thomaseizinger Feb 11, 2025
b95c177
Extend changelog entry
thomaseizinger Feb 11, 2025
79aa4b0
Undo semver-hack
thomaseizinger Feb 11, 2025
7e4599f
Reduce diff
thomaseizinger Feb 11, 2025
3f395bf
Remove unnecessary mut
thomaseizinger Feb 11, 2025
4d05665
Make it take `self` by value
thomaseizinger Feb 11, 2025
a69b550
Reduce diff
thomaseizinger Feb 11, 2025
9fda2c3
Undo diff hack
thomaseizinger Feb 11, 2025
93cf314
Make everything cfg(desktop)
thomaseizinger Feb 11, 2025
463b7ca
Rename vars to reduce diff
thomaseizinger Feb 11, 2025
fad99ed
Fix clippy
thomaseizinger Feb 13, 2025
a7acec4
Extract make_event_handler
thomaseizinger Feb 13, 2025
8f06fa7
Reduce diff
thomaseizinger Feb 13, 2025
972d346
Deprecate `App::run_return`
thomaseizinger Feb 13, 2025
0d8d848
Update changelog
thomaseizinger Feb 13, 2025
dbb64c1
Fix compile errors
thomaseizinger Feb 17, 2025
0ca7928
Accept reference
thomaseizinger Feb 17, 2025
6885b89
Create event handler first
thomaseizinger Feb 17, 2025
201703a
Update example
thomaseizinger Feb 17, 2025
7d94b41
Update manifest
thomaseizinger Feb 17, 2025
4dfec40
Fix example
thomaseizinger Feb 17, 2025
640db7e
Fix example docs
thomaseizinger Feb 24, 2025
9399241
Call `setup` only upon Ready
thomaseizinger Feb 24, 2025
d521c2e
Update changelog entry
thomaseizinger Feb 24, 2025
2e56bc3
Update docs
thomaseizinger Feb 25, 2025
e20ac0c
Update changelog
thomaseizinger Feb 25, 2025
ba70a4f
Add platform-specific note
thomaseizinger Feb 26, 2025
edaac28
update docs
lucasfernog Mar 15, 2025
15002c0
run_return on mobile
lucasfernog Mar 15, 2025
23dd118
Apply suggestions from code review [skip ci]
lucasfernog Mar 16, 2025
a2b4412
remove change file [skip ci]
lucasfernog Mar 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changes/introduce-run-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
tauri: 'minor:feat'
tauri-runtime: 'minor:feat'
tauri-runtime-wry: 'minor:feat'
---

Add `App::run_return` function. Contrary to `App::run`, this will **not** exit the process but instead return the requested exit-code. This allows the host app to perform further cleanup after Tauri has exited. `App::run_return` is only available on desktop platforms.

The `App::run_iteration` function is deprecated as part of this because calling it in a loop - as suggested by the name - will cause a busy-loop.
5 changes: 5 additions & 0 deletions .changes/run-return-mobile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri-runtime": minor:feat
---

`Runtime::run_return` now must also be implemented on mobile targets.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this can be omitted because the function is only added in this PR (see other changelog entry?)

90 changes: 59 additions & 31 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2830,39 +2830,51 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
});
}

fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
let windows = self.context.main_thread.windows.clone();
let window_id_map = self.context.window_id_map.clone();
let web_context = self.context.main_thread.web_context;
let plugins = self.context.plugins.clone();
fn run<F: FnMut(RunEvent<T>) + 'static>(self, callback: F) {
let event_handler = make_event_handler(&self, callback);

#[cfg(feature = "tracing")]
let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone();
let proxy = self.event_loop.create_proxy();
self.event_loop.run(event_handler)
}

self.event_loop.run(move |event, event_loop, control_flow| {
for p in plugins.lock().unwrap().iter_mut() {
let prevent_default = p.on_event(
&event,
event_loop,
&proxy,
control_flow,
EventLoopIterationContext {
callback: &mut callback,
window_id_map: window_id_map.clone(),
windows: windows.clone(),
#[cfg(feature = "tracing")]
active_tracing_spans: active_tracing_spans.clone(),
},
&web_context,
);
if prevent_default {
return;
}
}
handle_event_loop(
event,
#[cfg(not(target_os = "ios"))]
fn run_return<F: FnMut(RunEvent<T>) + 'static>(mut self, callback: F) -> i32 {
use tao::platform::run_return::EventLoopExtRunReturn;

let event_handler = make_event_handler(&self, callback);

self.event_loop.run_return(event_handler)
}

#[cfg(target_os = "ios")]
fn run_return<F: FnMut(RunEvent<T>) + 'static>(mut self, callback: F) -> i32 {
self.run(callback);
0
}
}

fn make_event_handler<T, F>(
runtime: &Wry<T>,
mut callback: F,
) -> impl FnMut(Event<'_, Message<T>>, &EventLoopWindowTarget<Message<T>>, &mut ControlFlow)
where
T: UserEvent,
F: FnMut(RunEvent<T>) + 'static,
{
let windows = runtime.context.main_thread.windows.clone();
let window_id_map = runtime.context.window_id_map.clone();
let web_context = runtime.context.main_thread.web_context.clone();
let plugins = runtime.context.plugins.clone();

#[cfg(feature = "tracing")]
let active_tracing_spans = runtime.context.main_thread.active_tracing_spans.clone();
let proxy = runtime.event_loop.create_proxy();

move |event, event_loop, control_flow| {
for p in plugins.lock().unwrap().iter_mut() {
let prevent_default = p.on_event(
&event,
event_loop,
&proxy,
control_flow,
EventLoopIterationContext {
callback: &mut callback,
Expand All @@ -2871,8 +2883,24 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
#[cfg(feature = "tracing")]
active_tracing_spans: active_tracing_spans.clone(),
},
&web_context,
);
})
if prevent_default {
return;
}
}
handle_event_loop(
event,
event_loop,
control_flow,
EventLoopIterationContext {
callback: &mut callback,
window_id_map: window_id_map.clone(),
windows: windows.clone(),
#[cfg(feature = "tracing")]
active_tracing_spans: active_tracing_spans.clone(),
},
);
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,9 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
#[cfg(desktop)]
fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, callback: F);

/// Equivalent to [`Runtime::run`] but returns the exit code instead of exiting the process.
fn run_return<F: FnMut(RunEvent<T>) + 'static>(self, callback: F) -> i32;

/// Run the webview runtime.
fn run<F: FnMut(RunEvent<T>) + 'static>(self, callback: F);
}
Expand Down
4 changes: 2 additions & 2 deletions crates/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,8 @@ name = "multiwindow"
path = "../../examples/multiwindow/main.rs"

[[example]]
name = "run-iteration"
path = "../../examples/run-iteration/main.rs"
name = "run-return"
path = "../../examples/run-return/main.rs"

[[example]]
name = "splashscreen"
Expand Down
64 changes: 64 additions & 0 deletions crates/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,13 @@ impl<R: Runtime> App<R> {

/// Runs the application.
///
/// This function never returns. When the application finishes, the process is exited directly using [`std::process::exit`].
/// See [`run_return`](Self::run_return) if you need to run code after the application event loop exits.
///
/// # Panics
///
/// This function will panic if the setup-function supplied in [`Builder::setup`] fails.
///
/// # Examples
/// ```,no_run
/// let app = tauri::Builder::default()
Expand Down Expand Up @@ -1092,6 +1099,60 @@ impl<R: Runtime> App<R> {
});
}

/// Runs the application, returning its intended exit code.
///
/// ## Platform-specific
///
/// - **iOS**: Unsupported. The application will fallback to [`run`](Self::run).
///
/// # Panics
///
/// This function will panic if the setup-function supplied in [`Builder::setup`] fails.
///
/// # Examples
/// ```,no_run
/// let app = tauri::Builder::default()
/// // on an actual app, remove the string argument
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
/// .expect("error while building tauri application");
/// let exit_code = app
/// .run_return(|_app_handle, event| match event {
/// tauri::RunEvent::ExitRequested { api, .. } => {
/// api.prevent_exit();
/// }
/// _ => {}
/// });
///
/// std::process::exit(exit_code);
/// ```
pub fn run_return<F: FnMut(&AppHandle<R>, RunEvent) + 'static>(mut self, mut callback: F) -> i32 {
let manager = self.manager.clone();
let app_handle = self.handle().clone();

self
.runtime
.take()
.unwrap()
.run_return(move |event| match event {
RuntimeRunEvent::Ready => {
if let Err(e) = setup(&mut self) {
panic!("Failed to setup app: {e}");
}
let event = on_event_loop_event(&app_handle, RuntimeRunEvent::Ready, &manager);
callback(&app_handle, event);
}
RuntimeRunEvent::Exit => {
let event = on_event_loop_event(&app_handle, RuntimeRunEvent::Exit, &manager);
callback(&app_handle, event);
app_handle.cleanup_before_exit();
}
_ => {
let event = on_event_loop_event(&app_handle, event, &manager);
callback(&app_handle, event);
}
})
}

/// Runs an iteration of the runtime event loop and immediately return.
///
/// Note that when using this API, app cleanup is not automatically done.
Expand All @@ -1115,6 +1176,9 @@ impl<R: Runtime> App<R> {
/// }
/// ```
#[cfg(desktop)]
#[deprecated(
note = "When called in a loop (as suggested by the name), this function will busy-loop. To re-gain control of control flow after the app has exited, use `App::run_return` instead."
)]
pub fn run_iteration<F: FnMut(&AppHandle<R>, RunEvent) + 'static>(&mut self, mut callback: F) {
let manager = self.manager.clone();
let app_handle = self.handle().clone();
Expand Down
6 changes: 6 additions & 0 deletions crates/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,12 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
))]
fn run_iteration<F: FnMut(RunEvent<T>)>(&mut self, callback: F) {}

fn run_return<F: FnMut(RunEvent<T>) + 'static>(self, callback: F) -> i32 {
self.run(callback);

0
}

fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
self.is_running.store(true, Ordering::Relaxed);
callback(RunEvent::Ready);
Expand Down
3 changes: 0 additions & 3 deletions examples/run-iteration/README.md

This file was deleted.

3 changes: 3 additions & 0 deletions examples/run-return/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Run Return Example

To execute run the following on the root directory of the repository: `cargo run --example run-return`.
File renamed without changes.
21 changes: 8 additions & 13 deletions examples/run-iteration/main.rs → examples/run-return/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,18 @@

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use tauri::Manager;

fn main() {
let mut app = tauri::Builder::default()
let app = tauri::Builder::default()
.build(tauri::generate_context!(
"../../examples/run-iteration/tauri.conf.json"
"../../examples/run-return/tauri.conf.json"
))
.expect("error while building tauri application");

loop {
app.run_iteration(|_app, _event| {
//println!("{:?}", _event);
});
let exit_code = app.run_return(|_app, _event| {
//println!("{:?}", _event);
});

println!("I run after exit");

if app.webview_windows().is_empty() {
app.cleanup_before_exit();
break;
}
}
std::process::exit(exit_code);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "../../crates/tauri-schema-generator/schemas/config.schema.json",
"productName": "RunIteration",
"productName": "RunReturn",
"version": "0.1.0",
"identifier": "com.tauri.dev",
"build": {
Expand Down
Loading