From b4622ea4d32720bc3bb2a8c740bb70cfe32fed93 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Thu, 11 Aug 2022 10:30:55 -0300 Subject: [PATCH] refactor(app): run setup and window creation when event loop is ready (#4914) --- .changes/config.json | 2 - .changes/refactor-setup.md | 5 +++ core/tauri/src/app.rs | 92 +++++++++++++++++++++++++++++--------- core/tauri/src/test/mod.rs | 16 ++++--- 4 files changed, 86 insertions(+), 29 deletions(-) create mode 100644 .changes/refactor-setup.md diff --git a/.changes/config.json b/.changes/config.json index eb8bdeb0c..9376b807a 100644 --- a/.changes/config.json +++ b/.changes/config.json @@ -3,7 +3,6 @@ "timeout": 3600000, "pkgManagers": { "rust": { - "errorOnVersionRange": "^2.0.0-0", "version": true, "getPublishedVersion": "cargo search ${ pkgFile.pkg.package.name } --limit 1 | sed -nE \"s/^[^\\\"]*\\\"//; s/\\\".*//1p\"", "prepublish": [ @@ -78,7 +77,6 @@ ] }, "javascript": { - "errorOnVersionRange": "^2.0.0-0", "version": true, "getPublishedVersion": "npm view ${ pkgFile.pkg.name } version", "prepublish": [ diff --git a/.changes/refactor-setup.md b/.changes/refactor-setup.md new file mode 100644 index 000000000..657cf32d2 --- /dev/null +++ b/.changes/refactor-setup.md @@ -0,0 +1,5 @@ +--- +"tauri": major +--- + +**Breaking change:** The window creation and setup hook are now called when the event loop is ready. diff --git a/core/tauri/src/app.rs b/core/tauri/src/app.rs index 7084b0924..9e9e4a811 100644 --- a/core/tauri/src/app.rs +++ b/core/tauri/src/app.rs @@ -40,6 +40,7 @@ use tauri_utils::PackageInfo; use std::{ collections::HashMap, + fmt, path::{Path, PathBuf}, sync::{mpsc::Sender, Arc, Weak}, }; @@ -526,9 +527,10 @@ impl ManagerBase for AppHandle { /// /// This type implements [`Manager`] which allows for manipulation of global application items. #[default_runtime(crate::Wry, wry)] -#[derive(Debug)] pub struct App { runtime: Option, + pending_windows: Option>>, + setup: Option>, manager: WindowManager, #[cfg(all(desktop, feature = "global-shortcut"))] global_shortcut_manager: R::GlobalShortcutManager, @@ -537,6 +539,22 @@ pub struct App { handle: AppHandle, } +impl fmt::Debug for App { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("App"); + d.field("runtime", &self.runtime) + .field("manager", &self.manager) + .field("handle", &self.handle); + + #[cfg(all(desktop, feature = "global-shortcut"))] + d.field("global_shortcut_manager", &self.global_shortcut_manager); + #[cfg(feature = "clipboard")] + d.field("clipboard_manager", &self.clipboard_manager); + + d.finish() + } +} + impl Manager for App {} impl ManagerBase for App { fn manager(&self) -> &WindowManager { @@ -544,7 +562,11 @@ impl ManagerBase for App { } fn runtime(&self) -> RuntimeOrDispatch<'_, R> { - RuntimeOrDispatch::Runtime(self.runtime.as_ref().unwrap()) + if let Some(runtime) = self.runtime.as_ref() { + RuntimeOrDispatch::Runtime(runtime) + } else { + self.handle.runtime() + } } fn managed_app_handle(&self) -> AppHandle { @@ -775,6 +797,17 @@ impl App { let app_handle = self.handle(); let manager = self.manager.clone(); self.runtime.take().unwrap().run(move |event| match event { + RuntimeRunEvent::Ready => { + 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), + ); + } RuntimeRunEvent::Exit => { on_event_loop_event( &app_handle, @@ -1460,8 +1493,11 @@ impl Builder { #[cfg(feature = "clipboard")] let clipboard_manager = runtime.clipboard_manager(); + #[allow(unused_mut)] let mut app = App { runtime: Some(runtime), + pending_windows: Some(self.pending_windows), + setup: Some(self.setup), manager: manager.clone(), #[cfg(all(desktop, feature = "global-shortcut"))] global_shortcut_manager: global_shortcut_manager.clone(), @@ -1551,26 +1587,6 @@ impl Builder { app.manager.initialize_plugins(&app.handle())?; - let window_labels = self - .pending_windows - .iter() - .map(|p| p.label.clone()) - .collect::>(); - - for pending in self.pending_windows { - let pending = - app - .manager - .prepare_window(app.handle.clone(), pending, &window_labels, None)?; - let detached = app.runtime.as_ref().unwrap().create_window(pending)?; - let _window = app.manager.attach_window(app.handle(), detached); - } - - (self.setup)(&mut app).map_err(|e| crate::Error::Setup(e.into()))?; - - #[cfg(updater)] - app.run_updater(); - Ok(app) } @@ -1593,6 +1609,38 @@ unsafe impl HasRawDisplayHandle for App { } } +fn setup(app: &mut App) -> crate::Result<()> { + let pending_windows = app.pending_windows.take(); + if let Some(pending_windows) = pending_windows { + let window_labels = pending_windows + .iter() + .map(|p| p.label.clone()) + .collect::>(); + + for pending in pending_windows { + let pending = + app + .manager + .prepare_window(app.handle.clone(), pending, &window_labels, None)?; + let detached = if let RuntimeOrDispatch::RuntimeHandle(runtime) = app.handle().runtime() { + runtime.create_window(pending)? + } else { + // the AppHandle's runtime is always RuntimeOrDispatch::RuntimeHandle + unreachable!() + }; + let _window = app.manager.attach_window(app.handle(), detached); + } + } + + if let Some(setup) = app.setup.take() { + (setup)(app).map_err(|e| crate::Error::Setup(e.into()))?; + } + + #[cfg(updater)] + app.run_updater(); + Ok(()) +} + fn on_event_loop_event, RunEvent) + 'static>( app_handle: &AppHandle, event: RuntimeRunEvent, diff --git a/core/tauri/src/test/mod.rs b/core/tauri/src/test/mod.rs index 61aa59664..bf0bb33e0 100644 --- a/core/tauri/src/test/mod.rs +++ b/core/tauri/src/test/mod.rs @@ -13,10 +13,10 @@ use std::{borrow::Cow, sync::Arc}; #[cfg(shell_scope)] use crate::ShellScopeConfig; -use crate::{Manager, Pattern}; +use crate::{Manager, Pattern, WindowBuilder}; use tauri_utils::{ assets::{AssetKey, Assets, CspHash}, - config::{CliConfig, Config, PatternKind, TauriConfig}, + config::{CliConfig, Config, PatternKind, TauriConfig, WindowUrl}, }; pub struct NoopAsset { @@ -46,7 +46,7 @@ pub fn mock_context(assets: A) -> crate::Context { package: Default::default(), tauri: TauriConfig { pattern: PatternKind::Brownfield, - windows: vec![Default::default()], + windows: Vec::new(), cli: Some(CliConfig { description: None, long_description: None, @@ -86,9 +86,15 @@ pub fn mock_context(assets: A) -> crate::Context { } pub fn mock_app() -> crate::App { - crate::Builder::::new() + let app = crate::Builder::::new() .build(mock_context(noop_assets())) - .unwrap() + .unwrap(); + + WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into())) + .build() + .unwrap(); + + app } pub(crate) fn mock_invoke_context() -> crate::endpoints::InvokeContext {