mirror of https://github.com/tauri-apps/tauri
refactor(core)!: App::run_iteration improvements (#8696)
* refactor(core): App::run_iteration improvements * lint * fixes * fix exit * Apply suggestions from code review Co-authored-by: Fabian-Lars <fabianlars@fabianlars.de> * update cargo.toml * booooool * fix mock runtime * fix doctests * fix doctest againrrrr --------- Co-authored-by: Fabian-Lars <fabianlars@fabianlars.de>
This commit is contained in:
parent
9cb9aa7978
commit
ec9818accb
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"tauri": patch:breaking
|
||||
---
|
||||
|
||||
Added a callback to the `App::run_iteration` and removed its return value.
|
|
@ -21,8 +21,8 @@ use tauri_runtime::{
|
|||
WindowBuilderBase, WindowEvent, WindowId,
|
||||
},
|
||||
DeviceEventFilter, Error, EventLoopProxy, ExitRequestedEventAction, Icon, Result, RunEvent,
|
||||
RunIteration, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, UserEvent,
|
||||
WebviewDispatch, WindowDispatch, WindowEventId,
|
||||
Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, UserEvent, WebviewDispatch,
|
||||
WindowDispatch, WindowEventId,
|
||||
};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -2286,7 +2286,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
|||
}
|
||||
|
||||
#[cfg(desktop)]
|
||||
fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) -> RunIteration {
|
||||
fn run_iteration<F: FnMut(RunEvent<T>)>(&mut self, mut callback: F) {
|
||||
use tao::platform::run_return::EventLoopExtRunReturn;
|
||||
let windows = self.context.main_thread.windows.clone();
|
||||
let webview_id_map = self.context.webview_id_map.clone();
|
||||
|
@ -2296,8 +2296,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
|||
#[cfg(feature = "tracing")]
|
||||
let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone();
|
||||
|
||||
let mut iteration = RunIteration::default();
|
||||
|
||||
let proxy = self.event_loop.create_proxy();
|
||||
|
||||
self
|
||||
|
@ -2328,7 +2326,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
|||
}
|
||||
}
|
||||
|
||||
iteration = handle_event_loop(
|
||||
handle_event_loop(
|
||||
event,
|
||||
event_loop,
|
||||
control_flow,
|
||||
|
@ -2341,8 +2339,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
|||
},
|
||||
);
|
||||
});
|
||||
|
||||
iteration
|
||||
}
|
||||
|
||||
fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
|
||||
|
@ -2392,7 +2388,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
|||
}
|
||||
|
||||
pub struct EventLoopIterationContext<'a, T: UserEvent> {
|
||||
pub callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
|
||||
pub callback: &'a mut (dyn FnMut(RunEvent<T>)),
|
||||
pub webview_id_map: WindowIdStore,
|
||||
pub windows: Rc<RefCell<HashMap<WindowId, WindowWrapper>>>,
|
||||
#[cfg(feature = "tracing")]
|
||||
|
@ -2408,7 +2404,7 @@ fn handle_user_message<T: UserEvent>(
|
|||
event_loop: &EventLoopWindowTarget<Message<T>>,
|
||||
message: Message<T>,
|
||||
context: UserMessageContext,
|
||||
) -> RunIteration {
|
||||
) {
|
||||
let UserMessageContext {
|
||||
webview_id_map,
|
||||
windows,
|
||||
|
@ -2825,11 +2821,6 @@ fn handle_user_message<T: UserEvent>(
|
|||
|
||||
Message::UserEvent(_) => (),
|
||||
}
|
||||
|
||||
let it = RunIteration {
|
||||
window_count: windows.borrow().len(),
|
||||
};
|
||||
it
|
||||
}
|
||||
|
||||
fn handle_event_loop<T: UserEvent>(
|
||||
|
@ -2837,7 +2828,7 @@ fn handle_event_loop<T: UserEvent>(
|
|||
event_loop: &EventLoopWindowTarget<Message<T>>,
|
||||
control_flow: &mut ControlFlow,
|
||||
context: EventLoopIterationContext<'_, T>,
|
||||
) -> RunIteration {
|
||||
) {
|
||||
let EventLoopIterationContext {
|
||||
callback,
|
||||
webview_id_map,
|
||||
|
@ -2994,7 +2985,7 @@ fn handle_event_loop<T: UserEvent>(
|
|||
}
|
||||
Message::UserEvent(t) => callback(RunEvent::UserEvent(t)),
|
||||
message => {
|
||||
return handle_user_message(
|
||||
handle_user_message(
|
||||
event_loop,
|
||||
message,
|
||||
UserMessageContext {
|
||||
|
@ -3010,15 +3001,10 @@ fn handle_event_loop<T: UserEvent>(
|
|||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let it = RunIteration {
|
||||
window_count: windows.borrow().len(),
|
||||
};
|
||||
it
|
||||
}
|
||||
|
||||
fn on_close_requested<'a, T: UserEvent>(
|
||||
callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
|
||||
fn on_close_requested<T: UserEvent>(
|
||||
callback: &mut (dyn FnMut(RunEvent<T>)),
|
||||
window_id: WindowId,
|
||||
windows: Rc<RefCell<HashMap<WindowId, WindowWrapper>>>,
|
||||
) {
|
||||
|
|
|
@ -184,12 +184,6 @@ pub enum ExitRequestedEventAction {
|
|||
Prevent,
|
||||
}
|
||||
|
||||
/// Metadata for a runtime event loop iteration on `run_iteration`.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RunIteration {
|
||||
pub window_count: usize,
|
||||
}
|
||||
|
||||
/// Application's activation policy. Corresponds to NSApplicationActivationPolicy.
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
|
||||
|
@ -340,9 +334,9 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
|
|||
/// [`tao`]: https://crates.io/crates/tao
|
||||
fn set_device_event_filter(&mut self, filter: DeviceEventFilter);
|
||||
|
||||
/// Runs the one step of the webview runtime event loop and returns control flow to the caller.
|
||||
/// Runs an iteration of the runtime event loop and returns control flow to the caller.
|
||||
#[cfg(desktop)]
|
||||
fn run_iteration<F: Fn(RunEvent<T>) + 'static>(&mut self, callback: F) -> RunIteration;
|
||||
fn run_iteration<F: FnMut(RunEvent<T>)>(&mut self, callback: F);
|
||||
|
||||
/// Run the webview runtime.
|
||||
fn run<F: FnMut(RunEvent<T>) + 'static>(self, callback: F);
|
||||
|
|
|
@ -205,3 +205,7 @@ path = "../../examples/streaming/main.rs"
|
|||
name = "isolation"
|
||||
path = "../../examples/isolation/main.rs"
|
||||
required-features = [ "isolation" ]
|
||||
|
||||
[[example]]
|
||||
name = "run-iteration"
|
||||
path = "../../examples/run-iteration/main.rs"
|
||||
|
|
|
@ -406,6 +406,7 @@ pub struct App<R: Runtime> {
|
|||
setup: Option<SetupHook<R>>,
|
||||
manager: Arc<AppManager<R>>,
|
||||
handle: AppHandle<R>,
|
||||
ran_setup: bool,
|
||||
}
|
||||
|
||||
impl<R: Runtime> fmt::Debug for App<R> {
|
||||
|
@ -862,59 +863,57 @@ impl<R: Runtime> App<R> {
|
|||
if let Err(e) = setup(&mut self) {
|
||||
panic!("Failed to setup app: {e}");
|
||||
}
|
||||
on_event_loop_event(
|
||||
&app_handle,
|
||||
RuntimeRunEvent::Ready,
|
||||
&manager,
|
||||
Some(&mut callback),
|
||||
);
|
||||
let event = on_event_loop_event(&app_handle, RuntimeRunEvent::Ready, &manager);
|
||||
callback(&app_handle, event);
|
||||
}
|
||||
RuntimeRunEvent::Exit => {
|
||||
on_event_loop_event(
|
||||
&app_handle,
|
||||
RuntimeRunEvent::Exit,
|
||||
&manager,
|
||||
Some(&mut callback),
|
||||
);
|
||||
let event = on_event_loop_event(&app_handle, RuntimeRunEvent::Exit, &manager);
|
||||
callback(&app_handle, event);
|
||||
app_handle.cleanup_before_exit();
|
||||
}
|
||||
_ => {
|
||||
on_event_loop_event(&app_handle, event, &manager, Some(&mut callback));
|
||||
let event = on_event_loop_event(&app_handle, event, &manager);
|
||||
callback(&app_handle, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Runs a iteration of the runtime event loop and immediately return.
|
||||
/// Runs an iteration of the runtime event loop and immediately return.
|
||||
///
|
||||
/// Note that when using this API, app cleanup is not automatically done.
|
||||
/// The cleanup calls [`App::cleanup_before_exit`] so you may want to call that function before exiting the application.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// use tauri::Manager;
|
||||
///
|
||||
/// let mut 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");
|
||||
///
|
||||
/// loop {
|
||||
/// let iteration = app.run_iteration();
|
||||
/// if iteration.window_count == 0 {
|
||||
/// app.run_iteration(|_app, _event| {});
|
||||
/// if app.webview_windows().is_empty() {
|
||||
/// app.cleanup_before_exit();
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(desktop)]
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(name = "app::run_iteration"))]
|
||||
pub fn run_iteration(&mut self) -> crate::runtime::RunIteration {
|
||||
pub fn run_iteration<F: FnMut(&AppHandle<R>, RunEvent)>(&mut self, mut callback: F) {
|
||||
let manager = self.manager.clone();
|
||||
let app_handle = self.handle().clone();
|
||||
|
||||
if !self.ran_setup {
|
||||
if let Err(e) = setup(self) {
|
||||
panic!("Failed to setup app: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
self.runtime.as_mut().unwrap().run_iteration(move |event| {
|
||||
on_event_loop_event(
|
||||
&app_handle,
|
||||
event,
|
||||
&manager,
|
||||
Option::<&mut Box<dyn FnMut(&AppHandle<R>, RunEvent)>>::None,
|
||||
)
|
||||
let event = on_event_loop_event(&app_handle, event, &manager);
|
||||
callback(&app_handle, event);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1537,6 +1536,7 @@ tauri::Builder::default()
|
|||
runtime_handle,
|
||||
manager,
|
||||
},
|
||||
ran_setup: false,
|
||||
};
|
||||
|
||||
#[cfg(desktop)]
|
||||
|
@ -1674,6 +1674,8 @@ unsafe impl<R: Runtime> HasRawDisplayHandle for App<R> {
|
|||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(name = "app::setup"))]
|
||||
fn setup<R: Runtime>(app: &mut App<R>) -> crate::Result<()> {
|
||||
app.ran_setup = true;
|
||||
|
||||
let window_labels = app
|
||||
.config()
|
||||
.tauri
|
||||
|
@ -1701,19 +1703,17 @@ fn setup<R: Runtime>(app: &mut App<R>) -> crate::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn on_event_loop_event<R: Runtime, F: FnMut(&AppHandle<R>, RunEvent) + 'static>(
|
||||
fn on_event_loop_event<R: Runtime>(
|
||||
app_handle: &AppHandle<R>,
|
||||
event: RuntimeRunEvent<EventLoopMessage>,
|
||||
manager: &AppManager<R>,
|
||||
callback: Option<&mut F>,
|
||||
) {
|
||||
) -> RunEvent {
|
||||
if let RuntimeRunEvent::WindowEvent {
|
||||
label,
|
||||
event: RuntimeWindowEvent::Destroyed,
|
||||
} = &event
|
||||
{
|
||||
// TODO: destroy webviews
|
||||
manager.window.on_window_close(label);
|
||||
manager.on_window_close(label);
|
||||
}
|
||||
|
||||
let event = match event {
|
||||
|
@ -1805,9 +1805,7 @@ fn on_event_loop_event<R: Runtime, F: FnMut(&AppHandle<R>, RunEvent) + 'static>(
|
|||
.expect("poisoned plugin store")
|
||||
.on_event(app_handle, &event);
|
||||
|
||||
if let Some(c) = callback {
|
||||
c(app_handle, event);
|
||||
}
|
||||
event
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -214,7 +214,7 @@ pub use {
|
|||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size},
|
||||
CursorIcon, FileDropEvent,
|
||||
},
|
||||
DeviceEventFilter, RunIteration, UserAttentionType,
|
||||
DeviceEventFilter, UserAttentionType,
|
||||
},
|
||||
self::state::{State, StateManager},
|
||||
self::utils::{
|
||||
|
|
|
@ -542,6 +542,14 @@ impl<R: Runtime> AppManager<R> {
|
|||
.map(|w| w.1.clone())
|
||||
}
|
||||
|
||||
pub(crate) fn on_window_close(&self, label: &str) {
|
||||
if let Some(window) = self.window.windows_lock().remove(label) {
|
||||
for webview in window.webviews() {
|
||||
self.webview.webviews_lock().remove(webview.label());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn windows(&self) -> HashMap<String, Window<R>> {
|
||||
self.window.windows_lock().clone()
|
||||
}
|
||||
|
|
|
@ -125,10 +125,6 @@ impl<R: Runtime> WindowManager<R> {
|
|||
window
|
||||
}
|
||||
|
||||
pub(crate) fn on_window_close(&self, label: &str) {
|
||||
self.windows_lock().remove(label);
|
||||
}
|
||||
|
||||
pub fn labels(&self) -> HashSet<String> {
|
||||
self.windows_lock().keys().cloned().collect()
|
||||
}
|
||||
|
|
|
@ -992,12 +992,7 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
|
|||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
fn run_iteration<F: Fn(RunEvent<T>) + 'static>(
|
||||
&mut self,
|
||||
callback: F,
|
||||
) -> tauri_runtime::RunIteration {
|
||||
Default::default()
|
||||
}
|
||||
fn run_iteration<F: FnMut(RunEvent<T>)>(&mut self, callback: F) {}
|
||||
|
||||
fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
|
||||
self.is_running.store(true, Ordering::Relaxed);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Run Iteration Example
|
||||
|
||||
To execute run the following on the root directory of the repository: `cargo run --example run-iteration`.
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Welcome to Tauri!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to Tauri!</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use tauri::Manager;
|
||||
|
||||
fn main() {
|
||||
let mut app = tauri::Builder::default()
|
||||
.build(tauri::generate_context!(
|
||||
"../../examples/run-iteration/tauri.conf.json"
|
||||
))
|
||||
.expect("error while building tauri application");
|
||||
|
||||
loop {
|
||||
app.run_iteration(|_app, _event| {
|
||||
//println!("{:?}", _event);
|
||||
});
|
||||
|
||||
if app.webview_windows().is_empty() {
|
||||
app.cleanup_before_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"$schema": "../../core/tauri-config-schema/schema.json",
|
||||
"build": {
|
||||
"distDir": [
|
||||
"index.html"
|
||||
],
|
||||
"devPath": [
|
||||
"index.html"
|
||||
],
|
||||
"beforeDevCommand": "",
|
||||
"beforeBuildCommand": ""
|
||||
},
|
||||
"package": {
|
||||
"productName": "RunIteration",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"identifier": "com.tauri.dev",
|
||||
"icon": [
|
||||
"../.icons/32x32.png",
|
||||
"../.icons/128x128.png",
|
||||
"../.icons/128x128@2x.png",
|
||||
"../.icons/icon.icns",
|
||||
"../.icons/icon.ico"
|
||||
],
|
||||
"resources": [],
|
||||
"externalBin": [],
|
||||
"copyright": "",
|
||||
"category": "DeveloperTool",
|
||||
"shortDescription": "",
|
||||
"longDescription": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
"files": {},
|
||||
"exceptionDomain": ""
|
||||
}
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"title": "Welcome to Tauri!",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"resizable": true,
|
||||
"fullscreen": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": "default-src 'self'; connect-src ipc: http://ipc.localhost"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue