Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce App::run_return #12668

Open
wants to merge 30 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
869b09e
Introduce `run_return`
thomaseizinger Feb 10, 2025
6ef503d
Fix compile error
thomaseizinger Feb 10, 2025
930e45f
Clone web_context
thomaseizinger Feb 10, 2025
a495daf
Refactor to Result API
thomaseizinger Feb 11, 2025
94ae3ef
Fix clippy
thomaseizinger Feb 11, 2025
3b3dd3a
Impl mock runtime
thomaseizinger Feb 11, 2025
5f4f2f4
Make it desktop-only
thomaseizinger Feb 11, 2025
9be493e
Add changelog entry
thomaseizinger Feb 11, 2025
0325274
Fix compile error
thomaseizinger Feb 11, 2025
9953452
Make it semver compatible
thomaseizinger Feb 11, 2025
918a1d5
Extend changelog entry
thomaseizinger Feb 11, 2025
f0580df
Undo semver-hack
thomaseizinger Feb 11, 2025
075d436
Reduce diff
thomaseizinger Feb 11, 2025
3d88211
Remove unnecessary mut
thomaseizinger Feb 11, 2025
ac2711b
Make it take `self` by value
thomaseizinger Feb 11, 2025
fcda384
Reduce diff
thomaseizinger Feb 11, 2025
e04ff09
Undo diff hack
thomaseizinger Feb 11, 2025
e48e8c3
Make everything cfg(desktop)
thomaseizinger Feb 11, 2025
71c51ea
Rename vars to reduce diff
thomaseizinger Feb 11, 2025
5818937
Fix clippy
thomaseizinger Feb 13, 2025
97a18a6
Extract make_event_handler
thomaseizinger Feb 13, 2025
419b084
Reduce diff
thomaseizinger Feb 13, 2025
4d7b761
Deprecate `App::run_return`
thomaseizinger Feb 13, 2025
dad7221
Update changelog
thomaseizinger Feb 13, 2025
793e2d5
Fix compile errors
thomaseizinger Feb 17, 2025
c5aadac
Accept reference
thomaseizinger Feb 17, 2025
3eacfa5
Create event handler first
thomaseizinger Feb 17, 2025
226adbb
Update example
thomaseizinger Feb 17, 2025
80591e0
Update manifest
thomaseizinger Feb 17, 2025
93f566c
Fix example
thomaseizinger Feb 17, 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
5 changes: 5 additions & 0 deletions .changes/introduce-run-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
tauri: 'minor:feat'
---

Add `App::run_return` function. Contrary to `App::run`, this will **not** exit the thread but instead return the requested exit-code. This allows the host app to perform further cleanup after Tauri has exited.
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
59 changes: 34 additions & 25 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2830,22 +2830,43 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
});
}

fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
fn run_return<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) -> i32 {
use tao::platform::run_return::EventLoopExtRunReturn;

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 web_context = self.context.main_thread.web_context.clone();
let plugins = self.context.plugins.clone();

#[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(move |event, event_loop, control_flow| {
for p in plugins.lock().unwrap().iter_mut() {
let prevent_default = p.on_event(
&event,
self
.event_loop
.run_return(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,
event_loop,
&proxy,
control_flow,
EventLoopIterationContext {
callback: &mut callback,
Expand All @@ -2854,25 +2875,13 @@ 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(),
},
);
})
})
}

fn run<F: FnMut(RunEvent<T>) + 'static>(mut self, callback: F) {
let exit_code = self.run_return(callback);
std::process::exit(exit_code);
}
}

Expand Down
4 changes: 4 additions & 0 deletions crates/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,10 @@ 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.
#[cfg(desktop)]
fn run_return<F: FnMut(RunEvent<T>) + 'static>(&mut self, callback: F) -> i32;
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved

/// Run the webview runtime.
fn run<F: FnMut(RunEvent<T>) + 'static>(self, callback: F);
}
Expand Down
38 changes: 38 additions & 0 deletions crates/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,44 @@ impl<R: Runtime> App<R> {
});
}

/// Runs the application, returning the exit code to use.
///
/// # 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();
/// }
/// _ => {}
/// })
/// .unwrap();
///
/// std::process::exit(exit_code);
/// ```
#[cfg(desktop)]
pub fn run_return<F: FnMut(&AppHandle<R>, RunEvent) + 'static>(mut self, mut callback: F) -> std::result::Result<i32, Box<dyn std::error::Error> {
let manager = self.manager.clone();
let app_handle = self.handle().clone();

if !self.ran_setup {
setup(&mut self)?;
}
Comment on lines +1122 to +1124
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious, don't we need to match event Ready/Exit like in App::run?

Copy link
Author

Choose a reason for hiding this comment

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

I am not too familiar with this bit and copied what was done for run_iteration before. When is the ready event emitted?

For exit, given that we now return control flow, I don't think we need to match on the Exit event.


let exit_code = self.runtime.as_mut().unwrap().run_return(move |event| {
let event = on_event_loop_event(&app_handle, event, &manager);
callback(&app_handle, event);
});

self.cleanup_before_exit();

Ok(exit_code)
}

/// Runs an iteration of the runtime event loop and immediately return.
///
/// Note that when using this API, app cleanup is not automatically done.
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>(&mut self, mut 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