diff --git a/.changes/weak-typing.md b/.changes/weak-typing.md new file mode 100644 index 000000000..69f721613 --- /dev/null +++ b/.changes/weak-typing.md @@ -0,0 +1,50 @@ +--- +"tauri": patch +"tauri-runtime": patch +"tauri-runtime-wry": patch +"tauri-macros": patch +"tauri-utils": patch +--- + +`Params` has been removed, along with all the associated types on it. Functions that previously accepted those +associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If +you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the +explicit type and let the compiler infer it instead. + +`tauri`: + +* See `Params` note +* If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a + simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition + of functions/items that previously took it. If you are using a custom runtime, you _may_ need to pass the runtime type + to these functions. +* If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all + methods that were previously taking the custom type now takes an `Into` or a `&str`. The types were already + required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change + affects you. + +`tauri-macros`: + +* (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when + the specified feature is enabled. + +`tauri-runtime`: + +* See `Params` note +* Removed `Params`, `MenuId`, `Tag`, `TagRef`. +* Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use. + * All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic. +* `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the + `Runtime` type directly +* `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly. +* (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`. + +`tauri-runtime-wry`: + +* See `Params` note +* update menu and runtime related types to the ones changed in `tauri-runtime`. + +`tauri-utils`: + +* `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into` to become trait object + safe. diff --git a/Cargo.toml b/Cargo.toml index 09744fe89..948f35d2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ members = [ "examples/helloworld/src-tauri", "examples/multiwindow/src-tauri", "examples/navigation/src-tauri", - "examples/params/src-tauri", "examples/splashscreen/src-tauri", "examples/state/src-tauri", "examples/sidecar/src-tauri", diff --git a/core/tauri-macros/src/lib.rs b/core/tauri-macros/src/lib.rs index 19acab544..01ac0a3f9 100644 --- a/core/tauri-macros/src/lib.rs +++ b/core/tauri-macros/src/lib.rs @@ -5,9 +5,10 @@ extern crate proc_macro; use crate::context::ContextItems; use proc_macro::TokenStream; -use syn::parse_macro_input; +use syn::{parse_macro_input, DeriveInput}; mod command; +mod runtime; #[macro_use] mod context; @@ -60,3 +61,16 @@ pub fn generate_context(items: TokenStream) -> TokenStream { let path = parse_macro_input!(items as ContextItems); context::generate_context(path).into() } + +/// Adds the default type for the last parameter (assumed to be runtime) for a specific feature. +/// +/// e.g. To default the runtime generic to type `crate::Wry` when the `wry` feature is enabled, the +/// syntax would look like `#[default_runtime(crate::Wry, wry)`. This is **always** set for the last +/// generic, so make sure the last generic is the runtime when using this macro. +#[doc(hidden)] +#[proc_macro_attribute] +pub fn default_runtime(attributes: TokenStream, input: TokenStream) -> TokenStream { + let attributes = parse_macro_input!(attributes as runtime::Attributes); + let input = parse_macro_input!(input as DeriveInput); + runtime::default_runtime(attributes, input).into() +} diff --git a/core/tauri-macros/src/runtime.rs b/core/tauri-macros/src/runtime.rs new file mode 100644 index 000000000..83213d30f --- /dev/null +++ b/core/tauri-macros/src/runtime.rs @@ -0,0 +1,62 @@ +// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::{parse_quote, DeriveInput, GenericParam, Ident, Token, Type, TypeParam}; + +/// The default runtime type to enable when the provided feature is enabled. +pub(crate) struct Attributes { + default_type: Type, + feature: Ident, +} + +impl Parse for Attributes { + fn parse(input: ParseStream) -> syn::Result { + let default_type = input.parse()?; + input.parse::()?; + Ok(Attributes { + default_type, + feature: input.parse()?, + }) + } +} + +pub(crate) fn default_runtime(attributes: Attributes, input: DeriveInput) -> TokenStream { + // create a new copy to manipulate for the wry feature flag + let mut wry = input.clone(); + let wry_runtime = wry + .generics + .params + .last_mut() + .expect("default_runtime requires the item to have at least 1 generic parameter"); + + // set the default value of the last generic parameter to the provided runtime type + match wry_runtime { + GenericParam::Type( + param @ TypeParam { + eq_token: None, + default: None, + .. + }, + ) => { + param.eq_token = Some(parse_quote!(=)); + param.default = Some(attributes.default_type); + } + _ => { + panic!("DefaultRuntime requires the last parameter to not have a default value") + } + }; + + let feature = attributes.feature.to_string(); + + quote!( + #[cfg(feature = #feature)] + #wry + + #[cfg(not(feature = #feature))] + #input + ) +} diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index bc89a38b1..4891ce7d6 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -13,8 +13,8 @@ use tauri_runtime::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}, DetachedWindow, PendingWindow, WindowEvent, }, - ClipboardManager, Dispatch, Error, GlobalShortcutManager, Icon, Params, Result, RunEvent, - RunIteration, Runtime, RuntimeHandle, UserAttentionType, + ClipboardManager, Dispatch, Error, GlobalShortcutManager, Icon, Result, RunEvent, RunIteration, + Runtime, RuntimeHandle, UserAttentionType, }; #[cfg(feature = "menu")] @@ -407,7 +407,7 @@ pub struct WindowBuilderWrapper { inner: WryWindowBuilder, center: bool, #[cfg(feature = "menu")] - menu: Menu, + menu: Menu, } // safe since `menu_items` are read only here @@ -454,7 +454,7 @@ impl WindowBuilder for WindowBuilderWrapper { } #[cfg(feature = "menu")] - fn menu(mut self, menu: Menu) -> Self { + fn menu(mut self, menu: Menu) -> Self { self.menu = convert_menu_id(Menu::new(), menu); self } @@ -898,10 +898,10 @@ impl Dispatch for WryDispatcher { // Creates a window by dispatching a message to the event loop. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. - fn create_window>( + fn create_window( &mut self, - pending: PendingWindow

, - ) -> Result> { + pending: PendingWindow, + ) -> Result> { let (tx, rx) = channel(); let label = pending.label.clone(); let context = self.context.clone(); @@ -1203,10 +1203,10 @@ impl RuntimeHandle for WryHandle { // Creates a window by dispatching a message to the event loop. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. - fn create_window>( + fn create_window( &self, - pending: PendingWindow

, - ) -> Result> { + pending: PendingWindow, + ) -> Result> { let (tx, rx) = channel(); let label = pending.label.clone(); let dispatcher_context = self.dispatcher_context.clone(); @@ -1306,10 +1306,7 @@ impl Runtime for Wry { self.clipboard_manager_handle.clone() } - fn create_window>( - &self, - pending: PendingWindow

, - ) -> Result> { + fn create_window(&self, pending: PendingWindow) -> Result> { let label = pending.label.clone(); let proxy = self.event_loop.create_proxy(); let webview = create_webview( @@ -1347,7 +1344,7 @@ impl Runtime for Wry { } #[cfg(feature = "system-tray")] - fn system_tray(&self, system_tray: SystemTray) -> Result { + fn system_tray(&self, system_tray: SystemTray) -> Result { let icon = system_tray .icon .expect("tray icon not set") @@ -1904,10 +1901,10 @@ fn center_window(window: &Window) -> Result<()> { } } -fn create_webview>( +fn create_webview( event_loop: &EventLoopWindowTarget, context: DispatcherContext, - pending: PendingWindow

, + pending: PendingWindow, ) -> Result { #[allow(unused_mut)] let PendingWindow { @@ -1983,7 +1980,7 @@ fn create_webview>( .map_err(|e| Error::CreateWebview(Box::new(e)))?; Ok(WebviewWrapper { - label: format!("{}", label), + label, inner: webview, #[cfg(feature = "menu")] menu_items, @@ -1993,10 +1990,10 @@ fn create_webview>( } /// Create a wry rpc handler from a tauri rpc handler. -fn create_rpc_handler>( +fn create_rpc_handler( context: DispatcherContext, - label: P::Label, - handler: WebviewRpcHandler

, + label: String, + handler: WebviewRpcHandler, ) -> Box Option + 'static> { Box::new(move |window, request| { handler( @@ -2014,10 +2011,10 @@ fn create_rpc_handler>( } /// Create a wry file drop handler from a tauri file drop handler. -fn create_file_drop_handler>( +fn create_file_drop_handler( context: DispatcherContext, - label: P::Label, - handler: FileDropHandler

, + label: String, + handler: FileDropHandler, ) -> Box bool + 'static> { Box::new(move |window, event| { handler( diff --git a/core/tauri-runtime-wry/src/menu.rs b/core/tauri-runtime-wry/src/menu.rs index 597543db8..1e5a2924f 100644 --- a/core/tauri-runtime-wry/src/menu.rs +++ b/core/tauri-runtime-wry/src/menu.rs @@ -8,7 +8,7 @@ pub use tauri_runtime::{ SystemTrayMenuEntry, SystemTrayMenuItem, TrayHandle, }, window::MenuEvent, - Icon, MenuId, SystemTrayEvent, + Icon, SystemTrayEvent, }; pub use wry::application::{ event::TrayEvent, @@ -31,6 +31,9 @@ pub use wry::application::platform::macos::{ #[cfg(feature = "system-tray")] use crate::{Error, Message, Result, TrayMessage}; +#[cfg(feature = "menu")] +use tauri_runtime::menu::MenuHash; + use uuid::Uuid; use std::{ @@ -145,12 +148,12 @@ impl From for NativeImageWrapper { pub struct MenuItemAttributesWrapper<'a>(pub WryMenuItemAttributes<'a>); -impl<'a, I: MenuId> From<&'a CustomMenuItem> for MenuItemAttributesWrapper<'a> { - fn from(item: &'a CustomMenuItem) -> Self { +impl<'a> From<&'a CustomMenuItem> for MenuItemAttributesWrapper<'a> { + fn from(item: &'a CustomMenuItem) -> Self { let mut attributes = WryMenuItemAttributes::new(&item.title) .with_enabled(item.enabled) .with_selected(item.selected) - .with_id(WryMenuId(item.id_value())); + .with_id(WryMenuId(item.id)); if let Some(accelerator) = item.keyboard_accelerator.as_ref() { attributes = attributes.with_accelerators(&accelerator.parse().expect("invalid accelerator")); } @@ -195,11 +198,11 @@ impl From for MenuItemWrapper { } #[cfg(feature = "menu")] -pub fn convert_menu_id(mut new_menu: Menu, menu: Menu) -> Menu { +pub fn convert_menu_id(mut new_menu: Menu, menu: Menu) -> Menu { for item in menu.items { match item { MenuEntry::CustomItem(c) => { - let mut item = CustomMenuItem::new(c.id_value(), c.title); + let mut item = CustomMenuItem::new(c.id_str, c.title); #[cfg(target_os = "macos")] if let Some(native_image) = c.native_image { item = item.native_image(native_image); @@ -229,8 +232,8 @@ pub fn convert_menu_id(mut new_menu: Menu, menu: Menu) -> Men #[cfg(feature = "menu")] pub fn to_wry_menu( - custom_menu_items: &mut HashMap, - menu: Menu, + custom_menu_items: &mut HashMap, + menu: Menu, ) -> MenuBar { let mut wry_menu = MenuBar::new(); for item in menu.items { @@ -262,9 +265,9 @@ pub fn to_wry_menu( } #[cfg(feature = "system-tray")] -pub fn to_wry_context_menu( - custom_menu_items: &mut HashMap, - menu: SystemTrayMenu, +pub fn to_wry_context_menu( + custom_menu_items: &mut HashMap, + menu: SystemTrayMenu, ) -> WryContextMenu { let mut tray_menu = WryContextMenu::new(); for item in menu.items { @@ -272,12 +275,11 @@ pub fn to_wry_context_menu( SystemTrayMenuEntry::CustomItem(c) => { #[allow(unused_mut)] let mut item = tray_menu.add_item(MenuItemAttributesWrapper::from(&c).0); - let id = c.id_value(); #[cfg(target_os = "macos")] if let Some(native_image) = c.native_image { item.set_native_image(NativeImageWrapper::from(native_image).0); } - custom_menu_items.insert(id, item); + custom_menu_items.insert(c.id, item); } SystemTrayMenuEntry::NativeItem(i) => { tray_menu.add_native_item(MenuItemWrapper::from(i).0); diff --git a/core/tauri-runtime/src/lib.rs b/core/tauri-runtime/src/lib.rs index 2ea09a761..fe6ab6b2c 100644 --- a/core/tauri-runtime/src/lib.rs +++ b/core/tauri-runtime/src/lib.rs @@ -6,11 +6,10 @@ #![cfg_attr(doc_cfg, feature(doc_cfg))] -use std::{fmt::Debug, hash::Hash, path::PathBuf, sync::mpsc::Sender}; - -use serde::{Deserialize, Serialize}; -use tauri_utils::assets::Assets; +use serde::Deserialize; +use std::{fmt::Debug, path::PathBuf, sync::mpsc::Sender}; use uuid::Uuid; + #[cfg(windows)] use winapi::shared::windef::HWND; @@ -20,32 +19,25 @@ use winapi::shared::windef::HWND; pub mod menu; /// Types useful for interacting with a user's monitors. pub mod monitor; -pub mod tag; pub mod webview; pub mod window; use monitor::Monitor; -use tag::Tag; use webview::WindowBuilder; use window::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, DetachedWindow, PendingWindow, WindowEvent, }; -/// A type that can be derived into a menu id. -pub trait MenuId: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {} - -impl MenuId for T where T: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {} - #[cfg(feature = "system-tray")] #[non_exhaustive] -pub struct SystemTray { +pub struct SystemTray { pub icon: Option, - pub menu: Option>, + pub menu: Option, } #[cfg(feature = "system-tray")] -impl Default for SystemTray { +impl Default for SystemTray { fn default() -> Self { Self { icon: None, @@ -55,13 +47,13 @@ impl Default for SystemTray { } #[cfg(feature = "system-tray")] -impl SystemTray { +impl SystemTray { /// Creates a new system tray that only renders an icon. pub fn new() -> Self { Default::default() } - pub fn menu(&self) -> Option<&menu::SystemTrayMenu> { + pub fn menu(&self) -> Option<&menu::SystemTrayMenu> { self.menu.as_ref() } @@ -72,7 +64,7 @@ impl SystemTray { } /// Sets the menu to show when the system tray is right clicked. - pub fn with_menu(mut self, menu: menu::SystemTrayMenu) -> Self { + pub fn with_menu(mut self, menu: menu::SystemTrayMenu) -> Self { self.menu.replace(menu); self } @@ -126,32 +118,6 @@ pub enum Error { /// Result type. pub type Result = std::result::Result; -#[doc(hidden)] -pub mod private { - pub trait ParamsBase {} -} - -/// Types associated with the running Tauri application. -pub trait Params: private::ParamsBase + 'static { - /// The event type used to create and listen to events. - type Event: Tag; - - /// The type used to determine the name of windows. - type Label: Tag; - - /// The type used to determine window menu ids. - type MenuId: MenuId; - - /// The type used to determine system tray menu ids. - type SystemTrayMenuId: MenuId; - - /// Assets that Tauri should serve from itself. - type Assets: Assets; - - /// The underlying webview runtime used by the Tauri application. - type Runtime: Runtime; -} - /// A icon definition. #[derive(Debug, Clone)] #[non_exhaustive] @@ -231,10 +197,10 @@ pub struct RunIteration { pub trait RuntimeHandle: Send + Sized + Clone + 'static { type Runtime: Runtime; /// Create a new webview window. - fn create_window>( + fn create_window( &self, - pending: PendingWindow

, - ) -> crate::Result>; + pending: PendingWindow, + ) -> crate::Result>; #[cfg(all(windows, feature = "system-tray"))] #[cfg_attr(doc_cfg, doc(cfg(all(windows, feature = "system-tray"))))] @@ -326,15 +292,12 @@ pub trait Runtime: Sized + 'static { fn clipboard_manager(&self) -> Self::ClipboardManager; /// Create a new webview window. - fn create_window>( - &self, - pending: PendingWindow

, - ) -> crate::Result>; + fn create_window(&self, pending: PendingWindow) -> crate::Result>; /// Adds the icon to the system tray with the specified menu items. #[cfg(feature = "system-tray")] #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] - fn system_tray(&self, system_tray: SystemTray) -> crate::Result; + fn system_tray(&self, system_tray: SystemTray) -> crate::Result; /// Registers a system tray event handler. #[cfg(feature = "system-tray")] @@ -449,10 +412,10 @@ pub trait Dispatch: Clone + Send + Sized + 'static { fn request_user_attention(&self, request_type: Option) -> crate::Result<()>; /// Create a new webview window. - fn create_window>( + fn create_window( &mut self, - pending: PendingWindow

, - ) -> crate::Result>; + pending: PendingWindow, + ) -> crate::Result>; /// Updates the window resizable flag. fn set_resizable(&self, resizable: bool) -> crate::Result<()>; diff --git a/core/tauri-runtime/src/menu.rs b/core/tauri-runtime/src/menu.rs index 3eb0fa019..cbbc0723c 100644 --- a/core/tauri-runtime/src/menu.rs +++ b/core/tauri-runtime/src/menu.rs @@ -2,9 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::{collections::hash_map::DefaultHasher, hash::Hasher}; +use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, +}; -use super::MenuId; +pub type MenuHash = u16; +pub type MenuId = String; +pub type MenuIdRef<'a> = &'a str; /// Named images defined by the system. #[cfg(target_os = "macos")] @@ -148,21 +153,21 @@ pub trait TrayHandle { /// A window menu. #[derive(Debug, Clone)] #[non_exhaustive] -pub struct Menu { - pub items: Vec>, +pub struct Menu { + pub items: Vec, } #[derive(Debug, Clone)] #[non_exhaustive] -pub struct Submenu { +pub struct Submenu { pub title: String, pub enabled: bool, - pub inner: Menu, + pub inner: Menu, } -impl Submenu { +impl Submenu { /// Creates a new submenu with the given title and menu items. - pub fn new>(title: S, menu: Menu) -> Self { + pub fn new>(title: S, menu: Menu) -> Self { Self { title: title.into(), enabled: true, @@ -171,20 +176,20 @@ impl Submenu { } } -impl Default for Menu { +impl Default for Menu { fn default() -> Self { Self { items: Vec::new() } } } -impl Menu { +impl Menu { /// Creates a new window menu. pub fn new() -> Self { Default::default() } /// Adds the custom menu item to the menu. - pub fn add_item(mut self, item: CustomMenuItem) -> Self { + pub fn add_item(mut self, item: CustomMenuItem) -> Self { self.items.push(MenuEntry::CustomItem(item)); self } @@ -196,7 +201,7 @@ impl Menu { } /// Adds an entry with submenu. - pub fn add_submenu(mut self, submenu: Submenu) -> Self { + pub fn add_submenu(mut self, submenu: Submenu) -> Self { self.items.push(MenuEntry::Submenu(submenu)); self } @@ -205,8 +210,9 @@ impl Menu { /// A custom menu item. #[derive(Debug, Clone)] #[non_exhaustive] -pub struct CustomMenuItem { - pub id: I, +pub struct CustomMenuItem { + pub id: MenuHash, + pub id_str: MenuId, pub title: String, pub keyboard_accelerator: Option, pub enabled: bool, @@ -215,11 +221,13 @@ pub struct CustomMenuItem { pub native_image: Option, } -impl CustomMenuItem { +impl CustomMenuItem { /// Create new custom menu item. - pub fn new>(id: I, title: T) -> Self { + pub fn new, T: Into>(id: I, title: T) -> Self { + let id_str = id.into(); Self { - id, + id: Self::hash(&id_str), + id_str, title: title.into(), keyboard_accelerator: None, enabled: true, @@ -255,22 +263,21 @@ impl CustomMenuItem { self } - #[doc(hidden)] - pub fn id_value(&self) -> u16 { - let mut s = DefaultHasher::new(); - self.id.hash(&mut s); - s.finish() as u16 + fn hash(id: &str) -> MenuHash { + let mut hasher = DefaultHasher::new(); + id.hash(&mut hasher); + hasher.finish() as MenuHash } } /// A system tray menu. #[derive(Debug, Clone)] #[non_exhaustive] -pub struct SystemTrayMenu { - pub items: Vec>, +pub struct SystemTrayMenu { + pub items: Vec, } -impl Default for SystemTrayMenu { +impl Default for SystemTrayMenu { fn default() -> Self { Self { items: Vec::new() } } @@ -278,15 +285,15 @@ impl Default for SystemTrayMenu { #[derive(Debug, Clone)] #[non_exhaustive] -pub struct SystemTraySubmenu { +pub struct SystemTraySubmenu { pub title: String, pub enabled: bool, - pub inner: SystemTrayMenu, + pub inner: SystemTrayMenu, } -impl SystemTraySubmenu { +impl SystemTraySubmenu { /// Creates a new submenu with the given title and menu items. - pub fn new>(title: S, menu: SystemTrayMenu) -> Self { + pub fn new>(title: S, menu: SystemTrayMenu) -> Self { Self { title: title.into(), enabled: true, @@ -295,14 +302,14 @@ impl SystemTraySubmenu { } } -impl SystemTrayMenu { +impl SystemTrayMenu { /// Creates a new system tray menu. pub fn new() -> Self { Default::default() } /// Adds the custom menu item to the system tray menu. - pub fn add_item(mut self, item: CustomMenuItem) -> Self { + pub fn add_item(mut self, item: CustomMenuItem) -> Self { self.items.push(SystemTrayMenuEntry::CustomItem(item)); self } @@ -314,7 +321,7 @@ impl SystemTrayMenu { } /// Adds an entry with submenu. - pub fn add_submenu(mut self, submenu: SystemTraySubmenu) -> Self { + pub fn add_submenu(mut self, submenu: SystemTraySubmenu) -> Self { self.items.push(SystemTrayMenuEntry::Submenu(submenu)); self } @@ -322,13 +329,13 @@ impl SystemTrayMenu { /// An entry on the system tray menu. #[derive(Debug, Clone)] -pub enum SystemTrayMenuEntry { +pub enum SystemTrayMenuEntry { /// A custom item. - CustomItem(CustomMenuItem), + CustomItem(CustomMenuItem), /// A native item. NativeItem(SystemTrayMenuItem), /// An entry with submenu. - Submenu(SystemTraySubmenu), + Submenu(SystemTraySubmenu), } /// System tray menu item. @@ -341,13 +348,13 @@ pub enum SystemTrayMenuItem { /// An entry on the system tray menu. #[derive(Debug, Clone)] -pub enum MenuEntry { +pub enum MenuEntry { /// A custom item. - CustomItem(CustomMenuItem), + CustomItem(CustomMenuItem), /// A native item. NativeItem(MenuItem), /// An entry with submenu. - Submenu(Submenu), + Submenu(Submenu), } /// A menu item, bound to a pre-defined action or `Custom` emit an event. Note that status bar only diff --git a/core/tauri-runtime/src/tag.rs b/core/tauri-runtime/src/tag.rs deleted file mode 100644 index b55a2118b..000000000 --- a/core/tauri-runtime/src/tag.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! Working with "string-able" types. - -use std::{ - fmt::{Debug, Display}, - hash::Hash, - str::FromStr, -}; - -/// Represents a "string-able" type. -/// -/// The type is required to be able to be represented as a string [`Display`], along with knowing -/// how to be parsed from the string representation [`FromStr`]. To make sure things stay easy to -/// debug, both the [`Tag`] and the [`FromStr::Err`] must implement [`Debug`]. -/// -/// [`Clone`], [`Hash`], and [`Eq`] are needed so that it can represent un-hashable types. -/// -/// [`Send`] and [`Sync`] and `'static` are current requirements due to how it is sometimes sent -/// across thread boundaries, although some of those constraints may relax in the future. -/// -/// The simplest type that fits all these requirements is a [`String`](std::string::String). -/// -/// # Handling Errors -/// -/// Because we leave it up to the type to implement [`FromStr`], if an error is returned during -/// parsing then Tauri will [`std::panic!`] with the string it failed to parse. -/// -/// To avoid Tauri panicking during the application runtime, have your type be able to handle -/// unknown events and never return an error in [`FromStr`]. Then it will be up to your own code -/// to handle the unknown event. -/// -/// # Example -/// -/// ``` -/// use std::fmt; -/// use std::str::FromStr; -/// -/// #[derive(Debug, Clone, Hash, Eq, PartialEq)] -/// enum Event { -/// Foo, -/// Bar, -/// Unknown(String), -/// } -/// -/// impl fmt::Display for Event { -/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// f.write_str(match self { -/// Self::Foo => "foo", -/// Self::Bar => "bar", -/// Self::Unknown(s) => &s -/// }) -/// } -/// } -/// -/// impl FromStr for Event { -/// type Err = std::convert::Infallible; -/// -/// fn from_str(s: &str) -> Result { -/// Ok(match s { -/// "foo" => Self::Foo, -/// "bar" => Self::Bar, -/// other => Self::Unknown(other.to_string()) -/// }) -/// } -/// } -/// -/// // safe to unwrap because we know it's infallible due to our FromStr implementation. -/// let event: Event = "tauri://file-drop".parse().unwrap(); -/// -/// // show that this event type can be represented as a Tag, a requirement for using it in Tauri. -/// fn is_file_drop(tag: impl tauri_runtime::tag::Tag) { -/// assert_eq!("tauri://file-drop", tag.to_string()); -/// } -/// -/// is_file_drop(event); -/// ``` -pub trait Tag: Hash + Eq + FromStr + Display + Debug + Clone + Send + Sync + 'static {} - -/// Automatically implement [`Tag`] for all types that fit the requirements. -impl Tag for T where - T: Hash + Eq + FromStr + Display + Debug + Clone + Send + Sync + 'static -{ -} - -/// A reference to a [`Tag`]. -/// -/// * [`Display`] so that we can still convert this tag to a JavaScript string. -/// * [`ToOwned`] to make sure we can clone it into the owned tag in specific cases. -/// * [`PartialEq`] so that we can compare refs to the owned tags easily. -/// * [`Hash`] + [`Eq`] because we want to be able to use a ref as a key to internal hashmaps. -pub trait TagRef: Display + ToOwned + PartialEq + Eq + Hash -where - T: std::borrow::Borrow, -{ -} - -/// Automatically implement [`TagRef`] for all types that fit the requirements. -impl TagRef for R -where - T: std::borrow::Borrow, - R: Display + ToOwned + PartialEq + Eq + Hash + ?Sized, -{ -} - -/// Private helper to turn [`Tag`] related things into JavaScript, safely. -/// -/// The main concern is string escaping, so we rely on [`serde_json`] to handle all serialization -/// of the [`Tag`] as a string. We do this instead of requiring [`serde::Serialize`] on [`Tag`] -/// because it really represents a string, not any serializable data structure. -/// -/// We don't want downstream users to implement this trait so that [`Tag`]s cannot be turned into -/// invalid JavaScript - regardless of their content. -pub trait ToJsString { - fn to_js_string(&self) -> crate::Result; -} - -impl ToJsString for D { - /// Turn any [`Tag`] into the JavaScript representation of a string. - fn to_js_string(&self) -> crate::Result { - Ok(serde_json::to_string(&self.to_string())?) - } -} - -/// Turn any collection of [`Tag`]s into a JavaScript array of strings. -pub fn tags_to_javascript_array(tags: &[impl Tag]) -> crate::Result { - let tags: Vec = tags.iter().map(ToString::to_string).collect(); - Ok(serde_json::to_string(&tags)?) -} diff --git a/core/tauri-runtime/src/webview.rs b/core/tauri-runtime/src/webview.rs index d40be787b..9b08c2321 100644 --- a/core/tauri-runtime/src/webview.rs +++ b/core/tauri-runtime/src/webview.rs @@ -7,7 +7,7 @@ use crate::{window::DetachedWindow, Icon}; #[cfg(feature = "menu")] -use crate::{menu::Menu, MenuId}; +use crate::menu::Menu; use serde::Deserialize; use serde_json::Value as JsonValue; @@ -109,7 +109,7 @@ pub trait WindowBuilder: WindowBuilderBase { /// Sets the menu for the window. #[cfg(feature = "menu")] #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] - fn menu(self, menu: Menu) -> Self; + fn menu(self, menu: Menu) -> Self; /// Show window in the center of the screen. fn center(self) -> Self; @@ -216,11 +216,11 @@ pub enum FileDropEvent { } /// Rpc handler. -pub type WebviewRpcHandler

= Box, RpcRequest) + Send>; +pub type WebviewRpcHandler = Box, RpcRequest) + Send>; /// File drop handler callback /// Return `true` in the callback to block the OS' default behavior of handling a file drop. -pub type FileDropHandler

= Box) -> bool + Send>; +pub type FileDropHandler = Box) -> bool + Send>; #[derive(Deserialize)] pub struct InvokePayload { diff --git a/core/tauri-runtime/src/window.rs b/core/tauri-runtime/src/window.rs index 8a1c0d825..9a37bf114 100644 --- a/core/tauri-runtime/src/window.rs +++ b/core/tauri-runtime/src/window.rs @@ -6,7 +6,7 @@ use crate::{ webview::{FileDropHandler, WebviewAttributes, WebviewRpcHandler}, - Dispatch, Params, Runtime, WindowBuilder, + Dispatch, Runtime, WindowBuilder, }; use serde::Serialize; use tauri_utils::config::WindowConfig; @@ -55,37 +55,37 @@ pub struct MenuEvent { } /// A webview window that has yet to be built. -pub struct PendingWindow { +pub struct PendingWindow { /// The label that the window will be named. - pub label: P::Label, + pub label: String, /// The [`WindowBuilder`] that the window will be created with. - pub window_builder: <::Dispatcher as Dispatch>::WindowBuilder, + pub window_builder: ::WindowBuilder, /// The [`WebviewAttributes`] that the webview will be created with. pub webview_attributes: WebviewAttributes, /// How to handle RPC calls on the webview window. - pub rpc_handler: Option>, + pub rpc_handler: Option>, /// How to handle a file dropping onto the webview window. - pub file_drop_handler: Option>, + pub file_drop_handler: Option>, /// The resolved URL to load on the webview. pub url: String, } -impl PendingWindow

{ +impl PendingWindow { /// Create a new [`PendingWindow`] with a label and starting url. pub fn new( - window_builder: <::Dispatcher as Dispatch>::WindowBuilder, + window_builder: ::WindowBuilder, webview_attributes: WebviewAttributes, - label: P::Label, + label: impl Into, ) -> Self { Self { window_builder, webview_attributes, - label, + label: label.into(), rpc_handler: None, file_drop_handler: None, url: "tauri://localhost".to_string(), @@ -96,15 +96,12 @@ impl PendingWindow

{ pub fn with_config( window_config: WindowConfig, webview_attributes: WebviewAttributes, - label: P::Label, + label: impl Into, ) -> Self { Self { - window_builder: - <<::Dispatcher as Dispatch>::WindowBuilder>::with_config( - window_config, - ), + window_builder: <::WindowBuilder>::with_config(window_config), webview_attributes, - label, + label: label.into(), rpc_handler: None, file_drop_handler: None, url: "tauri://localhost".to_string(), @@ -113,15 +110,15 @@ impl PendingWindow

{ } /// A webview window that is not yet managed by Tauri. -pub struct DetachedWindow { +pub struct DetachedWindow { /// Name of the window - pub label: P::Label, + pub label: String, /// The [`Dispatch`](crate::Dispatch) associated with the window. - pub dispatcher: ::Dispatcher, + pub dispatcher: R::Dispatcher, } -impl Clone for DetachedWindow

{ +impl Clone for DetachedWindow { fn clone(&self) -> Self { Self { label: self.label.clone(), @@ -130,15 +127,15 @@ impl Clone for DetachedWindow

{ } } -impl Hash for DetachedWindow

{ +impl Hash for DetachedWindow { /// Only use the [`DetachedWindow`]'s label to represent its hash. fn hash(&self, state: &mut H) { self.label.hash(state) } } -impl Eq for DetachedWindow

{} -impl PartialEq for DetachedWindow

{ +impl Eq for DetachedWindow {} +impl PartialEq for DetachedWindow { /// Only use the [`DetachedWindow`]'s label to compare equality. fn eq(&self, other: &Self) -> bool { self.label.eq(&other.label) diff --git a/core/tauri-utils/src/assets.rs b/core/tauri-utils/src/assets.rs index 24b14f1c4..2f352a746 100644 --- a/core/tauri-utils/src/assets.rs +++ b/core/tauri-utils/src/assets.rs @@ -76,7 +76,7 @@ impl> From

for AssetKey { /// Represents a container of file assets that are retrievable during runtime. pub trait Assets: Send + Sync + 'static { /// Get the content of the passed [`AssetKey`]. - fn get>(&self, key: Key) -> Option>; + fn get(&self, key: &AssetKey) -> Option>; } /// [`Assets`] implementation that only contains compile-time compressed and embedded assets. @@ -92,10 +92,10 @@ impl EmbeddedAssets { } impl Assets for EmbeddedAssets { - fn get>(&self, key: Key) -> Option> { + fn get(&self, key: &AssetKey) -> Option> { self .0 - .get(key.into().as_ref()) + .get(key.as_ref()) .copied() .map(zstd::decode_all) .and_then(Result::ok) diff --git a/core/tauri/src/app.rs b/core/tauri/src/app.rs index 6e1285ee5..b25bd2755 100644 --- a/core/tauri/src/app.rs +++ b/core/tauri/src/app.rs @@ -11,18 +11,18 @@ use crate::{ api::config::{Config, WindowUrl}, command::{CommandArg, CommandItem}, hooks::{InvokeHandler, OnPageLoad, PageLoadPayload, SetupHook}, - manager::{Args, WindowManager}, + manager::WindowManager, plugin::{Plugin, PluginStore}, runtime::{ - tag::Tag, webview::{CustomProtocol, WebviewAttributes, WindowBuilder}, window::{PendingWindow, WindowEvent}, - Dispatch, MenuId, Params, RunEvent, Runtime, + Dispatch, RunEvent, Runtime, }, sealed::{ManagerBase, RuntimeOrDispatch}, Context, Invoke, InvokeError, Manager, StateManager, Window, }; +use tauri_macros::default_runtime; use tauri_utils::PackageInfo; use std::{ @@ -32,7 +32,7 @@ use std::{ }; #[cfg(feature = "menu")] -use crate::runtime::menu::Menu; +use crate::runtime::menu::{Menu, MenuId, MenuIdRef}; #[cfg(all(windows, feature = "system-tray"))] use crate::runtime::RuntimeHandle; @@ -43,11 +43,10 @@ use crate::runtime::{Icon, SystemTrayEvent as RuntimeSystemTrayEvent}; use crate::updater; #[cfg(feature = "menu")] -pub(crate) type GlobalMenuEventListener

= Box) + Send + Sync>; -pub(crate) type GlobalWindowEventListener

= Box) + Send + Sync>; +pub(crate) type GlobalMenuEventListener = Box) + Send + Sync>; +pub(crate) type GlobalWindowEventListener = Box) + Send + Sync>; #[cfg(feature = "system-tray")] -type SystemTrayEventListener

= - Box, tray::SystemTrayEvent<

::SystemTrayMenuId>) + Send + Sync>; +type SystemTrayEventListener = Box, tray::SystemTrayEvent) + Send + Sync>; /// Api exposed on the `CloseRequested` event. pub struct CloseRequestApi(Sender); @@ -61,60 +60,58 @@ impl CloseRequestApi { /// An application event, triggered from the event loop. #[non_exhaustive] -pub enum Event { +pub enum Event { /// Event loop is exiting. Exit, /// Window close was requested by the user. #[non_exhaustive] CloseRequested { /// The window label. - label: P::Label, + label: String, /// Event API. api: CloseRequestApi, }, /// Window closed. - WindowClosed(P::Label), + WindowClosed(String), } -crate::manager::default_args! { - /// A menu event that was triggered on a window. - #[cfg(feature = "menu")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] - pub struct WindowMenuEvent { - pub(crate) menu_item_id: P::MenuId, - pub(crate) window: Window

, - } +/// A menu event that was triggered on a window. +#[cfg(feature = "menu")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] +#[default_runtime(crate::Wry, wry)] +pub struct WindowMenuEvent { + pub(crate) menu_item_id: MenuId, + pub(crate) window: Window, } #[cfg(feature = "menu")] -impl WindowMenuEvent

{ +impl WindowMenuEvent { /// The menu item id. - pub fn menu_item_id(&self) -> &P::MenuId { + pub fn menu_item_id(&self) -> MenuIdRef<'_> { &self.menu_item_id } /// The window that the menu belongs to. - pub fn window(&self) -> &Window

{ + pub fn window(&self) -> &Window { &self.window } } -crate::manager::default_args! { - /// A window event that was triggered on the specified window. - pub struct GlobalWindowEvent { - pub(crate) event: WindowEvent, - pub(crate) window: Window

, - } +/// A window event that was triggered on the specified window. +#[default_runtime(crate::Wry, wry)] +pub struct GlobalWindowEvent { + pub(crate) event: WindowEvent, + pub(crate) window: Window, } -impl GlobalWindowEvent

{ - /// The eventpayload. +impl GlobalWindowEvent { + /// The event payload. pub fn event(&self) -> &WindowEvent { &self.event } /// The window that the menu belongs to. - pub fn window(&self) -> &Window

{ + pub fn window(&self) -> &Window { &self.window } } @@ -138,21 +135,20 @@ impl PathResolver { } } -crate::manager::default_args! { - /// A handle to the currently running application. - /// - /// This type implements [`Manager`] which allows for manipulation of global application items. - pub struct AppHandle { - runtime_handle: ::Handle, - manager: WindowManager

, - global_shortcut_manager: ::GlobalShortcutManager, - clipboard_manager: ::ClipboardManager, - #[cfg(feature = "system-tray")] - tray_handle: Option>, - } +/// A handle to the currently running application. +/// +/// This type implements [`Manager`] which allows for manipulation of global application items. +#[default_runtime(crate::Wry, wry)] +pub struct AppHandle { + runtime_handle: R::Handle, + manager: WindowManager, + global_shortcut_manager: R::GlobalShortcutManager, + clipboard_manager: R::ClipboardManager, + #[cfg(feature = "system-tray")] + tray_handle: Option>, } -impl Clone for AppHandle

{ +impl Clone for AppHandle { fn clone(&self) -> Self { Self { runtime_handle: self.runtime_handle.clone(), @@ -165,14 +161,14 @@ impl Clone for AppHandle

{ } } -impl<'de, P: Params> CommandArg<'de, P> for AppHandle

{ +impl<'de, R: Runtime> CommandArg<'de, R> for AppHandle { /// Grabs the [`Window`] from the [`CommandItem`] and returns the associated [`AppHandle`]. This will never fail. - fn from_command(command: CommandItem<'de, P>) -> Result { + fn from_command(command: CommandItem<'de, R>) -> Result { Ok(command.message.window().app_handle) } } -impl AppHandle

{ +impl AppHandle { /// Removes the system tray. #[cfg(all(windows, feature = "system-tray"))] #[cfg_attr(doc_cfg, doc(cfg(all(windows, feature = "system-tray"))))] @@ -181,67 +177,66 @@ impl AppHandle

{ } } -impl Manager

for AppHandle

{} -impl ManagerBase

for AppHandle

{ - fn manager(&self) -> &WindowManager

{ +impl Manager for AppHandle {} +impl ManagerBase for AppHandle { + fn manager(&self) -> &WindowManager { &self.manager } - fn runtime(&self) -> RuntimeOrDispatch<'_, P> { + fn runtime(&self) -> RuntimeOrDispatch<'_, R> { RuntimeOrDispatch::RuntimeHandle(self.runtime_handle.clone()) } - fn app_handle(&self) -> AppHandle

{ + fn app_handle(&self) -> AppHandle { self.clone() } } -crate::manager::default_args! { - /// The instance of the currently running application. - /// - /// This type implements [`Manager`] which allows for manipulation of global application items. - pub struct App { - runtime: Option, - manager: WindowManager

, - global_shortcut_manager: ::GlobalShortcutManager, - clipboard_manager: ::ClipboardManager, - #[cfg(feature = "system-tray")] - tray_handle: Option>, - handle: AppHandle

, - } +/// The instance of the currently running application. +/// +/// This type implements [`Manager`] which allows for manipulation of global application items. +#[default_runtime(crate::Wry, wry)] +pub struct App { + runtime: Option, + manager: WindowManager, + global_shortcut_manager: R::GlobalShortcutManager, + clipboard_manager: R::ClipboardManager, + #[cfg(feature = "system-tray")] + tray_handle: Option>, + handle: AppHandle, } -impl Manager

for App

{} -impl ManagerBase

for App

{ - fn manager(&self) -> &WindowManager

{ +impl Manager for App {} +impl ManagerBase for App { + fn manager(&self) -> &WindowManager { &self.manager } - fn runtime(&self) -> RuntimeOrDispatch<'_, P> { + fn runtime(&self) -> RuntimeOrDispatch<'_, R> { RuntimeOrDispatch::Runtime(self.runtime.as_ref().unwrap()) } - fn app_handle(&self) -> AppHandle

{ + fn app_handle(&self) -> AppHandle { self.handle() } } macro_rules! shared_app_impl { ($app: ty) => { - impl $app { + impl $app { /// Creates a new webview window. - pub fn create_window(&self, label: P::Label, url: WindowUrl, setup: F) -> crate::Result<()> + pub fn create_window(&self, label: String, url: WindowUrl, setup: F) -> crate::Result<()> where F: FnOnce( - <::Dispatcher as Dispatch>::WindowBuilder, + ::WindowBuilder, WebviewAttributes, ) -> ( - <::Dispatcher as Dispatch>::WindowBuilder, + ::WindowBuilder, WebviewAttributes, ), { let (window_builder, webview_attributes) = setup( - <::Dispatcher as Dispatch>::WindowBuilder::new(), + ::WindowBuilder::new(), WebviewAttributes::new(url), ); self.create_new_window(PendingWindow::new( @@ -255,7 +250,7 @@ macro_rules! shared_app_impl { #[cfg(feature = "system-tray")] #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] /// Gets a handle handle to the system tray. - pub fn tray_handle(&self) -> tray::SystemTrayHandle

{ + pub fn tray_handle(&self) -> tray::SystemTrayHandle { self .tray_handle .clone() @@ -271,12 +266,12 @@ macro_rules! shared_app_impl { } /// Gets a copy of the global shortcut manager instance. - pub fn global_shortcut_manager(&self) -> ::GlobalShortcutManager { + pub fn global_shortcut_manager(&self) -> R::GlobalShortcutManager { self.global_shortcut_manager.clone() } /// Gets a copy of the clipboard manager instance. - pub fn clipboard_manager(&self) -> ::ClipboardManager { + pub fn clipboard_manager(&self) -> R::ClipboardManager { self.clipboard_manager.clone() } @@ -293,17 +288,17 @@ macro_rules! shared_app_impl { }; } -shared_app_impl!(App

); -shared_app_impl!(AppHandle

); +shared_app_impl!(App); +shared_app_impl!(AppHandle); -impl App

{ +impl App { /// Gets a handle to the application instance. - pub fn handle(&self) -> AppHandle

{ + pub fn handle(&self) -> AppHandle { self.handle.clone() } /// Runs the application. - pub fn run, Event

) + 'static>(mut self, callback: F) { + pub fn run, Event) + 'static>(mut self, callback: F) { let app_handle = self.handle(); let manager = self.manager.clone(); self.runtime.take().unwrap().run(move |event| match event { @@ -369,9 +364,9 @@ impl App

{ } #[cfg(feature = "updater")] -impl App

{ +impl App { /// Runs the updater hook with built-in dialog. - fn run_updater_dialog(&self, window: Window

) { + fn run_updater_dialog(&self, window: Window) { let updater_config = self.manager.config().tauri.updater.clone(); let package_info = self.manager.package_info().clone(); crate::async_runtime::spawn(async move { @@ -380,12 +375,12 @@ impl App

{ } /// Listen updater events when dialog are disabled. - fn listen_updater_events(&self, window: Window

) { + fn listen_updater_events(&self, window: Window) { let updater_config = self.manager.config().tauri.updater.clone(); updater::listener(updater_config, self.manager.package_info().clone(), &window); } - fn run_updater(&self, main_window: Option>) { + fn run_updater(&self, main_window: Option>) { if let Some(main_window) = main_window { let event_window = main_window.clone(); let updater_config = self.manager.config().tauri.updater.clone(); @@ -398,23 +393,18 @@ impl App

{ // When dialog is enabled, if user want to recheck // if an update is available after first start // invoke the Event `tauri://update` from JS or rust side. - main_window.listen( - updater::EVENT_CHECK_UPDATE - .parse::() - .unwrap_or_else(|_| panic!("bad label")), - move |_msg| { - let window = event_window.clone(); - let package_info = package_info.clone(); - let config = config.clone(); - // re-spawn task inside tokyo to launch the download - // we don't need to emit anything as everything is handled - // by the process (user is asked to restart at the end) - // and it's handled by the updater - crate::async_runtime::spawn(async move { - updater::check_update_with_dialog(config, package_info, window).await - }); - }, - ); + main_window.listen(updater::EVENT_CHECK_UPDATE, move |_msg| { + let window = event_window.clone(); + let package_info = package_info.clone(); + let config = config.clone(); + // re-spawn task inside tokyo to launch the download + // we don't need to emit anything as everything is handled + // by the process (user is asked to restart at the end) + // and it's handled by the updater + crate::async_runtime::spawn(async move { + updater::check_update_with_dialog(config, package_info, window).await + }); + }); } else if updater_config.active { // we only listen for `tauri://update` // once we receive the call, we check if an update is available or not @@ -429,29 +419,21 @@ impl App

{ /// Builds a Tauri application. #[allow(clippy::type_complexity)] -pub struct Builder -where - E: Tag, - L: Tag, - MID: MenuId, - TID: MenuId, - A: Assets, - R: Runtime, -{ +pub struct Builder { /// The JS message handler. - invoke_handler: Box>>, + invoke_handler: Box>, /// The setup hook. - setup: SetupHook>, + setup: SetupHook, /// Page load hook. - on_page_load: Box>>, + on_page_load: Box>, /// windows to create when starting up. - pending_windows: Vec>>, + pending_windows: Vec>, /// All passed plugins - plugins: PluginStore>, + plugins: PluginStore, /// The webview protocols available to all windows. uri_scheme_protocols: HashMap>, @@ -461,33 +443,25 @@ where /// The menu set to all windows. #[cfg(feature = "menu")] - menu: Option>, + menu: Option

, /// Menu event handlers that listens to all windows. #[cfg(feature = "menu")] - menu_event_listeners: Vec>>, + menu_event_listeners: Vec>, /// Window event handlers that listens to all windows. - window_event_listeners: Vec>>, + window_event_listeners: Vec>, /// The app system tray. #[cfg(feature = "system-tray")] - system_tray: Option>, + system_tray: Option, /// System tray event handlers. #[cfg(feature = "system-tray")] - system_tray_event_listeners: Vec>>, + system_tray_event_listeners: Vec>, } -impl Builder -where - E: Tag, - L: Tag, - MID: MenuId, - TID: MenuId, - A: Assets, - R: Runtime, -{ +impl Builder { /// Creates a new App builder. pub fn new() -> Self { Self { @@ -513,7 +487,7 @@ where /// Defines the JS message handler callback. pub fn invoke_handler(mut self, invoke_handler: F) -> Self where - F: Fn(Invoke>) + Send + Sync + 'static, + F: Fn(Invoke) + Send + Sync + 'static, { self.invoke_handler = Box::new(invoke_handler); self @@ -522,9 +496,7 @@ where /// Defines the setup hook. pub fn setup(mut self, setup: F) -> Self where - F: Fn(&mut App>) -> Result<(), Box> - + Send - + 'static, + F: Fn(&mut App) -> Result<(), Box> + Send + 'static, { self.setup = Box::new(setup); self @@ -533,14 +505,14 @@ where /// Defines the page load hook. pub fn on_page_load(mut self, on_page_load: F) -> Self where - F: Fn(Window>, PageLoadPayload) + Send + Sync + 'static, + F: Fn(Window, PageLoadPayload) + Send + Sync + 'static, { self.on_page_load = Box::new(on_page_load); self } /// Adds a plugin to the runtime. - pub fn plugin> + 'static>(mut self, plugin: P) -> Self { + pub fn plugin + 'static>(mut self, plugin: P) -> Self { self.plugins.register(plugin); self } @@ -633,7 +605,7 @@ where } /// Creates a new webview window. - pub fn create_window(mut self, label: L, url: WindowUrl, setup: F) -> Self + pub fn create_window(mut self, label: impl Into, url: WindowUrl, setup: F) -> Self where F: FnOnce( ::WindowBuilder, @@ -658,7 +630,7 @@ where /// Adds the icon configured on `tauri.conf.json` to the system tray with the specified menu items. #[cfg(feature = "system-tray")] #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] - pub fn system_tray(mut self, system_tray: tray::SystemTray) -> Self { + pub fn system_tray(mut self, system_tray: tray::SystemTray) -> Self { self.system_tray.replace(system_tray); self } @@ -666,7 +638,7 @@ where /// Sets the menu to use on all windows. #[cfg(feature = "menu")] #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] - pub fn menu(mut self, menu: Menu) -> Self { + pub fn menu(mut self, menu: Menu) -> Self { self.menu.replace(menu); self } @@ -674,9 +646,7 @@ where /// Registers a menu event handler for all windows. #[cfg(feature = "menu")] #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] - pub fn on_menu_event< - F: Fn(WindowMenuEvent>) + Send + Sync + 'static, - >( + pub fn on_menu_event) + Send + Sync + 'static>( mut self, handler: F, ) -> Self { @@ -685,9 +655,7 @@ where } /// Registers a window event handler for all windows. - pub fn on_window_event< - F: Fn(GlobalWindowEvent>) + Send + Sync + 'static, - >( + pub fn on_window_event) + Send + Sync + 'static>( mut self, handler: F, ) -> Self { @@ -699,7 +667,7 @@ where #[cfg(feature = "system-tray")] #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] pub fn on_system_tray_event< - F: Fn(&AppHandle>, tray::SystemTrayEvent) + Send + Sync + 'static, + F: Fn(&AppHandle, tray::SystemTrayEvent) + Send + Sync + 'static, >( mut self, handler: F, @@ -736,7 +704,7 @@ where /// Builds the application. #[allow(clippy::type_complexity)] - pub fn build(mut self, context: Context) -> crate::Result>> { + pub fn build(mut self, context: Context) -> crate::Result> { #[cfg(feature = "system-tray")] let system_tray_icon = { let icon = context.system_tray_icon.clone(); @@ -779,11 +747,8 @@ where // set up all the windows defined in the config for config in manager.config().tauri.windows.clone() { let url = config.url.clone(); + let label = config.label.clone(); let file_drop_enabled = config.file_drop_enabled; - let label = config - .label - .parse() - .unwrap_or_else(|_| panic!("bad label found in config: {}", config.label)); let mut webview_attributes = WebviewAttributes::new(url); if !file_drop_enabled { @@ -921,13 +886,13 @@ where } /// Runs the configured Tauri application. - pub fn run(self, context: Context) -> crate::Result<()> { + pub fn run(self, context: Context) -> crate::Result<()> { self.build(context)?.run(|_, _| {}); Ok(()) } } -fn on_event_loop_event(event: &RunEvent, manager: &WindowManager

) { +fn on_event_loop_event(event: &RunEvent, manager: &WindowManager) { if let RunEvent::WindowClose(label) = event { manager.on_window_close(label); } @@ -935,14 +900,7 @@ fn on_event_loop_event(event: &RunEvent, manager: &WindowManager

) /// Make `Wry` the default `Runtime` for `Builder` #[cfg(feature = "wry")] -impl Default for Builder { - fn default() -> Self { - Self::new() - } -} - -#[cfg(not(feature = "wry"))] -impl Default for Builder { +impl Default for Builder { fn default() -> Self { Self::new() } diff --git a/core/tauri/src/app/tray.rs b/core/tauri/src/app/tray.rs index 012ed6f78..cc0c161b7 100644 --- a/core/tauri/src/app/tray.rs +++ b/core/tauri/src/app/tray.rs @@ -2,22 +2,23 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -pub use crate::{ - runtime::{ - menu::{MenuUpdate, SystemTrayMenu, SystemTrayMenuEntry, TrayHandle}, - window::dpi::{PhysicalPosition, PhysicalSize}, - Icon, MenuId, Runtime, SystemTray, +pub use crate::runtime::{ + menu::{ + MenuHash, MenuId, MenuIdRef, MenuUpdate, SystemTrayMenu, SystemTrayMenuEntry, TrayHandle, }, - Params, + window::dpi::{PhysicalPosition, PhysicalSize}, + Icon, Runtime, SystemTray, }; +use tauri_macros::default_runtime; + use std::{collections::HashMap, sync::Arc}; -pub(crate) fn get_menu_ids(map: &mut HashMap, menu: &SystemTrayMenu) { +pub(crate) fn get_menu_ids(map: &mut HashMap, menu: &SystemTrayMenu) { for item in &menu.items { match item { SystemTrayMenuEntry::CustomItem(c) => { - map.insert(c.id_value(), c.id.clone()); + map.insert(c.id, c.id_str.clone()); } SystemTrayMenuEntry::Submenu(s) => get_menu_ids(map, &s.inner), _ => {} @@ -28,12 +29,12 @@ pub(crate) fn get_menu_ids(map: &mut HashMap, menu: &SystemTr /// System tray event. #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] #[non_exhaustive] -pub enum SystemTrayEvent { +pub enum SystemTrayEvent { /// Tray context menu item was clicked. #[non_exhaustive] MenuItemClick { /// The id of the menu item. - id: I, + id: MenuId, }, /// Tray icon received a left click. /// @@ -75,15 +76,14 @@ pub enum SystemTrayEvent { }, } -crate::manager::default_args! { - /// A handle to a system tray. Allows updating the context menu items. - pub struct SystemTrayHandle { - pub(crate) ids: Arc>, - pub(crate) inner: ::TrayHandler, - } +/// A handle to a system tray. Allows updating the context menu items. +#[default_runtime(crate::Wry, wry)] +pub struct SystemTrayHandle { + pub(crate) ids: Arc>, + pub(crate) inner: R::TrayHandler, } -impl Clone for SystemTrayHandle

{ +impl Clone for SystemTrayHandle { fn clone(&self) -> Self { Self { ids: self.ids.clone(), @@ -92,15 +92,14 @@ impl Clone for SystemTrayHandle

{ } } -crate::manager::default_args! { - /// A handle to a system tray menu item. - pub struct SystemTrayMenuItemHandle { - id: u16, - tray_handler: ::TrayHandler, - } +/// A handle to a system tray menu item. +#[default_runtime(crate::Wry, wry)] +pub struct SystemTrayMenuItemHandle { + id: MenuHash, + tray_handler: R::TrayHandler, } -impl Clone for SystemTrayMenuItemHandle

{ +impl Clone for SystemTrayMenuItemHandle { fn clone(&self) -> Self { Self { id: self.id, @@ -109,8 +108,8 @@ impl Clone for SystemTrayMenuItemHandle

{ } } -impl SystemTrayHandle

{ - pub fn get_item(&self, id: &P::SystemTrayMenuId) -> SystemTrayMenuItemHandle

{ +impl SystemTrayHandle { + pub fn get_item(&self, id: MenuIdRef<'_>) -> SystemTrayMenuItemHandle { for (raw, item_id) in self.ids.iter() { if item_id == id { return SystemTrayMenuItemHandle { @@ -128,7 +127,7 @@ impl SystemTrayHandle

{ } } -impl SystemTrayMenuItemHandle

{ +impl SystemTrayMenuItemHandle { /// Modifies the enabled state of the menu item. pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> { self diff --git a/core/tauri/src/command.rs b/core/tauri/src/command.rs index 88cab9a86..f5a3f2bf2 100644 --- a/core/tauri/src/command.rs +++ b/core/tauri/src/command.rs @@ -5,12 +5,13 @@ //! Useful items for custom commands. use crate::hooks::InvokeError; -use crate::{InvokeMessage, Params}; +use crate::runtime::Runtime; +use crate::InvokeMessage; use serde::de::Visitor; use serde::{Deserialize, Deserializer}; /// Represents a custom command. -pub struct CommandItem<'a, P: Params> { +pub struct CommandItem<'a, R: Runtime> { /// The name of the command, e.g. `handler` on `#[command] fn handler(value: u64)` pub name: &'static str, @@ -18,7 +19,7 @@ pub struct CommandItem<'a, P: Params> { pub key: &'static str, /// The [`InvokeMessage`] that was passed to this command. - pub message: &'a InvokeMessage

, + pub message: &'a InvokeMessage, } /// Trait implemented by command arguments to derive a value from a [`CommandItem`]. @@ -36,16 +37,16 @@ pub struct CommandItem<'a, P: Params> { /// * [`crate::State`] /// * `T where T: serde::Deserialize` /// * Any type that implements `Deserialize` can automatically be used as a [`CommandArg`]. -pub trait CommandArg<'de, P: Params>: Sized { +pub trait CommandArg<'de, R: Runtime>: Sized { /// Derives an instance of `Self` from the [`CommandItem`]. /// /// If the derivation fails, the corresponding message will be rejected using [`InvokeMessage#reject`]. - fn from_command(command: CommandItem<'de, P>) -> Result; + fn from_command(command: CommandItem<'de, R>) -> Result; } /// Automatically implement [`CommandArg`] for any type that can be deserialized. -impl<'de, D: Deserialize<'de>, P: Params> CommandArg<'de, P> for D { - fn from_command(command: CommandItem<'de, P>) -> Result { +impl<'de, D: Deserialize<'de>, R: Runtime> CommandArg<'de, R> for D { + fn from_command(command: CommandItem<'de, R>) -> Result { let arg = command.key; Self::deserialize(command).map_err(|e| crate::Error::InvalidArgs(arg, e).into()) } @@ -84,7 +85,7 @@ macro_rules! pass { /// If the key doesn't exist, an error will be returned if the deserialized type is not expecting /// an optional item. If the key does exist, the value will be called with /// [`Value`](serde_json::Value)'s [`Deserializer`] implementation. -impl<'de, P: Params> Deserializer<'de> for CommandItem<'de, P> { +impl<'de, R: Runtime> Deserializer<'de> for CommandItem<'de, R> { type Error = serde_json::Error; pass!(deserialize_any, visitor: V); @@ -146,9 +147,11 @@ impl<'de, P: Params> Deserializer<'de> for CommandItem<'de, P> { } /// [Autoref-based stable specialization](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md) +/// +/// Nothing in this module is considered stable. #[doc(hidden)] pub mod private { - use crate::{InvokeError, InvokeResolver, Params}; + use crate::{runtime::Runtime, InvokeError, InvokeResolver}; use futures::{FutureExt, TryFutureExt}; use serde::Serialize; use serde_json::Value; @@ -174,9 +177,9 @@ pub mod private { impl SerializeTag { #[inline(always)] - pub fn block(self, value: T, resolver: InvokeResolver

) + pub fn block(self, value: T, resolver: InvokeResolver) where - P: Params, + R: Runtime, T: Serialize, { resolver.respond(Ok(value)) @@ -211,9 +214,9 @@ pub mod private { impl ResultTag { #[inline(always)] - pub fn block(self, value: Result, resolver: InvokeResolver

) + pub fn block(self, value: Result, resolver: InvokeResolver) where - P: Params, + R: Runtime, T: Serialize, E: Into, { diff --git a/core/tauri/src/endpoints.rs b/core/tauri/src/endpoints.rs index d78af758e..d732af77b 100644 --- a/core/tauri/src/endpoints.rs +++ b/core/tauri/src/endpoints.rs @@ -5,7 +5,8 @@ use crate::{ api::{config::Config, PackageInfo}, hooks::{InvokeError, InvokeMessage, InvokeResolver}, - Invoke, Params, Window, + runtime::Runtime, + Invoke, Window, }; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; @@ -59,10 +60,10 @@ enum Module { } impl Module { - fn run( + fn run( self, - window: Window

, - resolver: InvokeResolver

, + window: Window, + resolver: InvokeResolver, config: Arc, package_info: PackageInfo, ) { @@ -164,9 +165,9 @@ impl Module { } } -pub(crate) fn handle( +pub(crate) fn handle( module: String, - invoke: Invoke

, + invoke: Invoke, config: Arc, package_info: &PackageInfo, ) { diff --git a/core/tauri/src/endpoints/clipboard.rs b/core/tauri/src/endpoints/clipboard.rs index be84943d1..62550553f 100644 --- a/core/tauri/src/endpoints/clipboard.rs +++ b/core/tauri/src/endpoints/clipboard.rs @@ -4,7 +4,7 @@ use super::InvokeResponse; use crate::{ - runtime::{ClipboardManager, Params}, + runtime::{ClipboardManager, Runtime}, window::Window, }; use serde::Deserialize; @@ -20,7 +20,7 @@ pub enum Cmd { } impl Cmd { - pub fn run(self, window: Window

) -> crate::Result { + pub fn run(self, window: Window) -> crate::Result { let mut clipboard = window.app_handle.clipboard_manager(); match self { Self::WriteText(text) => Ok(clipboard.write_text(text)?.into()), diff --git a/core/tauri/src/endpoints/dialog.rs b/core/tauri/src/endpoints/dialog.rs index 7ad755717..ea6b290a0 100644 --- a/core/tauri/src/endpoints/dialog.rs +++ b/core/tauri/src/endpoints/dialog.rs @@ -7,7 +7,8 @@ use super::InvokeResponse; use crate::api::dialog::FileDialogBuilder; use crate::{ api::dialog::{ask as ask_dialog, message as message_dialog, AskResponse}, - Params, Window, + runtime::Runtime, + Window, }; use serde::Deserialize; @@ -73,7 +74,7 @@ pub enum Cmd { impl Cmd { #[allow(unused_variables)] - pub fn run(self, window: Window

) -> crate::Result { + pub fn run(self, window: Window) -> crate::Result { match self { #[cfg(dialog_open)] Self::OpenDialog { options } => open(window, options), @@ -159,7 +160,7 @@ unsafe impl raw_window_handle::HasRawWindowHandle for WindowParent { } #[cfg(all(windows, any(dialog_open, dialog_save)))] -fn parent(window: Window

) -> crate::Result { +fn parent(window: Window) -> crate::Result { Ok(WindowParent { hwnd: window.hwnd()?, }) @@ -168,8 +169,8 @@ fn parent(window: Window

) -> crate::Result { /// Shows an open dialog. #[cfg(dialog_open)] #[allow(unused_variables)] -pub fn open( - window: Window

, +pub fn open( + window: Window, options: OpenDialogOptions, ) -> crate::Result { let mut dialog_builder = FileDialogBuilder::new(); @@ -200,8 +201,8 @@ pub fn open( /// Shows a save dialog. #[cfg(dialog_save)] #[allow(unused_variables)] -pub fn save( - window: Window

, +pub fn save( + window: Window, options: SaveDialogOptions, ) -> crate::Result { let mut dialog_builder = FileDialogBuilder::new(); diff --git a/core/tauri/src/endpoints/event.rs b/core/tauri/src/endpoints/event.rs index db3af4fd4..f19dd9506 100644 --- a/core/tauri/src/endpoints/event.rs +++ b/core/tauri/src/endpoints/event.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::{endpoints::InvokeResponse, sealed::ManagerBase, Manager, Params, Window}; +use crate::{endpoints::InvokeResponse, runtime::Runtime, sealed::ManagerBase, Manager, Window}; use serde::Deserialize; /// The API descriptor. @@ -25,7 +25,7 @@ pub enum Cmd { } impl Cmd { - pub fn run(self, window: Window

) -> crate::Result { + pub fn run(self, window: Window) -> crate::Result { match self { Self::Listen { event, handler } => { let event_id = rand::random(); @@ -41,23 +41,13 @@ impl Cmd { window_label, payload, } => { - // Panic if the user's `Tag` type decided to return an error while parsing. - let e: P::Event = event - .parse() - .unwrap_or_else(|_| panic!("Event module received unhandled event: {}", event)); - - let window_label: Option = window_label.map(|l| { - l.parse() - .unwrap_or_else(|_| panic!("Event module received unhandled window: {}", l)) - }); - // dispatch the event to Rust listeners - window.trigger(&e, payload.clone()); + window.trigger(&event, payload.clone()); if let Some(target) = window_label { - window.emit_to(&target, &e, payload)?; + window.emit_to(&target, &event, payload)?; } else { - window.emit_all(&e, payload)?; + window.emit_all(&event, payload)?; } Ok(().into()) } @@ -65,7 +55,7 @@ impl Cmd { } } -pub fn unlisten_js(window: &Window

, event_id: u64) -> String { +pub fn unlisten_js(window: &Window, event_id: u64) -> String { format!( " for (var event in (window['{listeners}'] || {{}})) {{ @@ -80,8 +70,8 @@ pub fn unlisten_js(window: &Window

, event_id: u64) -> String { ) } -pub fn listen_js( - window: &Window

, +pub fn listen_js( + window: &Window, event: String, event_id: u64, handler: String, diff --git a/core/tauri/src/endpoints/global_shortcut.rs b/core/tauri/src/endpoints/global_shortcut.rs index 0dc67fb1b..c749458c7 100644 --- a/core/tauri/src/endpoints/global_shortcut.rs +++ b/core/tauri/src/endpoints/global_shortcut.rs @@ -3,11 +3,11 @@ // SPDX-License-Identifier: MIT use super::InvokeResponse; -use crate::{Params, Window}; +use crate::{Runtime, Window}; use serde::Deserialize; #[cfg(global_shortcut_all)] -use crate::runtime::{GlobalShortcutManager, Runtime}; +use crate::runtime::GlobalShortcutManager; /// The API descriptor. #[derive(Deserialize)] @@ -29,9 +29,9 @@ pub enum Cmd { } #[cfg(global_shortcut_all)] -fn register_shortcut( - window: Window

, - manager: &mut ::GlobalShortcutManager, +fn register_shortcut( + window: Window, + manager: &mut R::GlobalShortcutManager, shortcut: String, handler: String, ) -> crate::Result<()> { @@ -46,7 +46,7 @@ fn register_shortcut( #[cfg(not(global_shortcut_all))] impl Cmd { - pub fn run(self, _window: Window

) -> crate::Result { + pub fn run(self, _window: Window) -> crate::Result { Err(crate::Error::ApiNotAllowlisted( "globalShortcut > all".to_string(), )) @@ -55,7 +55,7 @@ impl Cmd { #[cfg(global_shortcut_all)] impl Cmd { - pub fn run(self, window: Window

) -> crate::Result { + pub fn run(self, window: Window) -> crate::Result { match self { Self::Register { shortcut, handler } => { let mut manager = window.app_handle.global_shortcut_manager(); diff --git a/core/tauri/src/endpoints/internal.rs b/core/tauri/src/endpoints/internal.rs index 6049308b5..ceb5a4559 100644 --- a/core/tauri/src/endpoints/internal.rs +++ b/core/tauri/src/endpoints/internal.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use super::InvokeResponse; -use crate::{Params, Window}; +use crate::{runtime::Runtime, Window}; use serde::Deserialize; /// The API descriptor. @@ -14,7 +14,7 @@ pub enum Cmd { } impl Cmd { - pub fn run(self, window: Window

) -> crate::Result { + pub fn run(self, window: Window) -> crate::Result { match self { Self::ValidateSalt { salt } => Ok(window.verify_salt(salt).into()), } diff --git a/core/tauri/src/endpoints/shell.rs b/core/tauri/src/endpoints/shell.rs index 5ad0432ee..1d90df7a6 100644 --- a/core/tauri/src/endpoints/shell.rs +++ b/core/tauri/src/endpoints/shell.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::{endpoints::InvokeResponse, Params, Window}; +use crate::{endpoints::InvokeResponse, runtime::Runtime, Window}; use serde::Deserialize; #[cfg(shell_execute)] @@ -73,7 +73,7 @@ pub enum Cmd { impl Cmd { #[allow(unused_variables)] - pub fn run(self, window: Window

) -> crate::Result { + pub fn run(self, window: Window) -> crate::Result { match self { Self::Execute { program, diff --git a/core/tauri/src/endpoints/window.rs b/core/tauri/src/endpoints/window.rs index 2fe6dafcd..990444e29 100644 --- a/core/tauri/src/endpoints/window.rs +++ b/core/tauri/src/endpoints/window.rs @@ -3,15 +3,15 @@ // SPDX-License-Identifier: MIT #[cfg(window_create)] -use crate::runtime::{webview::WindowBuilder, Dispatch, Runtime}; +use crate::runtime::{webview::WindowBuilder, Dispatch}; use crate::{ api::config::WindowConfig, endpoints::InvokeResponse, runtime::{ window::dpi::{Position, Size}, - UserAttentionType, + Runtime, UserAttentionType, }, - Manager, Params, Window, + Manager, Window, }; use serde::Deserialize; @@ -103,7 +103,7 @@ struct WindowCreatedEvent { impl Cmd { #[allow(dead_code)] - pub async fn run(self, window: Window

) -> crate::Result { + pub async fn run(self, window: Window) -> crate::Result { match self { #[cfg(not(window_create))] Self::CreateWebview { .. } => { @@ -114,36 +114,21 @@ impl Cmd { #[cfg(window_create)] Self::CreateWebview { options } => { let mut window = window; - // Panic if the user's `Tag` type decided to return an error while parsing. - let label: P::Label = options.label.parse().unwrap_or_else(|_| { - panic!( - "Window module received unknown window label: {}", - options.label - ) - }); - + let label = options.label.clone(); let url = options.url.clone(); + window .create_window(label.clone(), url, |_, webview_attributes| { ( - <<::Dispatcher as Dispatch>::WindowBuilder>::with_config( - options, - ), + <::WindowBuilder>::with_config(options), webview_attributes, ) })? - .emit_others( - &crate::manager::tauri_event::("tauri://window-created"), - Some(WindowCreatedEvent { - label: label.to_string(), - }), - )?; + .emit_others("tauri://window-created", Some(WindowCreatedEvent { label }))?; } Self::Manage { label, cmd } => { let window = if let Some(l) = label { - window - .get_window(&l.parse().unwrap_or_else(|_| panic!("invalid label"))) - .ok_or(crate::Error::WebviewNotFound)? + window.get_window(&l).ok_or(crate::Error::WebviewNotFound)? } else { window }; diff --git a/core/tauri/src/event.rs b/core/tauri/src/event.rs index 371407006..40370f0e8 100644 --- a/core/tauri/src/event.rs +++ b/core/tauri/src/event.rs @@ -2,9 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::runtime::tag::{Tag, TagRef}; use std::{ - borrow::Borrow, boxed::Box, collections::HashMap, fmt, @@ -43,36 +41,33 @@ impl Event { } /// What to do with the pending handler when resolving it? -enum Pending { +enum Pending { Unlisten(EventHandler), - Listen(EventHandler, Event, Handler), - Trigger(Event, Option, Option), + Listen(EventHandler, String, Handler), + Trigger(String, Option, Option), } /// Stored in [`Listeners`] to be called upon when the event that stored it is triggered. -struct Handler { - window: Option, +struct Handler { + window: Option, callback: Box, } -/// A collection of handlers. Multiple handlers can represent the same event. -type Handlers = HashMap>>; - /// Holds event handlers and pending event handlers, along with the salts associating them. -struct InnerListeners { - handlers: Mutex>, - pending: Mutex>>, +struct InnerListeners { + handlers: Mutex>>, + pending: Mutex>, function_name: Uuid, listeners_object_name: Uuid, queue_object_name: Uuid, } /// A self-contained event manager. -pub(crate) struct Listeners { - inner: Arc>, +pub(crate) struct Listeners { + inner: Arc, } -impl Default for Listeners { +impl Default for Listeners { fn default() -> Self { Self { inner: Arc::new(InnerListeners { @@ -86,7 +81,7 @@ impl Default for Listeners { } } -impl Clone for Listeners { +impl Clone for Listeners { fn clone(&self) -> Self { Self { inner: self.inner.clone(), @@ -94,7 +89,7 @@ impl Clone for Listeners { } } -impl Listeners { +impl Listeners { /// Randomly generated function name to represent the JavaScript event function. pub(crate) fn function_name(&self) -> String { self.inner.function_name.to_string() @@ -111,7 +106,7 @@ impl Listeners { } /// Insert a pending event action to the queue. - fn insert_pending(&self, action: Pending) { + fn insert_pending(&self, action: Pending) { self .inner .pending @@ -140,7 +135,7 @@ impl Listeners { } } - fn listen_(&self, id: EventHandler, event: Event, handler: Handler) { + fn listen_(&self, id: EventHandler, event: String, handler: Handler) { match self.inner.handlers.try_lock() { Err(_) => self.insert_pending(Pending::Listen(id, event, handler)), Ok(mut lock) => { @@ -150,10 +145,10 @@ impl Listeners { } /// Adds an event listener for JS events. - pub(crate) fn listen( + pub(crate) fn listen( &self, - event: Event, - window: Option, + event: String, + window: Option, handler: F, ) -> EventHandler { let id = EventHandler(Uuid::new_v4()); @@ -168,10 +163,10 @@ impl Listeners { } /// Listen to a JS event and immediately unlisten. - pub(crate) fn once( + pub(crate) fn once( &self, - event: Event, - window: Option, + event: String, + window: Option, handler: F, ) -> EventHandler { let self_ = self.clone(); @@ -192,15 +187,7 @@ impl Listeners { } /// Triggers the given global event with its payload. - pub(crate) fn trigger( - &self, - event: &E, - window: Option, - payload: Option, - ) where - Event: Borrow, - E: TagRef, - { + pub(crate) fn trigger(&self, event: &str, window: Option, payload: Option) { let mut maybe_pending = false; match self.inner.handlers.try_lock() { Err(_) => self.insert_pending(Pending::Trigger(event.to_owned(), window, payload)), @@ -241,7 +228,7 @@ mod test { // check to see if listen() is properly passing keys into the LISTENERS map #[test] fn listeners_check_key(e in "[a-z]+") { - let listeners: Listeners = Default::default(); + let listeners: Listeners = Default::default(); // clone e as the key let key = e.clone(); // pass e and an dummy func into listen @@ -257,7 +244,7 @@ mod test { // check to see if listen inputs a handler function properly into the LISTENERS map. #[test] fn listeners_check_fn(e in "[a-z]+") { - let listeners: Listeners = Default::default(); + let listeners: Listeners = Default::default(); // clone e as the key let key = e.clone(); // pass e and an dummy func into listen @@ -283,7 +270,7 @@ mod test { // check to see if on_event properly grabs the stored function from listen. #[test] fn check_on_event(e in "[a-z]+", d in "[a-z]+") { - let listeners: Listeners = Default::default(); + let listeners: Listeners = Default::default(); // clone e as the key let key = e.clone(); // call listen with e and the event_fn dummy func diff --git a/core/tauri/src/hooks.rs b/core/tauri/src/hooks.rs index 929abc520..71007d02f 100644 --- a/core/tauri/src/hooks.rs +++ b/core/tauri/src/hooks.rs @@ -5,21 +5,24 @@ use crate::{ api::rpc::{format_callback, format_callback_result}, app::App, - Params, StateManager, Window, + runtime::Runtime, + StateManager, Window, }; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; use std::{future::Future, sync::Arc}; +use tauri_macros::default_runtime; + /// A closure that is run when the Tauri application is setting up. -pub type SetupHook

= - Box) -> Result<(), Box> + Send>; +pub type SetupHook = + Box) -> Result<(), Box> + Send>; /// A closure that is run everytime Tauri receives a message it doesn't explicitly handle. -pub type InvokeHandler

= dyn Fn(Invoke

) + Send + Sync + 'static; +pub type InvokeHandler = dyn Fn(Invoke) + Send + Sync + 'static; /// A closure that is run once every time a window is created and loaded. -pub type OnPageLoad

= dyn Fn(Window

, PageLoadPayload) + Send + Sync + 'static; +pub type OnPageLoad = dyn Fn(Window, PageLoadPayload) + Send + Sync + 'static; /// The payload for the [`OnPageLoad`] hook. #[derive(Debug, Clone, Deserialize)] @@ -34,15 +37,14 @@ impl PageLoadPayload { } } -crate::manager::default_args! { - /// The message and resolver given to a custom command. - pub struct Invoke { - /// The message passed. - pub message: InvokeMessage

, +/// The message and resolver given to a custom command. +#[default_runtime(crate::Wry, wry)] +pub struct Invoke { + /// The message passed. + pub message: InvokeMessage, - /// The resolver of the message. - pub resolver: InvokeResolver

, - } + /// The resolver of the message. + pub resolver: InvokeResolver, } /// Error response from an [`InvokeMessage`]. @@ -112,17 +114,16 @@ impl From for InvokeResponse { } } -crate::manager::default_args! { - /// Resolver of a invoke message. - pub struct InvokeResolver { - window: Window

, - pub(crate) callback: String, - pub(crate) error: String, - } +/// Resolver of a invoke message. +#[default_runtime(crate::Wry, wry)] +pub struct InvokeResolver { + window: Window, + pub(crate) callback: String, + pub(crate) error: String, } -impl InvokeResolver

{ - pub(crate) fn new(window: Window

, callback: String, error: String) -> Self { +impl InvokeResolver { + pub(crate) fn new(window: Window, callback: String, error: String) -> Self { Self { window, callback, @@ -191,7 +192,7 @@ impl InvokeResolver

{ /// If the Result `is_ok()`, the callback will be the `success_callback` function name and the argument will be the Ok value. /// If the Result `is_err()`, the callback will be the `error_callback` function name and the argument will be the Err value. pub async fn return_task( - window: Window

, + window: Window, task: F, success_callback: String, error_callback: String, @@ -204,7 +205,7 @@ impl InvokeResolver

{ } pub(crate) fn return_closure Result>( - window: Window

, + window: Window, f: F, success_callback: String, error_callback: String, @@ -213,7 +214,7 @@ impl InvokeResolver

{ } pub(crate) fn return_result( - window: Window

, + window: Window, response: InvokeResponse, success_callback: String, error_callback: String, @@ -232,24 +233,23 @@ impl InvokeResolver

{ } } -crate::manager::default_args! { - /// An invoke message. - pub struct InvokeMessage { - /// The window that received the invoke message. - pub(crate) window: Window

, - /// Application managed state. - pub(crate) state: Arc, - /// The RPC command. - pub(crate) command: String, - /// The JSON argument passed on the invoke message. - pub(crate) payload: JsonValue, - } +/// An invoke message. +#[default_runtime(crate::Wry, wry)] +pub struct InvokeMessage { + /// The window that received the invoke message. + pub(crate) window: Window, + /// Application managed state. + pub(crate) state: Arc, + /// The RPC command. + pub(crate) command: String, + /// The JSON argument passed on the invoke message. + pub(crate) payload: JsonValue, } -impl InvokeMessage

{ +impl InvokeMessage { /// Create an new [`InvokeMessage`] from a payload send to a window. pub(crate) fn new( - window: Window

, + window: Window, state: Arc, command: String, payload: JsonValue, @@ -270,13 +270,13 @@ impl InvokeMessage

{ /// The window that received the invoke. #[inline(always)] - pub fn window(&self) -> Window

{ + pub fn window(&self) -> Window { self.window.clone() } /// A reference to window that received the invoke. #[inline(always)] - pub fn window_ref(&self) -> &Window

{ + pub fn window_ref(&self) -> &Window { &self.window } diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index 2019fac24..53efebed9 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -63,7 +63,7 @@ use crate::{ runtime::window::PendingWindow, }; use serde::Serialize; -use std::{borrow::Borrow, collections::HashMap, sync::Arc}; +use std::{collections::HashMap, sync::Arc}; // Export types likely to be used by the application. #[cfg(any(feature = "menu", feature = "system-tray"))] @@ -89,13 +89,12 @@ pub use { PageLoadPayload, SetupHook, }, self::runtime::{ - tag::{Tag, TagRef}, webview::{WebviewAttributes, WindowBuilder}, window::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size}, WindowEvent, }, - Icon, MenuId, Params, RunIteration, UserAttentionType, + Icon, RunIteration, Runtime, UserAttentionType, }, self::state::{State, StateManager}, self::window::{Monitor, Window}, @@ -246,42 +245,26 @@ impl Context { // TODO: expand these docs /// Manages a running application. -pub trait Manager: sealed::ManagerBase

{ +pub trait Manager: sealed::ManagerBase { /// The [`Config`] the manager was created with. fn config(&self) -> Arc { self.manager().config() } /// Emits a event to all windows. - fn emit_all(&self, event: &E, payload: S) -> Result<()> - where - P::Event: Borrow, - E: TagRef, - S: Serialize + Clone, - { + fn emit_all(&self, event: &str, payload: S) -> Result<()> { self.manager().emit_filter(event, payload, |_| true) } /// Emits an event to a window with the specified label. - fn emit_to( - &self, - label: &L, - event: &E, - payload: S, - ) -> Result<()> - where - P::Label: Borrow, - P::Event: Borrow, - L: TagRef, - E: TagRef, - { + fn emit_to(&self, label: &str, event: &str, payload: S) -> Result<()> { self .manager() .emit_filter(event, payload, |w| label == w.label()) } /// Listen to a global event. - fn listen_global, F>(&self, event: E, handler: F) -> EventHandler + fn listen_global(&self, event: impl Into, handler: F) -> EventHandler where F: Fn(EmittedEvent) + Send + 'static, { @@ -289,7 +272,7 @@ pub trait Manager: sealed::ManagerBase

{ } /// Listen to a global event only once. - fn once_global, F>(&self, event: E, handler: F) -> EventHandler + fn once_global(&self, event: impl Into, handler: F) -> EventHandler where F: Fn(EmittedEvent) + Send + 'static, { @@ -297,11 +280,7 @@ pub trait Manager: sealed::ManagerBase

{ } /// Trigger a global event. - fn trigger_global(&self, event: &E, data: Option) - where - P::Event: Borrow, - E: TagRef, - { + fn trigger_global(&self, event: &str, data: Option) { self.manager().trigger(event, None, data) } @@ -311,16 +290,12 @@ pub trait Manager: sealed::ManagerBase

{ } /// Fetch a single window from the manager. - fn get_window(&self, label: &L) -> Option> - where - P::Label: Borrow, - L: TagRef, - { + fn get_window(&self, label: &str) -> Option> { self.manager().get_window(label) } /// Fetch all managed windows. - fn windows(&self) -> HashMap> { + fn windows(&self) -> HashMap> { self.manager().windows() } @@ -345,33 +320,33 @@ pub trait Manager: sealed::ManagerBase

{ /// Prevent implementation details from leaking out of the [`Manager`] trait. pub(crate) mod sealed { use crate::{app::AppHandle, manager::WindowManager}; - use tauri_runtime::{Params, Runtime, RuntimeHandle}; + use tauri_runtime::{Runtime, RuntimeHandle}; /// A running [`Runtime`] or a dispatcher to it. - pub enum RuntimeOrDispatch<'r, P: Params> { + pub enum RuntimeOrDispatch<'r, R: Runtime> { /// Reference to the running [`Runtime`]. - Runtime(&'r P::Runtime), + Runtime(&'r R), /// Handle to the running [`Runtime`]. - RuntimeHandle(::Handle), + RuntimeHandle(R::Handle), /// A dispatcher to the running [`Runtime`]. - Dispatch(::Dispatcher), + Dispatch(R::Dispatcher), } /// Managed handle to the application runtime. - pub trait ManagerBase { + pub trait ManagerBase { /// The manager behind the [`Managed`] item. - fn manager(&self) -> &WindowManager

; + fn manager(&self) -> &WindowManager; - fn runtime(&self) -> RuntimeOrDispatch<'_, P>; - fn app_handle(&self) -> AppHandle

; + fn runtime(&self) -> RuntimeOrDispatch<'_, R>; + fn app_handle(&self) -> AppHandle; /// Creates a new [`Window`] on the [`Runtime`] and attaches it to the [`Manager`]. fn create_new_window( &self, - pending: crate::PendingWindow

, - ) -> crate::Result> { + pending: crate::PendingWindow, + ) -> crate::Result> { use crate::runtime::Dispatch; let labels = self.manager().labels().into_iter().collect::>(); let pending = self diff --git a/core/tauri/src/manager.rs b/core/tauri/src/manager.rs index e5a5d4b24..a37caa514 100644 --- a/core/tauri/src/manager.rs +++ b/core/tauri/src/manager.rs @@ -2,9 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -// we re-export the default_args! macro as pub(crate) so we can use it easily from other modules -#![allow(clippy::single_component_path_imports)] - use crate::{ api::{ assets::Assets, @@ -17,14 +14,12 @@ use crate::{ hooks::{InvokeHandler, OnPageLoad, PageLoadPayload}, plugin::PluginStore, runtime::{ - private::ParamsBase, - tag::{tags_to_javascript_array, Tag, TagRef, ToJsString}, webview::{ CustomProtocol, FileDropEvent, FileDropHandler, InvokePayload, WebviewRpcHandler, WindowBuilder, }, window::{dpi::PhysicalSize, DetachedWindow, PendingWindow, WindowEvent}, - Icon, MenuId, Params, Runtime, + Icon, Runtime, }, App, Context, Invoke, StateManager, Window, }; @@ -34,20 +29,19 @@ use crate::app::{GlobalMenuEventListener, WindowMenuEvent}; #[cfg(feature = "menu")] use crate::{ - runtime::menu::{Menu, MenuEntry}, + runtime::menu::{Menu, MenuEntry, MenuHash, MenuId}, MenuEvent, }; use serde::Serialize; use serde_json::Value as JsonValue; -use std::borrow::Borrow; -use std::marker::PhantomData; use std::{ borrow::Cow, collections::{HashMap, HashSet}, fs::create_dir_all, sync::{Arc, Mutex, MutexGuard}, }; +use tauri_macros::default_runtime; use uuid::Uuid; const WINDOW_RESIZED_EVENT: &str = "tauri://resize"; @@ -60,162 +54,62 @@ const WINDOW_SCALE_FACTOR_CHANGED_EVENT: &str = "tauri://scale-change"; #[cfg(feature = "menu")] const MENU_EVENT: &str = "tauri://menu"; -/// Parse a string representing an internal tauri event into [`Params::Event`] -/// -/// # Panics -/// -/// This will panic if the `FromStr` implementation of [`Params::Event`] returns an error. -pub(crate) fn tauri_event(tauri_event: &str) -> Event { - tauri_event.parse().unwrap_or_else(|_| { - panic!( - "failed to parse internal tauri event into Params::Event: {}", - tauri_event - ) - }) +#[default_runtime(crate::Wry, wry)] +pub struct InnerWindowManager { + windows: Mutex>>, + plugins: Mutex>, + listeners: Listeners, + pub(crate) state: Arc, + + /// The JS message handler. + invoke_handler: Box>, + + /// The page load hook, invoked when the webview performs a navigation. + on_page_load: Box>, + + config: Arc, + assets: Arc, + default_window_icon: Option>, + + /// A list of salts that are valid for the current application. + salts: Mutex>, + package_info: PackageInfo, + /// The webview protocols protocols available to all windows. + uri_scheme_protocols: HashMap>, + /// The menu set to all windows. + #[cfg(feature = "menu")] + menu: Option

, + /// Maps runtime id to a strongly typed menu id. + #[cfg(feature = "menu")] + menu_ids: HashMap, + /// Menu event listeners to all windows. + #[cfg(feature = "menu")] + menu_event_listeners: Arc>>, + /// Window event listeners to all windows. + window_event_listeners: Arc>>, } -crate::manager::default_args! { - pub struct InnerWindowManager { - windows: Mutex>>, - plugins: Mutex>, - listeners: Listeners, - pub(crate) state: Arc, - - /// The JS message handler. - invoke_handler: Box>, - - /// The page load hook, invoked when the webview performs a navigation. - on_page_load: Box>, - - config: Arc, - assets: Arc, - default_window_icon: Option>, - - /// A list of salts that are valid for the current application. - salts: Mutex>, - package_info: PackageInfo, - /// The webview protocols protocols available to all windows. - uri_scheme_protocols: HashMap>, - /// The menu set to all windows. - #[cfg(feature = "menu")] - menu: Option>, - /// Maps runtime id to a strongly typed menu id. - #[cfg(feature = "menu")] - menu_ids: HashMap, - /// Menu event listeners to all windows. - #[cfg(feature = "menu")] - menu_event_listeners: Arc>>, - /// Window event listeners to all windows. - window_event_listeners: Arc>>, - } +#[default_runtime(crate::Wry, wry)] +pub struct WindowManager { + pub inner: Arc>, + invoke_keys: Arc>>, } -/// struct declaration using params + default args which includes optional feature wry -macro_rules! default_args { - ( - $(#[$attrs_struct:meta])* - $vis_struct:vis struct $name:ident<$p:ident: $params:ident> { - $( - $(#[$attrs_field:meta])* - $vis_field:vis $field:ident: $field_type:ty, - )* - } - ) => { - $(#[$attrs_struct])* - #[cfg(feature = "wry")] - $vis_struct struct $name<$p: $params = crate::manager::DefaultArgs> { - $( - $(#[$attrs_field])* - $vis_field $field: $field_type, - )* - } - - $(#[$attrs_struct])* - #[cfg(not(feature = "wry"))] - $vis_struct struct $name<$p: $params> { - $( - $(#[$attrs_field])* - $vis_field $field: $field_type, - )* - } - }; -} - -// export it to allow use from other modules -pub(crate) use default_args; - -/// This type should always match `Builder::default()`, otherwise the default type is useless. -#[cfg(feature = "wry")] -pub(crate) type DefaultArgs = - Args; - -/// A [Zero Sized Type] marker representing a full [`Params`]. -/// -/// [Zero Sized Type]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts -pub struct Args { - _event: PhantomData E>, - _label: PhantomData L>, - _menu_id: PhantomData MID>, - _tray_menu_id: PhantomData TID>, - _assets: PhantomData A>, - _runtime: PhantomData R>, -} - -impl Default - for Args -{ - fn default() -> Self { - Self { - _event: PhantomData, - _label: PhantomData, - _menu_id: PhantomData, - _tray_menu_id: PhantomData, - _assets: PhantomData, - _runtime: PhantomData, - } - } -} - -impl ParamsBase - for Args -{ -} -impl Params - for Args -{ - type Event = E; - type Label = L; - type MenuId = MID; - type SystemTrayMenuId = TID; - type Assets = A; - type Runtime = R; -} - -crate::manager::default_args! { - pub struct WindowManager { - pub inner: Arc>, - invoke_keys: Arc>>, - #[allow(clippy::type_complexity)] - _marker: Args, - } -} - -impl Clone for WindowManager

{ +impl Clone for WindowManager { fn clone(&self) -> Self { Self { inner: self.inner.clone(), invoke_keys: self.invoke_keys.clone(), - _marker: Args::default(), } } } #[cfg(feature = "menu")] -fn get_menu_ids(map: &mut HashMap, menu: &Menu) { +fn get_menu_ids(map: &mut HashMap, menu: &Menu) { for item in &menu.items { match item { MenuEntry::CustomItem(c) => { - map.insert(c.id_value(), c.id.clone()); + map.insert(c.id, c.id_str.clone()); } MenuEntry::Submenu(s) => get_menu_ids(map, &s.inner), _ => {} @@ -223,19 +117,19 @@ fn get_menu_ids(map: &mut HashMap, menu: &Menu) { } } -impl WindowManager

{ +impl WindowManager { #[allow(clippy::too_many_arguments)] pub(crate) fn with_handlers( - context: Context, - plugins: PluginStore

, - invoke_handler: Box>, - on_page_load: Box>, + context: Context, + plugins: PluginStore, + invoke_handler: Box>, + on_page_load: Box>, uri_scheme_protocols: HashMap>, state: StateManager, - window_event_listeners: Vec>, + window_event_listeners: Vec>, #[cfg(feature = "menu")] (menu, menu_event_listeners): ( - Option>, - Vec>, + Option

, + Vec>, ), ) -> Self { Self { @@ -267,12 +161,11 @@ impl WindowManager

{ window_event_listeners: Arc::new(window_event_listeners), }), invoke_keys: Default::default(), - _marker: Args::default(), } } /// Get a locked handle to the windows. - pub(crate) fn windows_lock(&self) -> MutexGuard<'_, HashMap>> { + pub(crate) fn windows_lock(&self) -> MutexGuard<'_, HashMap>> { self.inner.windows.lock().expect("poisoned window manager") } @@ -283,7 +176,7 @@ impl WindowManager

{ /// Get the menu ids mapper. #[cfg(feature = "menu")] - pub(crate) fn menu_ids(&self) -> HashMap { + pub(crate) fn menu_ids(&self) -> HashMap { self.inner.menu_ids.clone() } @@ -319,10 +212,10 @@ impl WindowManager

{ fn prepare_pending_window( &self, - mut pending: PendingWindow

, - label: P::Label, - pending_labels: &[P::Label], - ) -> crate::Result> { + mut pending: PendingWindow, + label: &str, + pending_labels: &[String], + ) -> crate::Result> { let is_init_global = self.inner.config.build.with_global_tauri; let plugin_init = self .inner @@ -339,8 +232,8 @@ impl WindowManager

{ window.__TAURI__.__windows = {window_labels_array}.map(function (label) {{ return {{ label: label }} }}); window.__TAURI__.__currentWindow = {{ label: {current_window_label} }} "#, - window_labels_array = tags_to_javascript_array(pending_labels)?, - current_window_label = label.to_js_string()?, + window_labels_array = serde_json::to_string(pending_labels)?, + current_window_label = serde_json::to_string(&label)?, )); #[cfg(dev)] @@ -403,7 +296,7 @@ impl WindowManager

{ Ok(pending) } - fn prepare_rpc_handler(&self, app_handle: AppHandle

) -> WebviewRpcHandler

{ + fn prepare_rpc_handler(&self, app_handle: AppHandle) -> WebviewRpcHandler { let manager = self.clone(); Box::new(move |window, request| { let window = Window::new(manager.clone(), window, app_handle.clone()); @@ -462,11 +355,11 @@ impl WindowManager

{ let is_html = path.ends_with(".html"); let asset_response = assets - .get(&path) + .get(&path.as_str().into()) .or_else(|| { #[cfg(debug_assertions)] eprintln!("Asset `{}` not found; fallback to index.html", path); // TODO log::error! - assets.get("index.html") + assets.get(&"index.html".into()) }) .ok_or(crate::Error::AssetNotFound(path)) .map(Cow::into_owned); @@ -498,7 +391,7 @@ impl WindowManager

{ } } - fn prepare_file_drop(&self, app_handle: AppHandle

) -> FileDropHandler

{ + fn prepare_file_drop(&self, app_handle: AppHandle) -> FileDropHandler { let manager = self.clone(); Box::new(move |event, window| { let manager = manager.clone(); @@ -506,17 +399,9 @@ impl WindowManager

{ crate::async_runtime::block_on(async move { let window = Window::new(manager.clone(), window, app_handle); let _ = match event { - FileDropEvent::Hovered(paths) => { - window.emit(&tauri_event::("tauri://file-drop"), Some(paths)) - } - FileDropEvent::Dropped(paths) => window.emit( - &tauri_event::("tauri://file-drop-hover"), - Some(paths), - ), - FileDropEvent::Cancelled => window.emit( - &tauri_event::("tauri://file-drop-cancelled"), - Some(()), - ), + FileDropEvent::Hovered(paths) => window.emit("tauri://file-drop", Some(paths)), + FileDropEvent::Dropped(paths) => window.emit("tauri://file-drop-hover", Some(paths)), + FileDropEvent::Cancelled => window.emit("tauri://file-drop-cancelled", Some(())), _ => unimplemented!(), }; }); @@ -601,24 +486,23 @@ impl WindowManager

{ #[cfg(test)] mod test { - use super::{Args, WindowManager}; + use super::WindowManager; use crate::{generate_context, plugin::PluginStore, StateManager, Wry}; #[test] fn check_get_url() { let context = generate_context!("test/fixture/src-tauri/tauri.conf.json", crate); - let manager: WindowManager> = - WindowManager::with_handlers( - context, - PluginStore::default(), - Box::new(|_| ()), - Box::new(|_, _| ()), - Default::default(), - StateManager::new(), - Default::default(), - #[cfg(feature = "menu")] - Default::default(), - ); + let manager: WindowManager = WindowManager::with_handlers( + context, + PluginStore::default(), + Box::new(|_| ()), + Box::new(|_, _| ()), + Default::default(), + StateManager::new(), + Default::default(), + #[cfg(feature = "menu")] + Default::default(), + ); #[cfg(custom_protocol)] assert_eq!(manager.get_url(), "tauri://localhost"); @@ -628,12 +512,12 @@ mod test { } } -impl WindowManager

{ - pub fn run_invoke_handler(&self, invoke: Invoke

) { +impl WindowManager { + pub fn run_invoke_handler(&self, invoke: Invoke) { (self.inner.invoke_handler)(invoke); } - pub fn run_on_page_load(&self, window: Window

, payload: PageLoadPayload) { + pub fn run_on_page_load(&self, window: Window, payload: PageLoadPayload) { (self.inner.on_page_load)(window.clone(), payload.clone()); self .inner @@ -643,7 +527,7 @@ impl WindowManager

{ .on_page_load(window, payload); } - pub fn extend_api(&self, invoke: Invoke

) { + pub fn extend_api(&self, invoke: Invoke) { self .inner .plugins @@ -652,7 +536,7 @@ impl WindowManager

{ .extend_api(invoke); } - pub fn initialize_plugins(&self, app: &App

) -> crate::Result<()> { + pub fn initialize_plugins(&self, app: &App) -> crate::Result<()> { self .inner .plugins @@ -663,14 +547,12 @@ impl WindowManager

{ pub fn prepare_window( &self, - app_handle: AppHandle

, - mut pending: PendingWindow

, - pending_labels: &[P::Label], - ) -> crate::Result> { + app_handle: AppHandle, + mut pending: PendingWindow, + pending_labels: &[String], + ) -> crate::Result> { if self.windows_lock().contains_key(&pending.label) { - return Err(crate::Error::WindowLabelAlreadyExists( - pending.label.to_string(), - )); + return Err(crate::Error::WindowLabelAlreadyExists(pending.label)); } let (is_local, url) = match &pending.webview_attributes.url { WindowUrl::App(path) => { @@ -691,7 +573,7 @@ impl WindowManager

{ if is_local { let label = pending.label.clone(); - pending = self.prepare_pending_window(pending, label, pending_labels)?; + pending = self.prepare_pending_window(pending, &label, pending_labels)?; pending.rpc_handler = Some(self.prepare_rpc_handler(app_handle.clone())); } @@ -703,7 +585,7 @@ impl WindowManager

{ Ok(pending) } - pub fn attach_window(&self, app_handle: AppHandle

, window: DetachedWindow

) -> Window

{ + pub fn attach_window(&self, app_handle: AppHandle, window: DetachedWindow) -> Window { let window = Window::new(self.clone(), window, app_handle); let window_ = window.clone(); @@ -737,7 +619,7 @@ impl WindowManager

{ { self .windows_lock() - .insert(window.label().clone(), window.clone()); + .insert(window.label().to_string(), window.clone()); } // let plugins know that a new window has been added to the manager @@ -754,17 +636,13 @@ impl WindowManager

{ } pub(crate) fn on_window_close(&self, label: &str) { - self - .windows_lock() - .remove(&label.parse().unwrap_or_else(|_| panic!("bad label"))); + self.windows_lock().remove(label); } - pub fn emit_filter(&self, event: &E, payload: S, filter: F) -> crate::Result<()> + pub fn emit_filter(&self, event: &str, payload: S, filter: F) -> crate::Result<()> where - P::Event: Borrow, - E: TagRef, S: Serialize + Clone, - F: Fn(&Window

) -> bool, + F: Fn(&Window) -> bool, { self .windows_lock() @@ -773,7 +651,7 @@ impl WindowManager

{ .try_for_each(|window| window.emit(event, payload.clone())) } - pub fn labels(&self) -> HashSet { + pub fn labels(&self) -> HashSet { self.windows_lock().keys().cloned().collect() } @@ -789,26 +667,22 @@ impl WindowManager

{ self.inner.listeners.unlisten(handler_id) } - pub fn trigger(&self, event: &E, window: Option, data: Option) - where - P::Event: Borrow, - E: TagRef, - { + pub fn trigger(&self, event: &str, window: Option, data: Option) { self.inner.listeners.trigger(event, window, data) } pub fn listen( &self, - event: P::Event, - window: Option, + event: String, + window: Option, handler: F, ) -> EventHandler { self.inner.listeners.listen(event, window, handler) } pub fn once( &self, - event: P::Event, - window: Option, + event: String, + window: Option, handler: F, ) -> EventHandler { self.inner.listeners.once(event, window, handler) @@ -848,52 +722,28 @@ impl WindowManager

{ .remove(&uuid) } - pub fn get_window(&self, label: &L) -> Option> - where - P::Label: Borrow, - L: TagRef, - { + pub fn get_window(&self, label: &str) -> Option> { self.windows_lock().get(label).cloned() } - pub fn windows(&self) -> HashMap> { + pub fn windows(&self) -> HashMap> { self.windows_lock().clone() } } -fn on_window_event( - window: &Window

, - manager: &WindowManager

, +fn on_window_event( + window: &Window, + manager: &WindowManager, event: &WindowEvent, ) -> crate::Result<()> { match event { - WindowEvent::Resized(size) => window.emit( - &WINDOW_RESIZED_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")), - Some(size), - )?, - WindowEvent::Moved(position) => window.emit( - &WINDOW_MOVED_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")), - Some(position), - )?, + WindowEvent::Resized(size) => window.emit(WINDOW_RESIZED_EVENT, Some(size))?, + WindowEvent::Moved(position) => window.emit(WINDOW_MOVED_EVENT, Some(position))?, WindowEvent::CloseRequested => { - window.emit( - &WINDOW_CLOSE_REQUESTED_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")), - Some(()), - )?; + window.emit(WINDOW_CLOSE_REQUESTED_EVENT, Some(()))?; } WindowEvent::Destroyed => { - window.emit( - &WINDOW_DESTROYED_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")), - Some(()), - )?; + window.emit(WINDOW_DESTROYED_EVENT, Some(()))?; let label = window.label(); for window in manager.inner.windows.lock().unwrap().values() { window.eval(&format!( @@ -903,14 +753,10 @@ fn on_window_event( } } WindowEvent::Focused(focused) => window.emit( - &if *focused { + if *focused { WINDOW_FOCUS_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")) } else { WINDOW_BLUR_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")) }, Some(()), )?, @@ -919,9 +765,7 @@ fn on_window_event( new_inner_size, .. } => window.emit( - &WINDOW_SCALE_FACTOR_CHANGED_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")), + WINDOW_SCALE_FACTOR_CHANGED_EVENT, Some(ScaleFactorChanged { scale_factor: *scale_factor, size: *new_inner_size, @@ -940,11 +784,6 @@ struct ScaleFactorChanged { } #[cfg(feature = "menu")] -fn on_menu_event(window: &Window

, event: &MenuEvent) -> crate::Result<()> { - window.emit( - &MENU_EVENT - .parse() - .unwrap_or_else(|_| panic!("unhandled event")), - Some(event.menu_item_id.clone()), - ) +fn on_menu_event(window: &Window, event: &MenuEvent) -> crate::Result<()> { + window.emit(MENU_EVENT, Some(event.menu_item_id.clone())) } diff --git a/core/tauri/src/plugin.rs b/core/tauri/src/plugin.rs index 0788c658f..e3ad4d5e4 100644 --- a/core/tauri/src/plugin.rs +++ b/core/tauri/src/plugin.rs @@ -4,21 +4,23 @@ //! Extend Tauri functionality. -use crate::{api::config::PluginConfig, App, Invoke, PageLoadPayload, Params, Window}; +use crate::{api::config::PluginConfig, runtime::Runtime, App, Invoke, PageLoadPayload, Window}; use serde_json::Value as JsonValue; use std::collections::HashMap; +use tauri_macros::default_runtime; + /// The plugin result type. pub type Result = std::result::Result>; /// The plugin interface. -pub trait Plugin: Send { +pub trait Plugin: Send { /// The plugin name. Used as key on the plugin config object. fn name(&self) -> &'static str; /// Initialize the plugin. #[allow(unused_variables)] - fn initialize(&mut self, app: &App

, config: JsonValue) -> Result<()> { + fn initialize(&mut self, app: &App, config: JsonValue) -> Result<()> { Ok(()) } @@ -33,25 +35,24 @@ pub trait Plugin: Send { /// Callback invoked when the webview is created. #[allow(unused_variables)] - fn created(&mut self, window: Window

) {} + fn created(&mut self, window: Window) {} /// Callback invoked when the webview performs a navigation. #[allow(unused_variables)] - fn on_page_load(&mut self, window: Window

, payload: PageLoadPayload) {} + fn on_page_load(&mut self, window: Window, payload: PageLoadPayload) {} /// Add invoke_handler API extension commands. #[allow(unused_variables)] - fn extend_api(&mut self, invoke: Invoke

) {} + fn extend_api(&mut self, invoke: Invoke) {} } -crate::manager::default_args! { - /// Plugin collection type. - pub(crate) struct PluginStore { - store: HashMap<&'static str, Box>>, - } +/// Plugin collection type. +#[default_runtime(crate::Wry, wry)] +pub(crate) struct PluginStore { + store: HashMap<&'static str, Box>>, } -impl Default for PluginStore

{ +impl Default for PluginStore { fn default() -> Self { Self { store: HashMap::new(), @@ -59,16 +60,16 @@ impl Default for PluginStore

{ } } -impl PluginStore

{ +impl PluginStore { /// Adds a plugin to the store. /// /// Returns `true` if a plugin with the same name is already in the store. - pub fn register + 'static>(&mut self, plugin: Plug) -> bool { + pub fn register + 'static>(&mut self, plugin: P) -> bool { self.store.insert(plugin.name(), Box::new(plugin)).is_some() } /// Initializes all plugins in the store. - pub(crate) fn initialize(&mut self, app: &App

, config: &PluginConfig) -> crate::Result<()> { + pub(crate) fn initialize(&mut self, app: &App, config: &PluginConfig) -> crate::Result<()> { self.store.values_mut().try_for_each(|plugin| { plugin .initialize( @@ -91,7 +92,7 @@ impl PluginStore

{ } /// Runs the created hook for all plugins in the store. - pub(crate) fn created(&mut self, window: Window

) { + pub(crate) fn created(&mut self, window: Window) { self .store .values_mut() @@ -99,14 +100,14 @@ impl PluginStore

{ } /// Runs the on_page_load hook for all plugins in the store. - pub(crate) fn on_page_load(&mut self, window: Window

, payload: PageLoadPayload) { + pub(crate) fn on_page_load(&mut self, window: Window, payload: PageLoadPayload) { self .store .values_mut() .for_each(|plugin| plugin.on_page_load(window.clone(), payload.clone())) } - pub(crate) fn extend_api(&mut self, mut invoke: Invoke

) { + pub(crate) fn extend_api(&mut self, mut invoke: Invoke) { let command = invoke.message.command.replace("plugin:", ""); let mut tokens = command.split('|'); // safe to unwrap: split always has a least one item diff --git a/core/tauri/src/state.rs b/core/tauri/src/state.rs index 0127757cc..8d010b567 100644 --- a/core/tauri/src/state.rs +++ b/core/tauri/src/state.rs @@ -2,8 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::command::{CommandArg, CommandItem}; -use crate::{InvokeError, Params}; +use crate::{ + command::{CommandArg, CommandItem}, + runtime::Runtime, + InvokeError, +}; use state::Container; /// A guard for a state value. @@ -34,9 +37,9 @@ impl Clone for State<'_, T> { } } -impl<'r, 'de: 'r, T: Send + Sync + 'static, P: Params> CommandArg<'de, P> for State<'r, T> { +impl<'r, 'de: 'r, T: Send + Sync + 'static, R: Runtime> CommandArg<'de, R> for State<'r, T> { /// Grabs the [`State`] from the [`CommandItem`]. This will never fail. - fn from_command(command: CommandItem<'de, P>) -> Result { + fn from_command(command: CommandItem<'de, R>) -> Result { Ok(command.message.state_ref().get()) } } diff --git a/core/tauri/src/updater/mod.rs b/core/tauri/src/updater/mod.rs index 95a52ed3d..f880301d0 100644 --- a/core/tauri/src/updater/mod.rs +++ b/core/tauri/src/updater/mod.rs @@ -332,14 +332,14 @@ mod error; pub use self::error::Error; -use crate::manager::tauri_event; use crate::{ api::{ config::UpdaterConfig, dialog::{ask, AskResponse}, process::restart, }, - Params, Window, + runtime::Runtime, + Window, }; /// Check for new updates @@ -376,10 +376,10 @@ struct UpdateManifest { } /// Check if there is any new update with builtin dialog. -pub(crate) async fn check_update_with_dialog( +pub(crate) async fn check_update_with_dialog( updater_config: UpdaterConfig, package_info: crate::api::PackageInfo, - window: Window

, + window: Window, ) { if let Some(endpoints) = updater_config.endpoints.clone() { // check updates @@ -418,106 +418,96 @@ pub(crate) async fn check_update_with_dialog( /// Experimental listener /// This function should be run on the main thread once. -pub(crate) fn listener( +pub(crate) fn listener( updater_config: UpdaterConfig, package_info: crate::api::PackageInfo, - window: &Window

, + window: &Window, ) { let isolated_window = window.clone(); // Wait to receive the event `"tauri://update"` - window.listen( - EVENT_CHECK_UPDATE - .parse::() - .unwrap_or_else(|_| panic!("bad label")), - move |_msg| { - let window = isolated_window.clone(); - let package_info = package_info.clone(); + window.listen(EVENT_CHECK_UPDATE, move |_msg| { + let window = isolated_window.clone(); + let package_info = package_info.clone(); - // prepare our endpoints - let endpoints = updater_config - .endpoints - .as_ref() - .expect("Something wrong with endpoints") - .clone(); + // prepare our endpoints + let endpoints = updater_config + .endpoints + .as_ref() + .expect("Something wrong with endpoints") + .clone(); - let pubkey = updater_config.pubkey.clone(); + let pubkey = updater_config.pubkey.clone(); - // check updates - crate::async_runtime::spawn(async move { - let window = window.clone(); - let window_isolation = window.clone(); - let pubkey = pubkey.clone(); + // check updates + crate::async_runtime::spawn(async move { + let window = window.clone(); + let window_isolation = window.clone(); + let pubkey = pubkey.clone(); - match self::core::builder() - .urls(&endpoints[..]) - .current_version(&package_info.version) - .build() - .await - { - Ok(updater) => { - // send notification if we need to update - if updater.should_update { - let body = updater.body.clone().unwrap_or_else(|| String::from("")); + match self::core::builder() + .urls(&endpoints[..]) + .current_version(&package_info.version) + .build() + .await + { + Ok(updater) => { + // send notification if we need to update + if updater.should_update { + let body = updater.body.clone().unwrap_or_else(|| String::from("")); - // Emit `tauri://update-available` - let _ = window.emit( - &tauri_event::(EVENT_UPDATE_AVAILABLE), - Some(UpdateManifest { - body, - date: updater.date.clone(), - version: updater.version.clone(), - }), - ); + // Emit `tauri://update-available` + let _ = window.emit( + EVENT_UPDATE_AVAILABLE, + Some(UpdateManifest { + body, + date: updater.date.clone(), + version: updater.version.clone(), + }), + ); - // Listen for `tauri://update-install` - window.once( - EVENT_INSTALL_UPDATE - .parse::() - .unwrap_or_else(|_| panic!("bad label")), - move |_msg| { - let window = window_isolation.clone(); - let updater = updater.clone(); - let pubkey = pubkey.clone(); + // Listen for `tauri://update-install` + window.once(EVENT_INSTALL_UPDATE, move |_msg| { + let window = window_isolation.clone(); + let updater = updater.clone(); + let pubkey = pubkey.clone(); - // Start installation - crate::async_runtime::spawn(async move { - // emit {"status": "PENDING"} - send_status_update(window.clone(), EVENT_STATUS_PENDING, None); + // Start installation + crate::async_runtime::spawn(async move { + // emit {"status": "PENDING"} + send_status_update(window.clone(), EVENT_STATUS_PENDING, None); - // Launch updater download process - // macOS we display the `Ready to restart dialog` asking to restart - // Windows is closing the current App and launch the downloaded MSI when ready (the process stop here) - // Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here) - let update_result = updater.clone().download_and_install(pubkey.clone()).await; + // Launch updater download process + // macOS we display the `Ready to restart dialog` asking to restart + // Windows is closing the current App and launch the downloaded MSI when ready (the process stop here) + // Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here) + let update_result = updater.clone().download_and_install(pubkey.clone()).await; - if let Err(err) = update_result { - // emit {"status": "ERROR", "error": "The error message"} - send_status_update(window.clone(), EVENT_STATUS_ERROR, Some(err.to_string())); - } else { - // emit {"status": "DONE"} - send_status_update(window.clone(), EVENT_STATUS_SUCCESS, None); - } - }) - }, - ); - } else { - send_status_update(window.clone(), EVENT_STATUS_UPTODATE, None); - } - } - Err(e) => { - send_status_update(window.clone(), EVENT_STATUS_ERROR, Some(e.to_string())); + if let Err(err) = update_result { + // emit {"status": "ERROR", "error": "The error message"} + send_status_update(window.clone(), EVENT_STATUS_ERROR, Some(err.to_string())); + } else { + // emit {"status": "DONE"} + send_status_update(window.clone(), EVENT_STATUS_SUCCESS, None); + } + }) + }); + } else { + send_status_update(window.clone(), EVENT_STATUS_UPTODATE, None); } } - }) - }, - ); + Err(e) => { + send_status_update(window.clone(), EVENT_STATUS_ERROR, Some(e.to_string())); + } + } + }) + }); } // Send a status update via `tauri://update-status` event. -fn send_status_update(window: Window

, status: &str, error: Option) { +fn send_status_update(window: Window, status: &str, error: Option) { let _ = window.emit( - &tauri_event::(EVENT_STATUS_UPDATE), + EVENT_STATUS_UPDATE, Some(StatusEvent { error, status: String::from(status), diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 79992e4f2..b68a0f985 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -18,13 +18,12 @@ use crate::{ manager::WindowManager, runtime::{ monitor::Monitor as RuntimeMonitor, - tag::{TagRef, ToJsString}, webview::{InvokePayload, WebviewAttributes, WindowBuilder}, window::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, DetachedWindow, PendingWindow, WindowEvent, }, - Dispatch, Icon, Params, Runtime, UserAttentionType, + Dispatch, Icon, Runtime, UserAttentionType, }, sealed::ManagerBase, sealed::RuntimeOrDispatch, @@ -33,10 +32,9 @@ use crate::{ use serde::Serialize; -use std::{ - borrow::Borrow, - hash::{Hash, Hasher}, -}; +use tauri_macros::default_runtime; + +use std::hash::{Hash, Hasher}; /// Monitor descriptor. #[derive(Debug, Clone, Serialize)] @@ -83,21 +81,20 @@ impl Monitor { } // TODO: expand these docs since this is a pretty important type -crate::manager::default_args! { - /// A webview window managed by Tauri. - /// - /// This type also implements [`Manager`] which allows you to manage other windows attached to - /// the same application. - pub struct Window { - /// The webview window created by the runtime. - window: DetachedWindow

, - /// The manager to associate this webview window with. - manager: WindowManager

, - pub(crate) app_handle: AppHandle

, - } +/// A webview window managed by Tauri. +/// +/// This type also implements [`Manager`] which allows you to manage other windows attached to +/// the same application. +#[default_runtime(crate::Wry, wry)] +pub struct Window { + /// The webview window created by the runtime. + window: DetachedWindow, + /// The manager to associate this webview window with. + manager: WindowManager, + pub(crate) app_handle: AppHandle, } -impl Clone for Window

{ +impl Clone for Window { fn clone(&self) -> Self { Self { window: self.window.clone(), @@ -107,49 +104,49 @@ impl Clone for Window

{ } } -impl Hash for Window

{ +impl Hash for Window { /// Only use the [`Window`]'s label to represent its hash. fn hash(&self, state: &mut H) { self.window.label.hash(state) } } -impl Eq for Window

{} -impl PartialEq for Window

{ +impl Eq for Window {} +impl PartialEq for Window { /// Only use the [`Window`]'s label to compare equality. fn eq(&self, other: &Self) -> bool { self.window.label.eq(&other.window.label) } } -impl Manager

for Window

{} -impl ManagerBase

for Window

{ - fn manager(&self) -> &WindowManager

{ +impl Manager for Window {} +impl ManagerBase for Window { + fn manager(&self) -> &WindowManager { &self.manager } - fn app_handle(&self) -> AppHandle

{ - self.app_handle.clone() + fn runtime(&self) -> RuntimeOrDispatch<'_, R> { + RuntimeOrDispatch::Dispatch(self.dispatcher()) } - fn runtime(&self) -> RuntimeOrDispatch<'_, P> { - RuntimeOrDispatch::Dispatch(self.dispatcher()) + fn app_handle(&self) -> AppHandle { + self.app_handle.clone() } } -impl<'de, P: Params> CommandArg<'de, P> for Window

{ +impl<'de, R: Runtime> CommandArg<'de, R> for Window { /// Grabs the [`Window`] from the [`CommandItem`]. This will never fail. - fn from_command(command: CommandItem<'de, P>) -> Result { + fn from_command(command: CommandItem<'de, R>) -> Result { Ok(command.message.window()) } } -impl Window

{ +impl Window { /// Create a new window that is attached to the manager. pub(crate) fn new( - manager: WindowManager

, - window: DetachedWindow

, - app_handle: AppHandle

, + manager: WindowManager, + window: DetachedWindow, + app_handle: AppHandle, ) -> Self { Self { window, @@ -161,21 +158,21 @@ impl Window

{ /// Creates a new webview window. pub fn create_window( &mut self, - label: P::Label, + label: String, url: WindowUrl, setup: F, - ) -> crate::Result> + ) -> crate::Result> where F: FnOnce( - <::Dispatcher as Dispatch>::WindowBuilder, + ::WindowBuilder, WebviewAttributes, ) -> ( - <::Dispatcher as Dispatch>::WindowBuilder, + ::WindowBuilder, WebviewAttributes, ), { let (window_builder, webview_attributes) = setup( - <::Dispatcher as Dispatch>::WindowBuilder::new(), + ::WindowBuilder::new(), WebviewAttributes::new(url), ); self.create_new_window(PendingWindow::new( @@ -186,7 +183,7 @@ impl Window

{ } /// The current window's dispatcher. - pub(crate) fn dispatcher(&self) -> ::Dispatcher { + pub(crate) fn dispatcher(&self) -> R::Dispatcher { self.window.dispatcher.clone() } @@ -238,21 +235,16 @@ impl Window

{ } /// The label of this window. - pub fn label(&self) -> &P::Label { + pub fn label(&self) -> &str { &self.window.label } /// Emits an event to the current window. - pub fn emit(&self, event: &E, payload: S) -> crate::Result<()> - where - P::Event: Borrow, - E: TagRef, - S: Serialize, - { + pub fn emit(&self, event: &str, payload: S) -> crate::Result<()> { self.eval(&format!( "window['{}']({{event: {}, payload: {}}}, '{}')", self.manager.event_emit_function_name(), - event.to_js_string()?, + serde_json::to_string(event)?, serde_json::to_value(payload)?, self.manager.generate_salt(), ))?; @@ -261,17 +253,12 @@ impl Window

{ } /// Emits an event on all windows except this one. - pub fn emit_others(&self, event: &E, payload: S) -> crate::Result<()> - where - P::Event: Borrow, - E: TagRef, - S: Serialize + Clone, - { + pub fn emit_others(&self, event: &str, payload: S) -> crate::Result<()> { self.manager.emit_filter(event, payload, |w| w != self) } /// Listen to an event on this window. - pub fn listen, F>(&self, event: E, handler: F) -> EventHandler + pub fn listen(&self, event: impl Into, handler: F) -> EventHandler where F: Fn(Event) + Send + 'static, { @@ -280,7 +267,7 @@ impl Window

{ } /// Listen to a an event on this window a single time. - pub fn once, F>(&self, event: E, handler: F) -> EventHandler + pub fn once(&self, event: impl Into, handler: F) -> EventHandler where F: Fn(Event) + Send + 'static, { @@ -289,11 +276,7 @@ impl Window

{ } /// Triggers an event on this window. - pub fn trigger(&self, event: &E, data: Option) - where - P::Event: Borrow, - E: TagRef, - { + pub fn trigger(&self, event: &str, data: Option) { let label = self.window.label.clone(); self.manager.trigger(event, Some(label), data) } @@ -311,7 +294,7 @@ impl Window

{ /// Registers a menu event listener. #[cfg(feature = "menu")] #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] - pub fn on_menu_event) + Send + 'static>(&self, f: F) -> uuid::Uuid { + pub fn on_menu_event(&self, f: F) -> uuid::Uuid { let menu_ids = self.manager.menu_ids(); self.window.dispatcher.on_menu_event(move |event| { f(MenuEvent { @@ -324,7 +307,7 @@ impl Window

{ /// Gets a handle to the window menu. #[cfg(feature = "menu")] - pub fn menu_handle(&self) -> MenuHandle

{ + pub fn menu_handle(&self) -> MenuHandle { MenuHandle { ids: self.manager.menu_ids(), dispatcher: self.dispatcher(), diff --git a/core/tauri/src/window/menu.rs b/core/tauri/src/window/menu.rs index d01c84468..2fdfb986b 100644 --- a/core/tauri/src/window/menu.rs +++ b/core/tauri/src/window/menu.rs @@ -2,37 +2,38 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::{ - runtime::{menu::MenuUpdate, Dispatch, MenuId, Runtime}, - Params, +use crate::runtime::{ + menu::{MenuHash, MenuId, MenuIdRef, MenuUpdate}, + Dispatch, Runtime, }; +use tauri_macros::default_runtime; + use std::collections::HashMap; /// The window menu event. #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] #[derive(Debug, Clone)] -pub struct MenuEvent { - pub(crate) menu_item_id: I, +pub struct MenuEvent { + pub(crate) menu_item_id: MenuId, } #[cfg(feature = "menu")] -impl MenuEvent { +impl MenuEvent { /// The menu item id. - pub fn menu_item_id(&self) -> &I { + pub fn menu_item_id(&self) -> MenuIdRef<'_> { &self.menu_item_id } } -crate::manager::default_args! { - /// A handle to a system tray. Allows updating the context menu items. - pub struct MenuHandle { - pub(crate) ids: HashMap, - pub(crate) dispatcher: ::Dispatcher, - } +/// A handle to a system tray. Allows updating the context menu items. +#[default_runtime(crate::Wry, wry)] +pub struct MenuHandle { + pub(crate) ids: HashMap, + pub(crate) dispatcher: R::Dispatcher, } -impl Clone for MenuHandle

{ +impl Clone for MenuHandle { fn clone(&self) -> Self { Self { ids: self.ids.clone(), @@ -41,15 +42,14 @@ impl Clone for MenuHandle

{ } } -crate::manager::default_args! { - /// A handle to a system tray menu item. - pub struct MenuItemHandle { - id: u16, - dispatcher: ::Dispatcher, - } +/// A handle to a system tray menu item. +#[default_runtime(crate::Wry, wry)] +pub struct MenuItemHandle { + id: u16, + dispatcher: R::Dispatcher, } -impl Clone for MenuItemHandle

{ +impl Clone for MenuItemHandle { fn clone(&self) -> Self { Self { id: self.id, @@ -58,9 +58,9 @@ impl Clone for MenuItemHandle

{ } } -impl MenuHandle

{ +impl MenuHandle { /// Gets a handle to the menu item that has the specified `id`. - pub fn get_item(&self, id: &P::MenuId) -> MenuItemHandle

{ + pub fn get_item(&self, id: MenuIdRef<'_>) -> MenuItemHandle { for (raw, item_id) in self.ids.iter() { if item_id == id { return MenuItemHandle { @@ -107,7 +107,7 @@ impl MenuHandle

{ } } -impl MenuItemHandle

{ +impl MenuItemHandle { /// Modifies the enabled state of the menu item. pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> { self diff --git a/docs/usage/guides/plugin.md b/docs/usage/guides/plugin.md index 52c82c458..380ea8711 100644 --- a/docs/usage/guides/plugin.md +++ b/docs/usage/guides/plugin.md @@ -17,10 +17,10 @@ Plugins allow you to hook into the Tauri application lifecycle and introduce new To write a plugin you just need to implement the `tauri::plugin::Plugin` trait: ```rust -use tauri::{plugin::{Plugin, Result as PluginResult}, PageLoadPayload, Params, Window, Invoke, App}; +use tauri::{plugin::{Plugin, Result as PluginResult}, runtime::Runtime, PageLoadPayload, Window, Invoke, App}; -struct MyAwesomePlugin { - invoke_handler: Box) + Send + Sync>, +struct MyAwesomePlugin { + invoke_handler: Box) + Send + Sync>, // plugin state, configuration fields } @@ -34,7 +34,7 @@ fn initialize() {} // this will be accessible with `invoke('plugin:awesome|do_something')`. fn do_something() {} -impl MyAwesomePlugin

{ +impl MyAwesomePlugin { // you can add configuration fields here, // see https://doc.rust-lang.org/1.0.0/style/ownership/builders.html pub fn new() -> Self { @@ -44,7 +44,7 @@ impl MyAwesomePlugin

{ } } -impl Plugin

for MyAwesomePlugin

{ +impl Plugin for MyAwesomePlugin { /// The plugin name. Must be defined and used on the `invoke` calls. fn name(&self) -> &'static str { "awesome" @@ -59,18 +59,18 @@ impl Plugin

for MyAwesomePlugin

{ } /// initialize plugin with the config provided on `tauri.conf.json > plugins > $yourPluginName` or the default value. - fn initialize(&mut self, app: &App

, config: serde_json::Value) -> PluginResult<()> { + fn initialize(&mut self, app: &App, config: serde_json::Value) -> PluginResult<()> { Ok(()) } /// Callback invoked when the Window is created. - fn created(&mut self, window: Window

) {} + fn created(&mut self, window: Window) {} /// Callback invoked when the webview performs a navigation. - fn on_page_load(&mut self, window: Window

, payload: PageLoadPayload) {} + fn on_page_load(&mut self, window: Window, payload: PageLoadPayload) {} /// Extend the invoke handler. - fn extend_api(&mut self, message: Invoke

) { + fn extend_api(&mut self, message: Invoke) { (self.invoke_handler)(message) } } diff --git a/examples/api/src-tauri/src/main.rs b/examples/api/src-tauri/src/main.rs index 5b5d4cc40..aac189109 100644 --- a/examples/api/src-tauri/src/main.rs +++ b/examples/api/src-tauri/src/main.rs @@ -52,8 +52,8 @@ fn main() { .system_tray( SystemTray::new().with_menu( SystemTrayMenu::new() - .add_item(CustomMenuItem::new("toggle".into(), "Toggle")) - .add_item(CustomMenuItem::new("new".into(), "New window")), + .add_item(CustomMenuItem::new("toggle", "Toggle")) + .add_item(CustomMenuItem::new("new", "New window")), ), ) .on_system_tray_event(|app, event| match event { diff --git a/examples/api/src-tauri/src/menu.rs b/examples/api/src-tauri/src/menu.rs index 09d84d8f9..a6cc9a62a 100644 --- a/examples/api/src-tauri/src/menu.rs +++ b/examples/api/src-tauri/src/menu.rs @@ -4,12 +4,12 @@ use tauri::{CustomMenuItem, Menu, MenuItem, Submenu}; -pub fn get_menu() -> Menu { +pub fn get_menu() -> Menu { #[allow(unused_mut)] let mut disable_item = - CustomMenuItem::new("disable-menu".into(), "Disable menu").accelerator("CmdOrControl+D"); + CustomMenuItem::new("disable-menu", "Disable menu").accelerator("CmdOrControl+D"); #[allow(unused_mut)] - let mut test_item = CustomMenuItem::new("test".into(), "Test").accelerator("CmdOrControl+T"); + let mut test_item = CustomMenuItem::new("test", "Test").accelerator("CmdOrControl+T"); #[cfg(target_os = "macos")] { disable_item = disable_item.native_image(tauri::NativeImage::MenuOnState); @@ -25,7 +25,7 @@ pub fn get_menu() -> Menu { let test_menu = Menu::new() .add_item(CustomMenuItem::new( - "selected/disabled".into(), + "selected/disabled", "Selected and disabled", )) .add_native_item(MenuItem::Separator) diff --git a/examples/commands/src-tauri/src/main.rs b/examples/commands/src-tauri/src/main.rs index cdcdb296a..b8e9346c5 100644 --- a/examples/commands/src-tauri/src/main.rs +++ b/examples/commands/src-tauri/src/main.rs @@ -16,7 +16,7 @@ mod commands; use commands::{cmd, invoke, message, resolver}; use serde::Deserialize; -use tauri::{command, Params, State, Window}; +use tauri::{command, State, Window}; #[derive(Debug)] pub struct MyState { @@ -125,7 +125,7 @@ async fn async_stateful_command_with_result( // Non-Ident command function arguments #[command] -fn command_arguments_wild(_: Window

) { +fn command_arguments_wild(_: Window) { println!("we saw the wildcard!") } diff --git a/examples/params/index.html b/examples/params/index.html deleted file mode 100644 index 96ec47282..000000000 --- a/examples/params/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - Params - - -

Simple custom `Params` types check.

- - diff --git a/examples/params/package.json b/examples/params/package.json deleted file mode 100644 index 305ea3d20..000000000 --- a/examples/params/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "params", - "version": "1.0.0", - "scripts": { - "tauri": "node ../../tooling/cli.js/bin/tauri" - } -} diff --git a/examples/params/src-tauri/.gitignore b/examples/params/src-tauri/.gitignore deleted file mode 100644 index 270a92d27..000000000 --- a/examples/params/src-tauri/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ -WixTools - -# These are backup files generated by rustfmt -**/*.rs.bk - -config.json -bundle.json diff --git a/examples/params/src-tauri/.license_template b/examples/params/src-tauri/.license_template deleted file mode 100644 index 9601f8a1b..000000000 --- a/examples/params/src-tauri/.license_template +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/examples/params/src-tauri/Cargo.toml b/examples/params/src-tauri/Cargo.toml deleted file mode 100644 index f3c64e767..000000000 --- a/examples/params/src-tauri/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "params" -version = "0.1.0" -description = "A simple Tauri Application showcasing custom Params types" -edition = "2018" - -[build-dependencies] -tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ] } - -[dependencies] -serde = { version = "1", features = [ "derive" ] } -tauri = { path = "../../../core/tauri", features = ["api-all"] } - -[features] -default = [ "custom-protocol" ] -custom-protocol = [ "tauri/custom-protocol" ] diff --git a/examples/params/src-tauri/build.rs b/examples/params/src-tauri/build.rs deleted file mode 100644 index 2ad1cb4e6..000000000 --- a/examples/params/src-tauri/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use tauri_build::{try_build, Attributes, WindowsAttributes}; - -fn main() { - if let Err(error) = try_build( - Attributes::new() - .windows_attributes(WindowsAttributes::new().window_icon_path("../../.icons/icon.ico")), - ) { - panic!("error found during tauri-build: {}", error); - } -} diff --git a/examples/params/src-tauri/src/main.rs b/examples/params/src-tauri/src/main.rs deleted file mode 100644 index c5575911c..000000000 --- a/examples/params/src-tauri/src/main.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -#![cfg_attr( - all(not(debug_assertions), target_os = "windows"), - windows_subsystem = "windows" -)] -#![allow( - // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 - clippy::nonstandard_macro_braces, -)] - -use serde::Serialize; -use std::fmt; -use std::str::FromStr; -use tauri::{command, Wry}; - -trait Params: - tauri::Params -{ -} -impl

Params for P where - P: tauri::Params -{ -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub enum Event { - Foo, - Bar, - Unknown(String), -} - -impl fmt::Display for Event { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Self::Foo => "foo", - Self::Bar => "bar", - Self::Unknown(s) => s, - }) - } -} - -impl FromStr for Event { - type Err = std::convert::Infallible; - - fn from_str(s: &str) -> Result { - Ok(match s { - "foo" => Self::Foo, - "bar" => Self::Bar, - other => Self::Unknown(other.to_string()), - }) - } -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub enum Window { - Main, -} - -impl fmt::Display for Window { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Self::Main => "main", - }) - } -} - -impl FromStr for Window { - type Err = Box; - - fn from_str(s: &str) -> Result { - if s == "main" { - Ok(Self::Main) - } else { - Err(format!("only expect main window label, found: {}", s).into()) - } - } -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize)] -pub enum Menu { - MenuFoo, - MenuBar, -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize)] -pub enum SystemMenu { - SystemFoo, - SystemBar, -} - -#[command] -fn log_window_label(window: tauri::Window) { - dbg!(window.label()); -} - -#[command] -fn send_foo(window: tauri::Window) { - window - .emit(&Event::Foo, ()) - .expect("couldn't send Event::Foo"); -} - -fn main() { - tauri::Builder::::new() - .invoke_handler(tauri::generate_handler![log_window_label, send_foo]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} diff --git a/examples/params/src-tauri/tauri.conf.json b/examples/params/src-tauri/tauri.conf.json deleted file mode 100644 index 3ee0163e9..000000000 --- a/examples/params/src-tauri/tauri.conf.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "build": { - "distDir": ["../index.html"], - "devPath": ["../index.html"], - "beforeDevCommand": "", - "beforeBuildCommand": "" - }, - "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": [], - "useBootstrapper": false - }, - "macOS": { - "frameworks": [], - "minimumSystemVersion": "", - "useBootstrapper": false, - "exceptionDomain": "" - } - }, - "allowlist": { - "all": true - }, - "windows": [ - { - "title": "Welcome to Tauri!", - "width": 800, - "height": 600, - "resizable": true, - "fullscreen": false - } - ], - "security": { - "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'" - }, - "updater": { - "active": false - } - } -} diff --git a/examples/splashscreen/src-tauri/src/main.rs b/examples/splashscreen/src-tauri/src/main.rs index 00a0cc2dd..2e211cc0b 100644 --- a/examples/splashscreen/src-tauri/src/main.rs +++ b/examples/splashscreen/src-tauri/src/main.rs @@ -48,18 +48,18 @@ mod rust { #[cfg(feature = "ui")] mod ui { use std::sync::{Arc, Mutex}; - use tauri::{Manager, Params, State, Window}; + use tauri::{Manager, State, Window}; // wrappers around each Window // we use a dedicated type because Tauri can only manage a single instance of a given type - struct SplashscreenWindow(Arc>>); - struct MainWindow(Arc>>); + struct SplashscreenWindow(Arc>); + struct MainWindow(Arc>); #[tauri::command] - fn close_splashscreen( - _: Window

, // force inference of P - splashscreen: State>, - main: State>, + fn close_splashscreen( + _: Window, // force inference of P + splashscreen: State, + main: State, ) { // Close splashscreen splashscreen.0.lock().unwrap().close().unwrap(); diff --git a/tooling/cli.js/test/jest/fixtures/app/src-tauri/src/main.rs b/tooling/cli.js/test/jest/fixtures/app/src-tauri/src/main.rs index be923f7ff..478c272f7 100644 --- a/tooling/cli.js/test/jest/fixtures/app/src-tauri/src/main.rs +++ b/tooling/cli.js/test/jest/fixtures/app/src-tauri/src/main.rs @@ -1,5 +1,5 @@ #[tauri::command(with_window)] -fn exit(window: tauri::Window

) { +fn exit(window: tauri::Window) { window.close().unwrap(); }