mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-28 13:34:18 +03:00
refactor(core): remove Params
and replace with strings (#2191)
* refactor(core): remove `Params` and replace with strings * add tauri-utils to changelog * update default runtime macro to accept type and feature * remove accidental default feature addition * remove changefile todo items that have no futher action * fix clippy warning * update changefile * finish change file * fix splashscreen example * fix markdown typo [skip ci] * remove final uses of `Params` * add license header to new runtime module in tauri-macros * update plugin guide to use runtime instead of params
This commit is contained in:
parent
074caa3247
commit
fd8fab507c
50
.changes/weak-typing.md
Normal file
50
.changes/weak-typing.md
Normal file
@ -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<String>` 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<AssetKey>` to become trait object
|
||||
safe.
|
@ -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",
|
||||
|
@ -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()
|
||||
}
|
||||
|
62
core/tauri-macros/src/runtime.rs
Normal file
62
core/tauri-macros/src/runtime.rs
Normal file
@ -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<Self> {
|
||||
let default_type = input.parse()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
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
|
||||
)
|
||||
}
|
@ -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<u16>,
|
||||
menu: Menu,
|
||||
}
|
||||
|
||||
// safe since `menu_items` are read only here
|
||||
@ -454,7 +454,7 @@ impl WindowBuilder for WindowBuilderWrapper {
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
fn menu<I: MenuId>(mut self, menu: Menu<I>) -> 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<P: Params<Runtime = Self::Runtime>>(
|
||||
fn create_window(
|
||||
&mut self,
|
||||
pending: PendingWindow<P>,
|
||||
) -> Result<DetachedWindow<P>> {
|
||||
pending: PendingWindow<Self::Runtime>,
|
||||
) -> Result<DetachedWindow<Self::Runtime>> {
|
||||
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<P: Params<Runtime = Self::Runtime>>(
|
||||
fn create_window(
|
||||
&self,
|
||||
pending: PendingWindow<P>,
|
||||
) -> Result<DetachedWindow<P>> {
|
||||
pending: PendingWindow<Self::Runtime>,
|
||||
) -> Result<DetachedWindow<Self::Runtime>> {
|
||||
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<P: Params<Runtime = Self>>(
|
||||
&self,
|
||||
pending: PendingWindow<P>,
|
||||
) -> Result<DetachedWindow<P>> {
|
||||
fn create_window(&self, pending: PendingWindow<Self>) -> Result<DetachedWindow<Self>> {
|
||||
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<I: MenuId>(&self, system_tray: SystemTray<I>) -> Result<Self::TrayHandler> {
|
||||
fn system_tray(&self, system_tray: SystemTray) -> Result<Self::TrayHandler> {
|
||||
let icon = system_tray
|
||||
.icon
|
||||
.expect("tray icon not set")
|
||||
@ -1904,10 +1901,10 @@ fn center_window(window: &Window) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_webview<P: Params<Runtime = Wry>>(
|
||||
fn create_webview(
|
||||
event_loop: &EventLoopWindowTarget<Message>,
|
||||
context: DispatcherContext,
|
||||
pending: PendingWindow<P>,
|
||||
pending: PendingWindow<Wry>,
|
||||
) -> Result<WebviewWrapper> {
|
||||
#[allow(unused_mut)]
|
||||
let PendingWindow {
|
||||
@ -1983,7 +1980,7 @@ fn create_webview<P: Params<Runtime = Wry>>(
|
||||
.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<P: Params<Runtime = Wry>>(
|
||||
}
|
||||
|
||||
/// Create a wry rpc handler from a tauri rpc handler.
|
||||
fn create_rpc_handler<P: Params<Runtime = Wry>>(
|
||||
fn create_rpc_handler(
|
||||
context: DispatcherContext,
|
||||
label: P::Label,
|
||||
handler: WebviewRpcHandler<P>,
|
||||
label: String,
|
||||
handler: WebviewRpcHandler<Wry>,
|
||||
) -> Box<dyn Fn(&Window, WryRpcRequest) -> Option<RpcResponse> + 'static> {
|
||||
Box::new(move |window, request| {
|
||||
handler(
|
||||
@ -2014,10 +2011,10 @@ fn create_rpc_handler<P: Params<Runtime = Wry>>(
|
||||
}
|
||||
|
||||
/// Create a wry file drop handler from a tauri file drop handler.
|
||||
fn create_file_drop_handler<P: Params<Runtime = Wry>>(
|
||||
fn create_file_drop_handler(
|
||||
context: DispatcherContext,
|
||||
label: P::Label,
|
||||
handler: FileDropHandler<P>,
|
||||
label: String,
|
||||
handler: FileDropHandler<Wry>,
|
||||
) -> Box<dyn Fn(&Window, WryFileDropEvent) -> bool + 'static> {
|
||||
Box::new(move |window, event| {
|
||||
handler(
|
||||
|
@ -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<NativeImage> for NativeImageWrapper {
|
||||
|
||||
pub struct MenuItemAttributesWrapper<'a>(pub WryMenuItemAttributes<'a>);
|
||||
|
||||
impl<'a, I: MenuId> From<&'a CustomMenuItem<I>> for MenuItemAttributesWrapper<'a> {
|
||||
fn from(item: &'a CustomMenuItem<I>) -> 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<SystemTrayMenuItem> for MenuItemWrapper {
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
pub fn convert_menu_id<I: MenuId>(mut new_menu: Menu<u16>, menu: Menu<I>) -> Menu<u16> {
|
||||
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<I: MenuId>(mut new_menu: Menu<u16>, menu: Menu<I>) -> Men
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
pub fn to_wry_menu(
|
||||
custom_menu_items: &mut HashMap<u16, WryCustomMenuItem>,
|
||||
menu: Menu<u16>,
|
||||
custom_menu_items: &mut HashMap<MenuHash, WryCustomMenuItem>,
|
||||
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<I: MenuId>(
|
||||
custom_menu_items: &mut HashMap<u16, WryCustomMenuItem>,
|
||||
menu: SystemTrayMenu<I>,
|
||||
pub fn to_wry_context_menu(
|
||||
custom_menu_items: &mut HashMap<MenuHash, WryCustomMenuItem>,
|
||||
menu: SystemTrayMenu,
|
||||
) -> WryContextMenu {
|
||||
let mut tray_menu = WryContextMenu::new();
|
||||
for item in menu.items {
|
||||
@ -272,12 +275,11 @@ pub fn to_wry_context_menu<I: MenuId>(
|
||||
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);
|
||||
|
@ -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<T> MenuId for T where T: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {}
|
||||
|
||||
#[cfg(feature = "system-tray")]
|
||||
#[non_exhaustive]
|
||||
pub struct SystemTray<I: MenuId> {
|
||||
pub struct SystemTray {
|
||||
pub icon: Option<Icon>,
|
||||
pub menu: Option<menu::SystemTrayMenu<I>>,
|
||||
pub menu: Option<menu::SystemTrayMenu>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "system-tray")]
|
||||
impl<I: MenuId> Default for SystemTray<I> {
|
||||
impl Default for SystemTray {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
icon: None,
|
||||
@ -55,13 +47,13 @@ impl<I: MenuId> Default for SystemTray<I> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "system-tray")]
|
||||
impl<I: MenuId> SystemTray<I> {
|
||||
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<I>> {
|
||||
pub fn menu(&self) -> Option<&menu::SystemTrayMenu> {
|
||||
self.menu.as_ref()
|
||||
}
|
||||
|
||||
@ -72,7 +64,7 @@ impl<I: MenuId> SystemTray<I> {
|
||||
}
|
||||
|
||||
/// Sets the menu to show when the system tray is right clicked.
|
||||
pub fn with_menu(mut self, menu: menu::SystemTrayMenu<I>) -> 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<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[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<Handle = Self>;
|
||||
/// Create a new webview window.
|
||||
fn create_window<P: Params<Runtime = Self::Runtime>>(
|
||||
fn create_window(
|
||||
&self,
|
||||
pending: PendingWindow<P>,
|
||||
) -> crate::Result<DetachedWindow<P>>;
|
||||
pending: PendingWindow<Self::Runtime>,
|
||||
) -> crate::Result<DetachedWindow<Self::Runtime>>;
|
||||
|
||||
#[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<P: Params<Runtime = Self>>(
|
||||
&self,
|
||||
pending: PendingWindow<P>,
|
||||
) -> crate::Result<DetachedWindow<P>>;
|
||||
fn create_window(&self, pending: PendingWindow<Self>) -> crate::Result<DetachedWindow<Self>>;
|
||||
|
||||
/// 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<I: MenuId>(&self, system_tray: SystemTray<I>) -> crate::Result<Self::TrayHandler>;
|
||||
fn system_tray(&self, system_tray: SystemTray) -> crate::Result<Self::TrayHandler>;
|
||||
|
||||
/// 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<UserAttentionType>) -> crate::Result<()>;
|
||||
|
||||
/// Create a new webview window.
|
||||
fn create_window<P: Params<Runtime = Self::Runtime>>(
|
||||
fn create_window(
|
||||
&mut self,
|
||||
pending: PendingWindow<P>,
|
||||
) -> crate::Result<DetachedWindow<P>>;
|
||||
pending: PendingWindow<Self::Runtime>,
|
||||
) -> crate::Result<DetachedWindow<Self::Runtime>>;
|
||||
|
||||
/// Updates the window resizable flag.
|
||||
fn set_resizable(&self, resizable: bool) -> crate::Result<()>;
|
||||
|
@ -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<I: MenuId> {
|
||||
pub items: Vec<MenuEntry<I>>,
|
||||
pub struct Menu {
|
||||
pub items: Vec<MenuEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct Submenu<I: MenuId> {
|
||||
pub struct Submenu {
|
||||
pub title: String,
|
||||
pub enabled: bool,
|
||||
pub inner: Menu<I>,
|
||||
pub inner: Menu,
|
||||
}
|
||||
|
||||
impl<I: MenuId> Submenu<I> {
|
||||
impl Submenu {
|
||||
/// Creates a new submenu with the given title and menu items.
|
||||
pub fn new<S: Into<String>>(title: S, menu: Menu<I>) -> Self {
|
||||
pub fn new<S: Into<String>>(title: S, menu: Menu) -> Self {
|
||||
Self {
|
||||
title: title.into(),
|
||||
enabled: true,
|
||||
@ -171,20 +176,20 @@ impl<I: MenuId> Submenu<I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: MenuId> Default for Menu<I> {
|
||||
impl Default for Menu {
|
||||
fn default() -> Self {
|
||||
Self { items: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: MenuId> Menu<I> {
|
||||
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<I>) -> Self {
|
||||
pub fn add_item(mut self, item: CustomMenuItem) -> Self {
|
||||
self.items.push(MenuEntry::CustomItem(item));
|
||||
self
|
||||
}
|
||||
@ -196,7 +201,7 @@ impl<I: MenuId> Menu<I> {
|
||||
}
|
||||
|
||||
/// Adds an entry with submenu.
|
||||
pub fn add_submenu(mut self, submenu: Submenu<I>) -> Self {
|
||||
pub fn add_submenu(mut self, submenu: Submenu) -> Self {
|
||||
self.items.push(MenuEntry::Submenu(submenu));
|
||||
self
|
||||
}
|
||||
@ -205,8 +210,9 @@ impl<I: MenuId> Menu<I> {
|
||||
/// A custom menu item.
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct CustomMenuItem<I: MenuId> {
|
||||
pub id: I,
|
||||
pub struct CustomMenuItem {
|
||||
pub id: MenuHash,
|
||||
pub id_str: MenuId,
|
||||
pub title: String,
|
||||
pub keyboard_accelerator: Option<String>,
|
||||
pub enabled: bool,
|
||||
@ -215,11 +221,13 @@ pub struct CustomMenuItem<I: MenuId> {
|
||||
pub native_image: Option<NativeImage>,
|
||||
}
|
||||
|
||||
impl<I: MenuId> CustomMenuItem<I> {
|
||||
impl CustomMenuItem {
|
||||
/// Create new custom menu item.
|
||||
pub fn new<T: Into<String>>(id: I, title: T) -> Self {
|
||||
pub fn new<I: Into<String>, T: Into<String>>(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<I: MenuId> CustomMenuItem<I> {
|
||||
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<I: MenuId> {
|
||||
pub items: Vec<SystemTrayMenuEntry<I>>,
|
||||
pub struct SystemTrayMenu {
|
||||
pub items: Vec<SystemTrayMenuEntry>,
|
||||
}
|
||||
|
||||
impl<I: MenuId> Default for SystemTrayMenu<I> {
|
||||
impl Default for SystemTrayMenu {
|
||||
fn default() -> Self {
|
||||
Self { items: Vec::new() }
|
||||
}
|
||||
@ -278,15 +285,15 @@ impl<I: MenuId> Default for SystemTrayMenu<I> {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct SystemTraySubmenu<I: MenuId> {
|
||||
pub struct SystemTraySubmenu {
|
||||
pub title: String,
|
||||
pub enabled: bool,
|
||||
pub inner: SystemTrayMenu<I>,
|
||||
pub inner: SystemTrayMenu,
|
||||
}
|
||||
|
||||
impl<I: MenuId> SystemTraySubmenu<I> {
|
||||
impl SystemTraySubmenu {
|
||||
/// Creates a new submenu with the given title and menu items.
|
||||
pub fn new<S: Into<String>>(title: S, menu: SystemTrayMenu<I>) -> Self {
|
||||
pub fn new<S: Into<String>>(title: S, menu: SystemTrayMenu) -> Self {
|
||||
Self {
|
||||
title: title.into(),
|
||||
enabled: true,
|
||||
@ -295,14 +302,14 @@ impl<I: MenuId> SystemTraySubmenu<I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: MenuId> SystemTrayMenu<I> {
|
||||
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<I>) -> Self {
|
||||
pub fn add_item(mut self, item: CustomMenuItem) -> Self {
|
||||
self.items.push(SystemTrayMenuEntry::CustomItem(item));
|
||||
self
|
||||
}
|
||||
@ -314,7 +321,7 @@ impl<I: MenuId> SystemTrayMenu<I> {
|
||||
}
|
||||
|
||||
/// Adds an entry with submenu.
|
||||
pub fn add_submenu(mut self, submenu: SystemTraySubmenu<I>) -> Self {
|
||||
pub fn add_submenu(mut self, submenu: SystemTraySubmenu) -> Self {
|
||||
self.items.push(SystemTrayMenuEntry::Submenu(submenu));
|
||||
self
|
||||
}
|
||||
@ -322,13 +329,13 @@ impl<I: MenuId> SystemTrayMenu<I> {
|
||||
|
||||
/// An entry on the system tray menu.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SystemTrayMenuEntry<I: MenuId> {
|
||||
pub enum SystemTrayMenuEntry {
|
||||
/// A custom item.
|
||||
CustomItem(CustomMenuItem<I>),
|
||||
CustomItem(CustomMenuItem),
|
||||
/// A native item.
|
||||
NativeItem(SystemTrayMenuItem),
|
||||
/// An entry with submenu.
|
||||
Submenu(SystemTraySubmenu<I>),
|
||||
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<I: MenuId> {
|
||||
pub enum MenuEntry {
|
||||
/// A custom item.
|
||||
CustomItem(CustomMenuItem<I>),
|
||||
CustomItem(CustomMenuItem),
|
||||
/// A native item.
|
||||
NativeItem(MenuItem),
|
||||
/// An entry with submenu.
|
||||
Submenu(Submenu<I>),
|
||||
Submenu(Submenu),
|
||||
}
|
||||
|
||||
/// A menu item, bound to a pre-defined action or `Custom` emit an event. Note that status bar only
|
||||
|
@ -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<Self, Self::Err> {
|
||||
/// 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<T, E: Debug> Tag for T where
|
||||
T: Hash + Eq + FromStr<Err = E> + 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<T: Tag>: Display + ToOwned<Owned = T> + PartialEq<T> + Eq + Hash
|
||||
where
|
||||
T: std::borrow::Borrow<Self>,
|
||||
{
|
||||
}
|
||||
|
||||
/// Automatically implement [`TagRef`] for all types that fit the requirements.
|
||||
impl<T: Tag, R> TagRef<T> for R
|
||||
where
|
||||
T: std::borrow::Borrow<R>,
|
||||
R: Display + ToOwned<Owned = T> + PartialEq<T> + 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<String>;
|
||||
}
|
||||
|
||||
impl<D: Display> ToJsString for D {
|
||||
/// Turn any [`Tag`] into the JavaScript representation of a string.
|
||||
fn to_js_string(&self) -> crate::Result<String> {
|
||||
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<String> {
|
||||
let tags: Vec<String> = tags.iter().map(ToString::to_string).collect();
|
||||
Ok(serde_json::to_string(&tags)?)
|
||||
}
|
@ -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<I: MenuId>(self, menu: Menu<I>) -> 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<P> = Box<dyn Fn(DetachedWindow<P>, RpcRequest) + Send>;
|
||||
pub type WebviewRpcHandler<R> = Box<dyn Fn(DetachedWindow<R>, 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<P> = Box<dyn Fn(FileDropEvent, DetachedWindow<P>) -> bool + Send>;
|
||||
pub type FileDropHandler<R> = Box<dyn Fn(FileDropEvent, DetachedWindow<R>) -> bool + Send>;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct InvokePayload {
|
||||
|
@ -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<P: Params> {
|
||||
pub struct PendingWindow<R: Runtime> {
|
||||
/// 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: <<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
pub window_builder: <R::Dispatcher as Dispatch>::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<WebviewRpcHandler<P>>,
|
||||
pub rpc_handler: Option<WebviewRpcHandler<R>>,
|
||||
|
||||
/// How to handle a file dropping onto the webview window.
|
||||
pub file_drop_handler: Option<FileDropHandler<P>>,
|
||||
pub file_drop_handler: Option<FileDropHandler<R>>,
|
||||
|
||||
/// The resolved URL to load on the webview.
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
impl<P: Params> PendingWindow<P> {
|
||||
impl<R: Runtime> PendingWindow<R> {
|
||||
/// Create a new [`PendingWindow`] with a label and starting url.
|
||||
pub fn new(
|
||||
window_builder: <<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
window_builder: <R::Dispatcher as Dispatch>::WindowBuilder,
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: P::Label,
|
||||
label: impl Into<String>,
|
||||
) -> 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<P: Params> PendingWindow<P> {
|
||||
pub fn with_config(
|
||||
window_config: WindowConfig,
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: P::Label,
|
||||
label: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
window_builder:
|
||||
<<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder>::with_config(
|
||||
window_config,
|
||||
),
|
||||
window_builder: <<R::Dispatcher as Dispatch>::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<P: Params> PendingWindow<P> {
|
||||
}
|
||||
|
||||
/// A webview window that is not yet managed by Tauri.
|
||||
pub struct DetachedWindow<P: Params> {
|
||||
pub struct DetachedWindow<R: Runtime> {
|
||||
/// Name of the window
|
||||
pub label: P::Label,
|
||||
pub label: String,
|
||||
|
||||
/// The [`Dispatch`](crate::Dispatch) associated with the window.
|
||||
pub dispatcher: <P::Runtime as Runtime>::Dispatcher,
|
||||
pub dispatcher: R::Dispatcher,
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for DetachedWindow<P> {
|
||||
impl<R: Runtime> Clone for DetachedWindow<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
label: self.label.clone(),
|
||||
@ -130,15 +127,15 @@ impl<P: Params> Clone for DetachedWindow<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Hash for DetachedWindow<P> {
|
||||
impl<R: Runtime> Hash for DetachedWindow<R> {
|
||||
/// Only use the [`DetachedWindow`]'s label to represent its hash.
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.label.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Eq for DetachedWindow<P> {}
|
||||
impl<P: Params> PartialEq for DetachedWindow<P> {
|
||||
impl<R: Runtime> Eq for DetachedWindow<R> {}
|
||||
impl<R: Runtime> PartialEq for DetachedWindow<R> {
|
||||
/// Only use the [`DetachedWindow`]'s label to compare equality.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.label.eq(&other.label)
|
||||
|
@ -76,7 +76,7 @@ impl<P: AsRef<Path>> From<P> 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<Key: Into<AssetKey>>(&self, key: Key) -> Option<Cow<'_, [u8]>>;
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>>;
|
||||
}
|
||||
|
||||
/// [`Assets`] implementation that only contains compile-time compressed and embedded assets.
|
||||
@ -92,10 +92,10 @@ impl EmbeddedAssets {
|
||||
}
|
||||
|
||||
impl Assets for EmbeddedAssets {
|
||||
fn get<Key: Into<AssetKey>>(&self, key: Key) -> Option<Cow<'_, [u8]>> {
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
|
||||
self
|
||||
.0
|
||||
.get(key.into().as_ref())
|
||||
.get(key.as_ref())
|
||||
.copied()
|
||||
.map(zstd::decode_all)
|
||||
.and_then(Result::ok)
|
||||
|
@ -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<P> = Box<dyn Fn(WindowMenuEvent<P>) + Send + Sync>;
|
||||
pub(crate) type GlobalWindowEventListener<P> = Box<dyn Fn(GlobalWindowEvent<P>) + Send + Sync>;
|
||||
pub(crate) type GlobalMenuEventListener<R> = Box<dyn Fn(WindowMenuEvent<R>) + Send + Sync>;
|
||||
pub(crate) type GlobalWindowEventListener<R> = Box<dyn Fn(GlobalWindowEvent<R>) + Send + Sync>;
|
||||
#[cfg(feature = "system-tray")]
|
||||
type SystemTrayEventListener<P> =
|
||||
Box<dyn Fn(&AppHandle<P>, tray::SystemTrayEvent<<P as Params>::SystemTrayMenuId>) + Send + Sync>;
|
||||
type SystemTrayEventListener<R> = Box<dyn Fn(&AppHandle<R>, tray::SystemTrayEvent) + Send + Sync>;
|
||||
|
||||
/// Api exposed on the `CloseRequested` event.
|
||||
pub struct CloseRequestApi(Sender<bool>);
|
||||
@ -61,60 +60,58 @@ impl CloseRequestApi {
|
||||
|
||||
/// An application event, triggered from the event loop.
|
||||
#[non_exhaustive]
|
||||
pub enum Event<P: Params> {
|
||||
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<P: Params> {
|
||||
pub(crate) menu_item_id: P::MenuId,
|
||||
pub(crate) window: Window<P>,
|
||||
}
|
||||
/// 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<R: Runtime> {
|
||||
pub(crate) menu_item_id: MenuId,
|
||||
pub(crate) window: Window<R>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
impl<P: Params> WindowMenuEvent<P> {
|
||||
impl<R: Runtime> WindowMenuEvent<R> {
|
||||
/// 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<P> {
|
||||
pub fn window(&self) -> &Window<R> {
|
||||
&self.window
|
||||
}
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
/// A window event that was triggered on the specified window.
|
||||
pub struct GlobalWindowEvent<P: Params> {
|
||||
pub(crate) event: WindowEvent,
|
||||
pub(crate) window: Window<P>,
|
||||
}
|
||||
/// A window event that was triggered on the specified window.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct GlobalWindowEvent<R: Runtime> {
|
||||
pub(crate) event: WindowEvent,
|
||||
pub(crate) window: Window<R>,
|
||||
}
|
||||
|
||||
impl<P: Params> GlobalWindowEvent<P> {
|
||||
/// The eventpayload.
|
||||
impl<R: Runtime> GlobalWindowEvent<R> {
|
||||
/// The event payload.
|
||||
pub fn event(&self) -> &WindowEvent {
|
||||
&self.event
|
||||
}
|
||||
|
||||
/// The window that the menu belongs to.
|
||||
pub fn window(&self) -> &Window<P> {
|
||||
pub fn window(&self) -> &Window<R> {
|
||||
&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<P: Params> {
|
||||
runtime_handle: <P::Runtime as Runtime>::Handle,
|
||||
manager: WindowManager<P>,
|
||||
global_shortcut_manager: <P::Runtime as Runtime>::GlobalShortcutManager,
|
||||
clipboard_manager: <P::Runtime as Runtime>::ClipboardManager,
|
||||
#[cfg(feature = "system-tray")]
|
||||
tray_handle: Option<tray::SystemTrayHandle<P>>,
|
||||
}
|
||||
/// 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<R: Runtime> {
|
||||
runtime_handle: R::Handle,
|
||||
manager: WindowManager<R>,
|
||||
global_shortcut_manager: R::GlobalShortcutManager,
|
||||
clipboard_manager: R::ClipboardManager,
|
||||
#[cfg(feature = "system-tray")]
|
||||
tray_handle: Option<tray::SystemTrayHandle<R>>,
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for AppHandle<P> {
|
||||
impl<R: Runtime> Clone for AppHandle<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
runtime_handle: self.runtime_handle.clone(),
|
||||
@ -165,14 +161,14 @@ impl<P: Params> Clone for AppHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, P: Params> CommandArg<'de, P> for AppHandle<P> {
|
||||
impl<'de, R: Runtime> CommandArg<'de, R> for AppHandle<R> {
|
||||
/// Grabs the [`Window`] from the [`CommandItem`] and returns the associated [`AppHandle`]. This will never fail.
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
|
||||
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
|
||||
Ok(command.message.window().app_handle)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> AppHandle<P> {
|
||||
impl<R: Runtime> AppHandle<R> {
|
||||
/// 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<P: Params> AppHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Manager<P> for AppHandle<P> {}
|
||||
impl<P: Params> ManagerBase<P> for AppHandle<P> {
|
||||
fn manager(&self) -> &WindowManager<P> {
|
||||
impl<R: Runtime> Manager<R> for AppHandle<R> {}
|
||||
impl<R: Runtime> ManagerBase<R> for AppHandle<R> {
|
||||
fn manager(&self) -> &WindowManager<R> {
|
||||
&self.manager
|
||||
}
|
||||
|
||||
fn runtime(&self) -> RuntimeOrDispatch<'_, P> {
|
||||
fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
|
||||
RuntimeOrDispatch::RuntimeHandle(self.runtime_handle.clone())
|
||||
}
|
||||
|
||||
fn app_handle(&self) -> AppHandle<P> {
|
||||
fn app_handle(&self) -> AppHandle<R> {
|
||||
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<P: Params> {
|
||||
runtime: Option<P::Runtime>,
|
||||
manager: WindowManager<P>,
|
||||
global_shortcut_manager: <P::Runtime as Runtime>::GlobalShortcutManager,
|
||||
clipboard_manager: <P::Runtime as Runtime>::ClipboardManager,
|
||||
#[cfg(feature = "system-tray")]
|
||||
tray_handle: Option<tray::SystemTrayHandle<P>>,
|
||||
handle: AppHandle<P>,
|
||||
}
|
||||
/// 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<R: Runtime> {
|
||||
runtime: Option<R>,
|
||||
manager: WindowManager<R>,
|
||||
global_shortcut_manager: R::GlobalShortcutManager,
|
||||
clipboard_manager: R::ClipboardManager,
|
||||
#[cfg(feature = "system-tray")]
|
||||
tray_handle: Option<tray::SystemTrayHandle<R>>,
|
||||
handle: AppHandle<R>,
|
||||
}
|
||||
|
||||
impl<P: Params> Manager<P> for App<P> {}
|
||||
impl<P: Params> ManagerBase<P> for App<P> {
|
||||
fn manager(&self) -> &WindowManager<P> {
|
||||
impl<R: Runtime> Manager<R> for App<R> {}
|
||||
impl<R: Runtime> ManagerBase<R> for App<R> {
|
||||
fn manager(&self) -> &WindowManager<R> {
|
||||
&self.manager
|
||||
}
|
||||
|
||||
fn runtime(&self) -> RuntimeOrDispatch<'_, P> {
|
||||
fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
|
||||
RuntimeOrDispatch::Runtime(self.runtime.as_ref().unwrap())
|
||||
}
|
||||
|
||||
fn app_handle(&self) -> AppHandle<P> {
|
||||
fn app_handle(&self) -> AppHandle<R> {
|
||||
self.handle()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! shared_app_impl {
|
||||
($app: ty) => {
|
||||
impl<P: Params> $app {
|
||||
impl<R: Runtime> $app {
|
||||
/// Creates a new webview window.
|
||||
pub fn create_window<F>(&self, label: P::Label, url: WindowUrl, setup: F) -> crate::Result<()>
|
||||
pub fn create_window<F>(&self, label: String, url: WindowUrl, setup: F) -> crate::Result<()>
|
||||
where
|
||||
F: FnOnce(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
<R::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
) -> (
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
<R::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
),
|
||||
{
|
||||
let (window_builder, webview_attributes) = setup(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder::new(),
|
||||
<R::Dispatcher as Dispatch>::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<P> {
|
||||
pub fn tray_handle(&self) -> tray::SystemTrayHandle<R> {
|
||||
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) -> <P::Runtime as Runtime>::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) -> <P::Runtime as Runtime>::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<P>);
|
||||
shared_app_impl!(AppHandle<P>);
|
||||
shared_app_impl!(App<R>);
|
||||
shared_app_impl!(AppHandle<R>);
|
||||
|
||||
impl<P: Params> App<P> {
|
||||
impl<R: Runtime> App<R> {
|
||||
/// Gets a handle to the application instance.
|
||||
pub fn handle(&self) -> AppHandle<P> {
|
||||
pub fn handle(&self) -> AppHandle<R> {
|
||||
self.handle.clone()
|
||||
}
|
||||
|
||||
/// Runs the application.
|
||||
pub fn run<F: Fn(&AppHandle<P>, Event<P>) + 'static>(mut self, callback: F) {
|
||||
pub fn run<F: Fn(&AppHandle<R>, 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<P: Params> App<P> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "updater")]
|
||||
impl<P: Params> App<P> {
|
||||
impl<R: Runtime> App<R> {
|
||||
/// Runs the updater hook with built-in dialog.
|
||||
fn run_updater_dialog(&self, window: Window<P>) {
|
||||
fn run_updater_dialog(&self, window: Window<R>) {
|
||||
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<P: Params> App<P> {
|
||||
}
|
||||
|
||||
/// Listen updater events when dialog are disabled.
|
||||
fn listen_updater_events(&self, window: Window<P>) {
|
||||
fn listen_updater_events(&self, window: Window<R>) {
|
||||
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<Window<P>>) {
|
||||
fn run_updater(&self, main_window: Option<Window<R>>) {
|
||||
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<P: Params> App<P> {
|
||||
// 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::<P::Event>()
|
||||
.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<P: Params> App<P> {
|
||||
|
||||
/// Builds a Tauri application.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct Builder<E, L, MID, TID, A, R>
|
||||
where
|
||||
E: Tag,
|
||||
L: Tag,
|
||||
MID: MenuId,
|
||||
TID: MenuId,
|
||||
A: Assets,
|
||||
R: Runtime,
|
||||
{
|
||||
pub struct Builder<R: Runtime> {
|
||||
/// The JS message handler.
|
||||
invoke_handler: Box<InvokeHandler<Args<E, L, MID, TID, A, R>>>,
|
||||
invoke_handler: Box<InvokeHandler<R>>,
|
||||
|
||||
/// The setup hook.
|
||||
setup: SetupHook<Args<E, L, MID, TID, A, R>>,
|
||||
setup: SetupHook<R>,
|
||||
|
||||
/// Page load hook.
|
||||
on_page_load: Box<OnPageLoad<Args<E, L, MID, TID, A, R>>>,
|
||||
on_page_load: Box<OnPageLoad<R>>,
|
||||
|
||||
/// windows to create when starting up.
|
||||
pending_windows: Vec<PendingWindow<Args<E, L, MID, TID, A, R>>>,
|
||||
pending_windows: Vec<PendingWindow<R>>,
|
||||
|
||||
/// All passed plugins
|
||||
plugins: PluginStore<Args<E, L, MID, TID, A, R>>,
|
||||
plugins: PluginStore<R>,
|
||||
|
||||
/// The webview protocols available to all windows.
|
||||
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol>>,
|
||||
@ -461,33 +443,25 @@ where
|
||||
|
||||
/// The menu set to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu: Option<Menu<MID>>,
|
||||
menu: Option<Menu>,
|
||||
|
||||
/// Menu event handlers that listens to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_event_listeners: Vec<GlobalMenuEventListener<Args<E, L, MID, TID, A, R>>>,
|
||||
menu_event_listeners: Vec<GlobalMenuEventListener<R>>,
|
||||
|
||||
/// Window event handlers that listens to all windows.
|
||||
window_event_listeners: Vec<GlobalWindowEventListener<Args<E, L, MID, TID, A, R>>>,
|
||||
window_event_listeners: Vec<GlobalWindowEventListener<R>>,
|
||||
|
||||
/// The app system tray.
|
||||
#[cfg(feature = "system-tray")]
|
||||
system_tray: Option<tray::SystemTray<TID>>,
|
||||
system_tray: Option<tray::SystemTray>,
|
||||
|
||||
/// System tray event handlers.
|
||||
#[cfg(feature = "system-tray")]
|
||||
system_tray_event_listeners: Vec<SystemTrayEventListener<Args<E, L, MID, TID, A, R>>>,
|
||||
system_tray_event_listeners: Vec<SystemTrayEventListener<R>>,
|
||||
}
|
||||
|
||||
impl<E, L, MID, TID, A, R> Builder<E, L, MID, TID, A, R>
|
||||
where
|
||||
E: Tag,
|
||||
L: Tag,
|
||||
MID: MenuId,
|
||||
TID: MenuId,
|
||||
A: Assets,
|
||||
R: Runtime,
|
||||
{
|
||||
impl<R: Runtime> Builder<R> {
|
||||
/// 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<F>(mut self, invoke_handler: F) -> Self
|
||||
where
|
||||
F: Fn(Invoke<Args<E, L, MID, TID, A, R>>) + Send + Sync + 'static,
|
||||
F: Fn(Invoke<R>) + Send + Sync + 'static,
|
||||
{
|
||||
self.invoke_handler = Box::new(invoke_handler);
|
||||
self
|
||||
@ -522,9 +496,7 @@ where
|
||||
/// Defines the setup hook.
|
||||
pub fn setup<F>(mut self, setup: F) -> Self
|
||||
where
|
||||
F: Fn(&mut App<Args<E, L, MID, TID, A, R>>) -> Result<(), Box<dyn std::error::Error + Send>>
|
||||
+ Send
|
||||
+ 'static,
|
||||
F: Fn(&mut App<R>) -> Result<(), Box<dyn std::error::Error + Send>> + Send + 'static,
|
||||
{
|
||||
self.setup = Box::new(setup);
|
||||
self
|
||||
@ -533,14 +505,14 @@ where
|
||||
/// Defines the page load hook.
|
||||
pub fn on_page_load<F>(mut self, on_page_load: F) -> Self
|
||||
where
|
||||
F: Fn(Window<Args<E, L, MID, TID, A, R>>, PageLoadPayload) + Send + Sync + 'static,
|
||||
F: Fn(Window<R>, PageLoadPayload) + Send + Sync + 'static,
|
||||
{
|
||||
self.on_page_load = Box::new(on_page_load);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a plugin to the runtime.
|
||||
pub fn plugin<P: Plugin<Args<E, L, MID, TID, A, R>> + 'static>(mut self, plugin: P) -> Self {
|
||||
pub fn plugin<P: Plugin<R> + '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<F>(mut self, label: L, url: WindowUrl, setup: F) -> Self
|
||||
pub fn create_window<F>(mut self, label: impl Into<String>, url: WindowUrl, setup: F) -> Self
|
||||
where
|
||||
F: FnOnce(
|
||||
<R::Dispatcher as Dispatch>::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<TID>) -> 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<MID>) -> 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<Args<E, L, MID, TID, A, R>>) + Send + Sync + 'static,
|
||||
>(
|
||||
pub fn on_menu_event<F: Fn(WindowMenuEvent<R>) + 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<Args<E, L, MID, TID, A, R>>) + Send + Sync + 'static,
|
||||
>(
|
||||
pub fn on_window_event<F: Fn(GlobalWindowEvent<R>) + 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<Args<E, L, MID, TID, A, R>>, tray::SystemTrayEvent<TID>) + Send + Sync + 'static,
|
||||
F: Fn(&AppHandle<R>, 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<A>) -> crate::Result<App<Args<E, L, MID, TID, A, R>>> {
|
||||
pub fn build<A: Assets>(mut self, context: Context<A>) -> crate::Result<App<R>> {
|
||||
#[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<A>) -> crate::Result<()> {
|
||||
pub fn run<A: Assets>(self, context: Context<A>) -> crate::Result<()> {
|
||||
self.build(context)?.run(|_, _| {});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn on_event_loop_event<P: Params>(event: &RunEvent, manager: &WindowManager<P>) {
|
||||
fn on_event_loop_event<R: Runtime>(event: &RunEvent, manager: &WindowManager<R>) {
|
||||
if let RunEvent::WindowClose(label) = event {
|
||||
manager.on_window_close(label);
|
||||
}
|
||||
@ -935,14 +900,7 @@ fn on_event_loop_event<P: Params>(event: &RunEvent, manager: &WindowManager<P>)
|
||||
|
||||
/// Make `Wry` the default `Runtime` for `Builder`
|
||||
#[cfg(feature = "wry")]
|
||||
impl<A: Assets> Default for Builder<String, String, String, String, A, crate::Wry> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wry"))]
|
||||
impl<A: Assets, R: Runtime> Default for Builder<String, String, String, String, A, R> {
|
||||
impl Default for Builder<crate::Wry> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
|
@ -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<I: MenuId>(map: &mut HashMap<u16, I>, menu: &SystemTrayMenu<I>) {
|
||||
pub(crate) fn get_menu_ids(map: &mut HashMap<MenuHash, MenuId>, 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<I: MenuId>(map: &mut HashMap<u16, I>, menu: &SystemTr
|
||||
/// System tray event.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
|
||||
#[non_exhaustive]
|
||||
pub enum SystemTrayEvent<I: MenuId> {
|
||||
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<I: MenuId> {
|
||||
},
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
/// A handle to a system tray. Allows updating the context menu items.
|
||||
pub struct SystemTrayHandle<P: Params> {
|
||||
pub(crate) ids: Arc<HashMap<u16, P::SystemTrayMenuId>>,
|
||||
pub(crate) inner: <P::Runtime as Runtime>::TrayHandler,
|
||||
}
|
||||
/// A handle to a system tray. Allows updating the context menu items.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct SystemTrayHandle<R: Runtime> {
|
||||
pub(crate) ids: Arc<HashMap<MenuHash, MenuId>>,
|
||||
pub(crate) inner: R::TrayHandler,
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for SystemTrayHandle<P> {
|
||||
impl<R: Runtime> Clone for SystemTrayHandle<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
ids: self.ids.clone(),
|
||||
@ -92,15 +92,14 @@ impl<P: Params> Clone for SystemTrayHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
/// A handle to a system tray menu item.
|
||||
pub struct SystemTrayMenuItemHandle<P: Params> {
|
||||
id: u16,
|
||||
tray_handler: <P::Runtime as Runtime>::TrayHandler,
|
||||
}
|
||||
/// A handle to a system tray menu item.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct SystemTrayMenuItemHandle<R: Runtime> {
|
||||
id: MenuHash,
|
||||
tray_handler: R::TrayHandler,
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for SystemTrayMenuItemHandle<P> {
|
||||
impl<R: Runtime> Clone for SystemTrayMenuItemHandle<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
id: self.id,
|
||||
@ -109,8 +108,8 @@ impl<P: Params> Clone for SystemTrayMenuItemHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> SystemTrayHandle<P> {
|
||||
pub fn get_item(&self, id: &P::SystemTrayMenuId) -> SystemTrayMenuItemHandle<P> {
|
||||
impl<R: Runtime> SystemTrayHandle<R> {
|
||||
pub fn get_item(&self, id: MenuIdRef<'_>) -> SystemTrayMenuItemHandle<R> {
|
||||
for (raw, item_id) in self.ids.iter() {
|
||||
if item_id == id {
|
||||
return SystemTrayMenuItemHandle {
|
||||
@ -128,7 +127,7 @@ impl<P: Params> SystemTrayHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> SystemTrayMenuItemHandle<P> {
|
||||
impl<R: Runtime> SystemTrayMenuItemHandle<R> {
|
||||
/// Modifies the enabled state of the menu item.
|
||||
pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
|
||||
self
|
||||
|
@ -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<P>,
|
||||
pub message: &'a InvokeMessage<R>,
|
||||
}
|
||||
|
||||
/// 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<Self, InvokeError>;
|
||||
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError>;
|
||||
}
|
||||
|
||||
/// 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<Self, InvokeError> {
|
||||
impl<'de, D: Deserialize<'de>, R: Runtime> CommandArg<'de, R> for D {
|
||||
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
|
||||
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<P, T>(self, value: T, resolver: InvokeResolver<P>)
|
||||
pub fn block<R, T>(self, value: T, resolver: InvokeResolver<R>)
|
||||
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<P, T, E>(self, value: Result<T, E>, resolver: InvokeResolver<P>)
|
||||
pub fn block<R, T, E>(self, value: Result<T, E>, resolver: InvokeResolver<R>)
|
||||
where
|
||||
P: Params,
|
||||
R: Runtime,
|
||||
T: Serialize,
|
||||
E: Into<InvokeError>,
|
||||
{
|
||||
|
@ -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<P: Params>(
|
||||
fn run<R: Runtime>(
|
||||
self,
|
||||
window: Window<P>,
|
||||
resolver: InvokeResolver<P>,
|
||||
window: Window<R>,
|
||||
resolver: InvokeResolver<R>,
|
||||
config: Arc<Config>,
|
||||
package_info: PackageInfo,
|
||||
) {
|
||||
@ -164,9 +165,9 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle<P: Params>(
|
||||
pub(crate) fn handle<R: Runtime>(
|
||||
module: String,
|
||||
invoke: Invoke<P>,
|
||||
invoke: Invoke<R>,
|
||||
config: Arc<Config>,
|
||||
package_info: &PackageInfo,
|
||||
) {
|
||||
|
@ -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<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
let mut clipboard = window.app_handle.clipboard_manager();
|
||||
match self {
|
||||
Self::WriteText(text) => Ok(clipboard.write_text(text)?.into()),
|
||||
|
@ -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<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
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<P: Params>(window: Window<P>) -> crate::Result<WindowParent> {
|
||||
fn parent<R: Runtime>(window: Window<R>) -> crate::Result<WindowParent> {
|
||||
Ok(WindowParent {
|
||||
hwnd: window.hwnd()?,
|
||||
})
|
||||
@ -168,8 +169,8 @@ fn parent<P: Params>(window: Window<P>) -> crate::Result<WindowParent> {
|
||||
/// Shows an open dialog.
|
||||
#[cfg(dialog_open)]
|
||||
#[allow(unused_variables)]
|
||||
pub fn open<P: Params>(
|
||||
window: Window<P>,
|
||||
pub fn open<R: Runtime>(
|
||||
window: Window<R>,
|
||||
options: OpenDialogOptions,
|
||||
) -> crate::Result<InvokeResponse> {
|
||||
let mut dialog_builder = FileDialogBuilder::new();
|
||||
@ -200,8 +201,8 @@ pub fn open<P: Params>(
|
||||
/// Shows a save dialog.
|
||||
#[cfg(dialog_save)]
|
||||
#[allow(unused_variables)]
|
||||
pub fn save<P: Params>(
|
||||
window: Window<P>,
|
||||
pub fn save<R: Runtime>(
|
||||
window: Window<R>,
|
||||
options: SaveDialogOptions,
|
||||
) -> crate::Result<InvokeResponse> {
|
||||
let mut dialog_builder = FileDialogBuilder::new();
|
||||
|
@ -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<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
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<P::Label> = 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<P: Params>(window: &Window<P>, event_id: u64) -> String {
|
||||
pub fn unlisten_js<R: Runtime>(window: &Window<R>, event_id: u64) -> String {
|
||||
format!(
|
||||
"
|
||||
for (var event in (window['{listeners}'] || {{}})) {{
|
||||
@ -80,8 +70,8 @@ pub fn unlisten_js<P: Params>(window: &Window<P>, event_id: u64) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn listen_js<P: Params>(
|
||||
window: &Window<P>,
|
||||
pub fn listen_js<R: Runtime>(
|
||||
window: &Window<R>,
|
||||
event: String,
|
||||
event_id: u64,
|
||||
handler: String,
|
||||
|
@ -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<P: Params>(
|
||||
window: Window<P>,
|
||||
manager: &mut <P::Runtime as Runtime>::GlobalShortcutManager,
|
||||
fn register_shortcut<R: Runtime>(
|
||||
window: Window<R>,
|
||||
manager: &mut R::GlobalShortcutManager,
|
||||
shortcut: String,
|
||||
handler: String,
|
||||
) -> crate::Result<()> {
|
||||
@ -46,7 +46,7 @@ fn register_shortcut<P: Params>(
|
||||
|
||||
#[cfg(not(global_shortcut_all))]
|
||||
impl Cmd {
|
||||
pub fn run<P: Params>(self, _window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, _window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
Err(crate::Error::ApiNotAllowlisted(
|
||||
"globalShortcut > all".to_string(),
|
||||
))
|
||||
@ -55,7 +55,7 @@ impl Cmd {
|
||||
|
||||
#[cfg(global_shortcut_all)]
|
||||
impl Cmd {
|
||||
pub fn run<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
match self {
|
||||
Self::Register { shortcut, handler } => {
|
||||
let mut manager = window.app_handle.global_shortcut_manager();
|
||||
|
@ -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<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
match self {
|
||||
Self::ValidateSalt { salt } => Ok(window.verify_salt(salt).into()),
|
||||
}
|
||||
|
@ -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<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
match self {
|
||||
Self::Execute {
|
||||
program,
|
||||
|
@ -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<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
|
||||
pub async fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
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| {
|
||||
(
|
||||
<<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder>::with_config(
|
||||
options,
|
||||
),
|
||||
<<R::Dispatcher as Dispatch>::WindowBuilder>::with_config(options),
|
||||
webview_attributes,
|
||||
)
|
||||
})?
|
||||
.emit_others(
|
||||
&crate::manager::tauri_event::<P::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
|
||||
};
|
||||
|
@ -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<Event: Tag, Window: Tag> {
|
||||
enum Pending {
|
||||
Unlisten(EventHandler),
|
||||
Listen(EventHandler, Event, Handler<Window>),
|
||||
Trigger(Event, Option<Window>, Option<String>),
|
||||
Listen(EventHandler, String, Handler),
|
||||
Trigger(String, Option<String>, Option<String>),
|
||||
}
|
||||
|
||||
/// Stored in [`Listeners`] to be called upon when the event that stored it is triggered.
|
||||
struct Handler<Window: Tag> {
|
||||
window: Option<Window>,
|
||||
struct Handler {
|
||||
window: Option<String>,
|
||||
callback: Box<dyn Fn(Event) + Send>,
|
||||
}
|
||||
|
||||
/// A collection of handlers. Multiple handlers can represent the same event.
|
||||
type Handlers<Event, Window> = HashMap<Event, HashMap<EventHandler, Handler<Window>>>;
|
||||
|
||||
/// Holds event handlers and pending event handlers, along with the salts associating them.
|
||||
struct InnerListeners<Event: Tag, Window: Tag> {
|
||||
handlers: Mutex<Handlers<Event, Window>>,
|
||||
pending: Mutex<Vec<Pending<Event, Window>>>,
|
||||
struct InnerListeners {
|
||||
handlers: Mutex<HashMap<String, HashMap<EventHandler, Handler>>>,
|
||||
pending: Mutex<Vec<Pending>>,
|
||||
function_name: Uuid,
|
||||
listeners_object_name: Uuid,
|
||||
queue_object_name: Uuid,
|
||||
}
|
||||
|
||||
/// A self-contained event manager.
|
||||
pub(crate) struct Listeners<Event: Tag, Window: Tag> {
|
||||
inner: Arc<InnerListeners<Event, Window>>,
|
||||
pub(crate) struct Listeners {
|
||||
inner: Arc<InnerListeners>,
|
||||
}
|
||||
|
||||
impl<Event: Tag, Window: Tag> Default for Listeners<Event, Window> {
|
||||
impl Default for Listeners {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(InnerListeners {
|
||||
@ -86,7 +81,7 @@ impl<Event: Tag, Window: Tag> Default for Listeners<Event, Window> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Event: Tag, Window: Tag> Clone for Listeners<Event, Window> {
|
||||
impl Clone for Listeners {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
@ -94,7 +89,7 @@ impl<Event: Tag, Window: Tag> Clone for Listeners<Event, Window> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Event: Tag, Window: Tag> Listeners<Event, Window> {
|
||||
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<Event: Tag, Window: Tag> Listeners<Event, Window> {
|
||||
}
|
||||
|
||||
/// Insert a pending event action to the queue.
|
||||
fn insert_pending(&self, action: Pending<Event, Window>) {
|
||||
fn insert_pending(&self, action: Pending) {
|
||||
self
|
||||
.inner
|
||||
.pending
|
||||
@ -140,7 +135,7 @@ impl<Event: Tag, Window: Tag> Listeners<Event, Window> {
|
||||
}
|
||||
}
|
||||
|
||||
fn listen_(&self, id: EventHandler, event: Event, handler: Handler<Window>) {
|
||||
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<Event: Tag, Window: Tag> Listeners<Event, Window> {
|
||||
}
|
||||
|
||||
/// Adds an event listener for JS events.
|
||||
pub(crate) fn listen<F: Fn(self::Event) + Send + 'static>(
|
||||
pub(crate) fn listen<F: Fn(Event) + Send + 'static>(
|
||||
&self,
|
||||
event: Event,
|
||||
window: Option<Window>,
|
||||
event: String,
|
||||
window: Option<String>,
|
||||
handler: F,
|
||||
) -> EventHandler {
|
||||
let id = EventHandler(Uuid::new_v4());
|
||||
@ -168,10 +163,10 @@ impl<Event: Tag, Window: Tag> Listeners<Event, Window> {
|
||||
}
|
||||
|
||||
/// Listen to a JS event and immediately unlisten.
|
||||
pub(crate) fn once<F: Fn(self::Event) + Send + 'static>(
|
||||
pub(crate) fn once<F: Fn(Event) + Send + 'static>(
|
||||
&self,
|
||||
event: Event,
|
||||
window: Option<Window>,
|
||||
event: String,
|
||||
window: Option<String>,
|
||||
handler: F,
|
||||
) -> EventHandler {
|
||||
let self_ = self.clone();
|
||||
@ -192,15 +187,7 @@ impl<Event: Tag, Window: Tag> Listeners<Event, Window> {
|
||||
}
|
||||
|
||||
/// Triggers the given global event with its payload.
|
||||
pub(crate) fn trigger<E: ?Sized>(
|
||||
&self,
|
||||
event: &E,
|
||||
window: Option<Window>,
|
||||
payload: Option<String>,
|
||||
) where
|
||||
Event: Borrow<E>,
|
||||
E: TagRef<Event>,
|
||||
{
|
||||
pub(crate) fn trigger(&self, event: &str, window: Option<String>, payload: Option<String>) {
|
||||
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<String, String> = 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<String, String> = 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<String, String> = 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
|
||||
|
@ -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<P> =
|
||||
Box<dyn Fn(&mut App<P>) -> Result<(), Box<dyn std::error::Error + Send>> + Send>;
|
||||
pub type SetupHook<R> =
|
||||
Box<dyn Fn(&mut App<R>) -> Result<(), Box<dyn std::error::Error + Send>> + Send>;
|
||||
|
||||
/// A closure that is run everytime Tauri receives a message it doesn't explicitly handle.
|
||||
pub type InvokeHandler<P> = dyn Fn(Invoke<P>) + Send + Sync + 'static;
|
||||
pub type InvokeHandler<R> = dyn Fn(Invoke<R>) + Send + Sync + 'static;
|
||||
|
||||
/// A closure that is run once every time a window is created and loaded.
|
||||
pub type OnPageLoad<P> = dyn Fn(Window<P>, PageLoadPayload) + Send + Sync + 'static;
|
||||
pub type OnPageLoad<R> = dyn Fn(Window<R>, 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<P: Params> {
|
||||
/// The message passed.
|
||||
pub message: InvokeMessage<P>,
|
||||
/// The message and resolver given to a custom command.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct Invoke<R: Runtime> {
|
||||
/// The message passed.
|
||||
pub message: InvokeMessage<R>,
|
||||
|
||||
/// The resolver of the message.
|
||||
pub resolver: InvokeResolver<P>,
|
||||
}
|
||||
/// The resolver of the message.
|
||||
pub resolver: InvokeResolver<R>,
|
||||
}
|
||||
|
||||
/// Error response from an [`InvokeMessage`].
|
||||
@ -112,17 +114,16 @@ impl From<InvokeError> for InvokeResponse {
|
||||
}
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
/// Resolver of a invoke message.
|
||||
pub struct InvokeResolver<P: Params> {
|
||||
window: Window<P>,
|
||||
pub(crate) callback: String,
|
||||
pub(crate) error: String,
|
||||
}
|
||||
/// Resolver of a invoke message.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct InvokeResolver<R: Runtime> {
|
||||
window: Window<R>,
|
||||
pub(crate) callback: String,
|
||||
pub(crate) error: String,
|
||||
}
|
||||
|
||||
impl<P: Params> InvokeResolver<P> {
|
||||
pub(crate) fn new(window: Window<P>, callback: String, error: String) -> Self {
|
||||
impl<R: Runtime> InvokeResolver<R> {
|
||||
pub(crate) fn new(window: Window<R>, callback: String, error: String) -> Self {
|
||||
Self {
|
||||
window,
|
||||
callback,
|
||||
@ -191,7 +192,7 @@ impl<P: Params> InvokeResolver<P> {
|
||||
/// 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<T, F>(
|
||||
window: Window<P>,
|
||||
window: Window<R>,
|
||||
task: F,
|
||||
success_callback: String,
|
||||
error_callback: String,
|
||||
@ -204,7 +205,7 @@ impl<P: Params> InvokeResolver<P> {
|
||||
}
|
||||
|
||||
pub(crate) fn return_closure<T: Serialize, F: FnOnce() -> Result<T, InvokeError>>(
|
||||
window: Window<P>,
|
||||
window: Window<R>,
|
||||
f: F,
|
||||
success_callback: String,
|
||||
error_callback: String,
|
||||
@ -213,7 +214,7 @@ impl<P: Params> InvokeResolver<P> {
|
||||
}
|
||||
|
||||
pub(crate) fn return_result(
|
||||
window: Window<P>,
|
||||
window: Window<R>,
|
||||
response: InvokeResponse,
|
||||
success_callback: String,
|
||||
error_callback: String,
|
||||
@ -232,24 +233,23 @@ impl<P: Params> InvokeResolver<P> {
|
||||
}
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
/// An invoke message.
|
||||
pub struct InvokeMessage<P: Params> {
|
||||
/// The window that received the invoke message.
|
||||
pub(crate) window: Window<P>,
|
||||
/// Application managed state.
|
||||
pub(crate) state: Arc<StateManager>,
|
||||
/// 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<R: Runtime> {
|
||||
/// The window that received the invoke message.
|
||||
pub(crate) window: Window<R>,
|
||||
/// Application managed state.
|
||||
pub(crate) state: Arc<StateManager>,
|
||||
/// The RPC command.
|
||||
pub(crate) command: String,
|
||||
/// The JSON argument passed on the invoke message.
|
||||
pub(crate) payload: JsonValue,
|
||||
}
|
||||
|
||||
impl<P: Params> InvokeMessage<P> {
|
||||
impl<R: Runtime> InvokeMessage<R> {
|
||||
/// Create an new [`InvokeMessage`] from a payload send to a window.
|
||||
pub(crate) fn new(
|
||||
window: Window<P>,
|
||||
window: Window<R>,
|
||||
state: Arc<StateManager>,
|
||||
command: String,
|
||||
payload: JsonValue,
|
||||
@ -270,13 +270,13 @@ impl<P: Params> InvokeMessage<P> {
|
||||
|
||||
/// The window that received the invoke.
|
||||
#[inline(always)]
|
||||
pub fn window(&self) -> Window<P> {
|
||||
pub fn window(&self) -> Window<R> {
|
||||
self.window.clone()
|
||||
}
|
||||
|
||||
/// A reference to window that received the invoke.
|
||||
#[inline(always)]
|
||||
pub fn window_ref(&self) -> &Window<P> {
|
||||
pub fn window_ref(&self) -> &Window<R> {
|
||||
&self.window
|
||||
}
|
||||
|
||||
|
@ -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<A: Assets> Context<A> {
|
||||
|
||||
// TODO: expand these docs
|
||||
/// Manages a running application.
|
||||
pub trait Manager<P: Params>: sealed::ManagerBase<P> {
|
||||
pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
|
||||
/// The [`Config`] the manager was created with.
|
||||
fn config(&self) -> Arc<Config> {
|
||||
self.manager().config()
|
||||
}
|
||||
|
||||
/// Emits a event to all windows.
|
||||
fn emit_all<E: ?Sized, S>(&self, event: &E, payload: S) -> Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize + Clone,
|
||||
{
|
||||
fn emit_all<S: Serialize + Clone>(&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<E: ?Sized, L: ?Sized, S: Serialize + Clone>(
|
||||
&self,
|
||||
label: &L,
|
||||
event: &E,
|
||||
payload: S,
|
||||
) -> Result<()>
|
||||
where
|
||||
P::Label: Borrow<L>,
|
||||
P::Event: Borrow<E>,
|
||||
L: TagRef<P::Label>,
|
||||
E: TagRef<P::Event>,
|
||||
{
|
||||
fn emit_to<S: Serialize + Clone>(&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<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
fn listen_global<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(EmittedEvent) + Send + 'static,
|
||||
{
|
||||
@ -289,7 +272,7 @@ pub trait Manager<P: Params>: sealed::ManagerBase<P> {
|
||||
}
|
||||
|
||||
/// Listen to a global event only once.
|
||||
fn once_global<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
fn once_global<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(EmittedEvent) + Send + 'static,
|
||||
{
|
||||
@ -297,11 +280,7 @@ pub trait Manager<P: Params>: sealed::ManagerBase<P> {
|
||||
}
|
||||
|
||||
/// Trigger a global event.
|
||||
fn trigger_global<E: ?Sized>(&self, event: &E, data: Option<String>)
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
{
|
||||
fn trigger_global(&self, event: &str, data: Option<String>) {
|
||||
self.manager().trigger(event, None, data)
|
||||
}
|
||||
|
||||
@ -311,16 +290,12 @@ pub trait Manager<P: Params>: sealed::ManagerBase<P> {
|
||||
}
|
||||
|
||||
/// Fetch a single window from the manager.
|
||||
fn get_window<L: ?Sized>(&self, label: &L) -> Option<Window<P>>
|
||||
where
|
||||
P::Label: Borrow<L>,
|
||||
L: TagRef<P::Label>,
|
||||
{
|
||||
fn get_window(&self, label: &str) -> Option<Window<R>> {
|
||||
self.manager().get_window(label)
|
||||
}
|
||||
|
||||
/// Fetch all managed windows.
|
||||
fn windows(&self) -> HashMap<P::Label, Window<P>> {
|
||||
fn windows(&self) -> HashMap<String, Window<R>> {
|
||||
self.manager().windows()
|
||||
}
|
||||
|
||||
@ -345,33 +320,33 @@ pub trait Manager<P: Params>: sealed::ManagerBase<P> {
|
||||
/// 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(<P::Runtime as Runtime>::Handle),
|
||||
RuntimeHandle(R::Handle),
|
||||
|
||||
/// A dispatcher to the running [`Runtime`].
|
||||
Dispatch(<P::Runtime as Runtime>::Dispatcher),
|
||||
Dispatch(R::Dispatcher),
|
||||
}
|
||||
|
||||
/// Managed handle to the application runtime.
|
||||
pub trait ManagerBase<P: Params> {
|
||||
pub trait ManagerBase<R: Runtime> {
|
||||
/// The manager behind the [`Managed`] item.
|
||||
fn manager(&self) -> &WindowManager<P>;
|
||||
fn manager(&self) -> &WindowManager<R>;
|
||||
|
||||
fn runtime(&self) -> RuntimeOrDispatch<'_, P>;
|
||||
fn app_handle(&self) -> AppHandle<P>;
|
||||
fn runtime(&self) -> RuntimeOrDispatch<'_, R>;
|
||||
fn app_handle(&self) -> AppHandle<R>;
|
||||
|
||||
/// Creates a new [`Window`] on the [`Runtime`] and attaches it to the [`Manager`].
|
||||
fn create_new_window(
|
||||
&self,
|
||||
pending: crate::PendingWindow<P>,
|
||||
) -> crate::Result<crate::Window<P>> {
|
||||
pending: crate::PendingWindow<R>,
|
||||
) -> crate::Result<crate::Window<R>> {
|
||||
use crate::runtime::Dispatch;
|
||||
let labels = self.manager().labels().into_iter().collect::<Vec<_>>();
|
||||
let pending = self
|
||||
|
@ -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<Event: Tag>(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<R: Runtime> {
|
||||
windows: Mutex<HashMap<String, Window<R>>>,
|
||||
plugins: Mutex<PluginStore<R>>,
|
||||
listeners: Listeners,
|
||||
pub(crate) state: Arc<StateManager>,
|
||||
|
||||
/// The JS message handler.
|
||||
invoke_handler: Box<InvokeHandler<R>>,
|
||||
|
||||
/// The page load hook, invoked when the webview performs a navigation.
|
||||
on_page_load: Box<OnPageLoad<R>>,
|
||||
|
||||
config: Arc<Config>,
|
||||
assets: Arc<dyn Assets>,
|
||||
default_window_icon: Option<Vec<u8>>,
|
||||
|
||||
/// A list of salts that are valid for the current application.
|
||||
salts: Mutex<HashSet<Uuid>>,
|
||||
package_info: PackageInfo,
|
||||
/// The webview protocols protocols available to all windows.
|
||||
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol>>,
|
||||
/// The menu set to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu: Option<Menu>,
|
||||
/// Maps runtime id to a strongly typed menu id.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_ids: HashMap<MenuHash, MenuId>,
|
||||
/// Menu event listeners to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_event_listeners: Arc<Vec<GlobalMenuEventListener<R>>>,
|
||||
/// Window event listeners to all windows.
|
||||
window_event_listeners: Arc<Vec<GlobalWindowEventListener<R>>>,
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
pub struct InnerWindowManager<P: Params> {
|
||||
windows: Mutex<HashMap<P::Label, Window<P>>>,
|
||||
plugins: Mutex<PluginStore<P>>,
|
||||
listeners: Listeners<P::Event, P::Label>,
|
||||
pub(crate) state: Arc<StateManager>,
|
||||
|
||||
/// The JS message handler.
|
||||
invoke_handler: Box<InvokeHandler<P>>,
|
||||
|
||||
/// The page load hook, invoked when the webview performs a navigation.
|
||||
on_page_load: Box<OnPageLoad<P>>,
|
||||
|
||||
config: Arc<Config>,
|
||||
assets: Arc<P::Assets>,
|
||||
default_window_icon: Option<Vec<u8>>,
|
||||
|
||||
/// A list of salts that are valid for the current application.
|
||||
salts: Mutex<HashSet<Uuid>>,
|
||||
package_info: PackageInfo,
|
||||
/// The webview protocols protocols available to all windows.
|
||||
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol>>,
|
||||
/// The menu set to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu: Option<Menu<P::MenuId>>,
|
||||
/// Maps runtime id to a strongly typed menu id.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_ids: HashMap<u16, P::MenuId>,
|
||||
/// Menu event listeners to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_event_listeners: Arc<Vec<GlobalMenuEventListener<P>>>,
|
||||
/// Window event listeners to all windows.
|
||||
window_event_listeners: Arc<Vec<GlobalWindowEventListener<P>>>,
|
||||
}
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct WindowManager<R: Runtime> {
|
||||
pub inner: Arc<InnerWindowManager<R>>,
|
||||
invoke_keys: Arc<Mutex<Vec<u32>>>,
|
||||
}
|
||||
|
||||
/// 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<String, String, String, String, crate::api::assets::EmbeddedAssets, crate::Wry>;
|
||||
|
||||
/// 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<E: Tag, L: Tag, MID: MenuId, TID: MenuId, A: Assets, R: Runtime> {
|
||||
_event: PhantomData<fn() -> E>,
|
||||
_label: PhantomData<fn() -> L>,
|
||||
_menu_id: PhantomData<fn() -> MID>,
|
||||
_tray_menu_id: PhantomData<fn() -> TID>,
|
||||
_assets: PhantomData<fn() -> A>,
|
||||
_runtime: PhantomData<fn() -> R>,
|
||||
}
|
||||
|
||||
impl<E: Tag, L: Tag, MID: MenuId, TID: MenuId, A: Assets, R: Runtime> Default
|
||||
for Args<E, L, MID, TID, A, R>
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
_event: PhantomData,
|
||||
_label: PhantomData,
|
||||
_menu_id: PhantomData,
|
||||
_tray_menu_id: PhantomData,
|
||||
_assets: PhantomData,
|
||||
_runtime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Tag, L: Tag, MID: MenuId, TID: MenuId, A: Assets, R: Runtime> ParamsBase
|
||||
for Args<E, L, MID, TID, A, R>
|
||||
{
|
||||
}
|
||||
impl<E: Tag, L: Tag, MID: MenuId, TID: MenuId, A: Assets, R: Runtime> Params
|
||||
for Args<E, L, MID, TID, A, R>
|
||||
{
|
||||
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<P: Params> {
|
||||
pub inner: Arc<InnerWindowManager<P>>,
|
||||
invoke_keys: Arc<Mutex<Vec<u32>>>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
_marker: Args<P::Event, P::Label, P::MenuId, P::SystemTrayMenuId, P::Assets, P::Runtime>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for WindowManager<P> {
|
||||
impl<R: Runtime> Clone for WindowManager<R> {
|
||||
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<I: MenuId>(map: &mut HashMap<u16, I>, menu: &Menu<I>) {
|
||||
fn get_menu_ids(map: &mut HashMap<MenuHash, MenuId>, 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<I: MenuId>(map: &mut HashMap<u16, I>, menu: &Menu<I>) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> WindowManager<P> {
|
||||
impl<R: Runtime> WindowManager<R> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn with_handlers(
|
||||
context: Context<P::Assets>,
|
||||
plugins: PluginStore<P>,
|
||||
invoke_handler: Box<InvokeHandler<P>>,
|
||||
on_page_load: Box<OnPageLoad<P>>,
|
||||
context: Context<impl Assets>,
|
||||
plugins: PluginStore<R>,
|
||||
invoke_handler: Box<InvokeHandler<R>>,
|
||||
on_page_load: Box<OnPageLoad<R>>,
|
||||
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol>>,
|
||||
state: StateManager,
|
||||
window_event_listeners: Vec<GlobalWindowEventListener<P>>,
|
||||
window_event_listeners: Vec<GlobalWindowEventListener<R>>,
|
||||
#[cfg(feature = "menu")] (menu, menu_event_listeners): (
|
||||
Option<Menu<P::MenuId>>,
|
||||
Vec<GlobalMenuEventListener<P>>,
|
||||
Option<Menu>,
|
||||
Vec<GlobalMenuEventListener<R>>,
|
||||
),
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -267,12 +161,11 @@ impl<P: Params> WindowManager<P> {
|
||||
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<P::Label, Window<P>>> {
|
||||
pub(crate) fn windows_lock(&self) -> MutexGuard<'_, HashMap<String, Window<R>>> {
|
||||
self.inner.windows.lock().expect("poisoned window manager")
|
||||
}
|
||||
|
||||
@ -283,7 +176,7 @@ impl<P: Params> WindowManager<P> {
|
||||
|
||||
/// Get the menu ids mapper.
|
||||
#[cfg(feature = "menu")]
|
||||
pub(crate) fn menu_ids(&self) -> HashMap<u16, P::MenuId> {
|
||||
pub(crate) fn menu_ids(&self) -> HashMap<MenuHash, MenuId> {
|
||||
self.inner.menu_ids.clone()
|
||||
}
|
||||
|
||||
@ -319,10 +212,10 @@ impl<P: Params> WindowManager<P> {
|
||||
|
||||
fn prepare_pending_window(
|
||||
&self,
|
||||
mut pending: PendingWindow<P>,
|
||||
label: P::Label,
|
||||
pending_labels: &[P::Label],
|
||||
) -> crate::Result<PendingWindow<P>> {
|
||||
mut pending: PendingWindow<R>,
|
||||
label: &str,
|
||||
pending_labels: &[String],
|
||||
) -> crate::Result<PendingWindow<R>> {
|
||||
let is_init_global = self.inner.config.build.with_global_tauri;
|
||||
let plugin_init = self
|
||||
.inner
|
||||
@ -339,8 +232,8 @@ impl<P: Params> WindowManager<P> {
|
||||
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<P: Params> WindowManager<P> {
|
||||
Ok(pending)
|
||||
}
|
||||
|
||||
fn prepare_rpc_handler(&self, app_handle: AppHandle<P>) -> WebviewRpcHandler<P> {
|
||||
fn prepare_rpc_handler(&self, app_handle: AppHandle<R>) -> WebviewRpcHandler<R> {
|
||||
let manager = self.clone();
|
||||
Box::new(move |window, request| {
|
||||
let window = Window::new(manager.clone(), window, app_handle.clone());
|
||||
@ -462,11 +355,11 @@ impl<P: Params> WindowManager<P> {
|
||||
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<P: Params> WindowManager<P> {
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_file_drop(&self, app_handle: AppHandle<P>) -> FileDropHandler<P> {
|
||||
fn prepare_file_drop(&self, app_handle: AppHandle<R>) -> FileDropHandler<R> {
|
||||
let manager = self.clone();
|
||||
Box::new(move |event, window| {
|
||||
let manager = manager.clone();
|
||||
@ -506,17 +399,9 @@ impl<P: Params> WindowManager<P> {
|
||||
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::<P::Event>("tauri://file-drop"), Some(paths))
|
||||
}
|
||||
FileDropEvent::Dropped(paths) => window.emit(
|
||||
&tauri_event::<P::Event>("tauri://file-drop-hover"),
|
||||
Some(paths),
|
||||
),
|
||||
FileDropEvent::Cancelled => window.emit(
|
||||
&tauri_event::<P::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<P: Params> WindowManager<P> {
|
||||
|
||||
#[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<Args<String, String, String, String, _, Wry>> =
|
||||
WindowManager::with_handlers(
|
||||
context,
|
||||
PluginStore::default(),
|
||||
Box::new(|_| ()),
|
||||
Box::new(|_, _| ()),
|
||||
Default::default(),
|
||||
StateManager::new(),
|
||||
Default::default(),
|
||||
#[cfg(feature = "menu")]
|
||||
Default::default(),
|
||||
);
|
||||
let manager: WindowManager<Wry> = 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<P: Params> WindowManager<P> {
|
||||
pub fn run_invoke_handler(&self, invoke: Invoke<P>) {
|
||||
impl<R: Runtime> WindowManager<R> {
|
||||
pub fn run_invoke_handler(&self, invoke: Invoke<R>) {
|
||||
(self.inner.invoke_handler)(invoke);
|
||||
}
|
||||
|
||||
pub fn run_on_page_load(&self, window: Window<P>, payload: PageLoadPayload) {
|
||||
pub fn run_on_page_load(&self, window: Window<R>, payload: PageLoadPayload) {
|
||||
(self.inner.on_page_load)(window.clone(), payload.clone());
|
||||
self
|
||||
.inner
|
||||
@ -643,7 +527,7 @@ impl<P: Params> WindowManager<P> {
|
||||
.on_page_load(window, payload);
|
||||
}
|
||||
|
||||
pub fn extend_api(&self, invoke: Invoke<P>) {
|
||||
pub fn extend_api(&self, invoke: Invoke<R>) {
|
||||
self
|
||||
.inner
|
||||
.plugins
|
||||
@ -652,7 +536,7 @@ impl<P: Params> WindowManager<P> {
|
||||
.extend_api(invoke);
|
||||
}
|
||||
|
||||
pub fn initialize_plugins(&self, app: &App<P>) -> crate::Result<()> {
|
||||
pub fn initialize_plugins(&self, app: &App<R>) -> crate::Result<()> {
|
||||
self
|
||||
.inner
|
||||
.plugins
|
||||
@ -663,14 +547,12 @@ impl<P: Params> WindowManager<P> {
|
||||
|
||||
pub fn prepare_window(
|
||||
&self,
|
||||
app_handle: AppHandle<P>,
|
||||
mut pending: PendingWindow<P>,
|
||||
pending_labels: &[P::Label],
|
||||
) -> crate::Result<PendingWindow<P>> {
|
||||
app_handle: AppHandle<R>,
|
||||
mut pending: PendingWindow<R>,
|
||||
pending_labels: &[String],
|
||||
) -> crate::Result<PendingWindow<R>> {
|
||||
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<P: Params> WindowManager<P> {
|
||||
|
||||
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<P: Params> WindowManager<P> {
|
||||
Ok(pending)
|
||||
}
|
||||
|
||||
pub fn attach_window(&self, app_handle: AppHandle<P>, window: DetachedWindow<P>) -> Window<P> {
|
||||
pub fn attach_window(&self, app_handle: AppHandle<R>, window: DetachedWindow<R>) -> Window<R> {
|
||||
let window = Window::new(self.clone(), window, app_handle);
|
||||
|
||||
let window_ = window.clone();
|
||||
@ -737,7 +619,7 @@ impl<P: Params> WindowManager<P> {
|
||||
{
|
||||
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<P: Params> WindowManager<P> {
|
||||
}
|
||||
|
||||
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<E: ?Sized, S, F>(&self, event: &E, payload: S, filter: F) -> crate::Result<()>
|
||||
pub fn emit_filter<S, F>(&self, event: &str, payload: S, filter: F) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize + Clone,
|
||||
F: Fn(&Window<P>) -> bool,
|
||||
F: Fn(&Window<R>) -> bool,
|
||||
{
|
||||
self
|
||||
.windows_lock()
|
||||
@ -773,7 +651,7 @@ impl<P: Params> WindowManager<P> {
|
||||
.try_for_each(|window| window.emit(event, payload.clone()))
|
||||
}
|
||||
|
||||
pub fn labels(&self) -> HashSet<P::Label> {
|
||||
pub fn labels(&self) -> HashSet<String> {
|
||||
self.windows_lock().keys().cloned().collect()
|
||||
}
|
||||
|
||||
@ -789,26 +667,22 @@ impl<P: Params> WindowManager<P> {
|
||||
self.inner.listeners.unlisten(handler_id)
|
||||
}
|
||||
|
||||
pub fn trigger<E: ?Sized>(&self, event: &E, window: Option<P::Label>, data: Option<String>)
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
{
|
||||
pub fn trigger(&self, event: &str, window: Option<String>, data: Option<String>) {
|
||||
self.inner.listeners.trigger(event, window, data)
|
||||
}
|
||||
|
||||
pub fn listen<F: Fn(Event) + Send + 'static>(
|
||||
&self,
|
||||
event: P::Event,
|
||||
window: Option<P::Label>,
|
||||
event: String,
|
||||
window: Option<String>,
|
||||
handler: F,
|
||||
) -> EventHandler {
|
||||
self.inner.listeners.listen(event, window, handler)
|
||||
}
|
||||
pub fn once<F: Fn(Event) + Send + 'static>(
|
||||
&self,
|
||||
event: P::Event,
|
||||
window: Option<P::Label>,
|
||||
event: String,
|
||||
window: Option<String>,
|
||||
handler: F,
|
||||
) -> EventHandler {
|
||||
self.inner.listeners.once(event, window, handler)
|
||||
@ -848,52 +722,28 @@ impl<P: Params> WindowManager<P> {
|
||||
.remove(&uuid)
|
||||
}
|
||||
|
||||
pub fn get_window<L: ?Sized>(&self, label: &L) -> Option<Window<P>>
|
||||
where
|
||||
P::Label: Borrow<L>,
|
||||
L: TagRef<P::Label>,
|
||||
{
|
||||
pub fn get_window(&self, label: &str) -> Option<Window<R>> {
|
||||
self.windows_lock().get(label).cloned()
|
||||
}
|
||||
|
||||
pub fn windows(&self) -> HashMap<P::Label, Window<P>> {
|
||||
pub fn windows(&self) -> HashMap<String, Window<R>> {
|
||||
self.windows_lock().clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn on_window_event<P: Params>(
|
||||
window: &Window<P>,
|
||||
manager: &WindowManager<P>,
|
||||
fn on_window_event<R: Runtime>(
|
||||
window: &Window<R>,
|
||||
manager: &WindowManager<R>,
|
||||
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<P: Params>(
|
||||
}
|
||||
}
|
||||
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<P: Params>(
|
||||
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<P: Params>(window: &Window<P>, event: &MenuEvent<P::MenuId>) -> crate::Result<()> {
|
||||
window.emit(
|
||||
&MENU_EVENT
|
||||
.parse()
|
||||
.unwrap_or_else(|_| panic!("unhandled event")),
|
||||
Some(event.menu_item_id.clone()),
|
||||
)
|
||||
fn on_menu_event<R: Runtime>(window: &Window<R>, event: &MenuEvent) -> crate::Result<()> {
|
||||
window.emit(MENU_EVENT, Some(event.menu_item_id.clone()))
|
||||
}
|
||||
|
@ -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<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
/// The plugin interface.
|
||||
pub trait Plugin<P: Params>: Send {
|
||||
pub trait Plugin<R: Runtime>: 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<P>, config: JsonValue) -> Result<()> {
|
||||
fn initialize(&mut self, app: &App<R>, config: JsonValue) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -33,25 +35,24 @@ pub trait Plugin<P: Params>: Send {
|
||||
|
||||
/// Callback invoked when the webview is created.
|
||||
#[allow(unused_variables)]
|
||||
fn created(&mut self, window: Window<P>) {}
|
||||
fn created(&mut self, window: Window<R>) {}
|
||||
|
||||
/// Callback invoked when the webview performs a navigation.
|
||||
#[allow(unused_variables)]
|
||||
fn on_page_load(&mut self, window: Window<P>, payload: PageLoadPayload) {}
|
||||
fn on_page_load(&mut self, window: Window<R>, payload: PageLoadPayload) {}
|
||||
|
||||
/// Add invoke_handler API extension commands.
|
||||
#[allow(unused_variables)]
|
||||
fn extend_api(&mut self, invoke: Invoke<P>) {}
|
||||
fn extend_api(&mut self, invoke: Invoke<R>) {}
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
/// Plugin collection type.
|
||||
pub(crate) struct PluginStore<P: Params> {
|
||||
store: HashMap<&'static str, Box<dyn Plugin<P>>>,
|
||||
}
|
||||
/// Plugin collection type.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub(crate) struct PluginStore<R: Runtime> {
|
||||
store: HashMap<&'static str, Box<dyn Plugin<R>>>,
|
||||
}
|
||||
|
||||
impl<P: Params> Default for PluginStore<P> {
|
||||
impl<R: Runtime> Default for PluginStore<R> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
store: HashMap::new(),
|
||||
@ -59,16 +60,16 @@ impl<P: Params> Default for PluginStore<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> PluginStore<P> {
|
||||
impl<R: Runtime> PluginStore<R> {
|
||||
/// Adds a plugin to the store.
|
||||
///
|
||||
/// Returns `true` if a plugin with the same name is already in the store.
|
||||
pub fn register<Plug: Plugin<P> + 'static>(&mut self, plugin: Plug) -> bool {
|
||||
pub fn register<P: Plugin<R> + '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<P>, config: &PluginConfig) -> crate::Result<()> {
|
||||
pub(crate) fn initialize(&mut self, app: &App<R>, config: &PluginConfig) -> crate::Result<()> {
|
||||
self.store.values_mut().try_for_each(|plugin| {
|
||||
plugin
|
||||
.initialize(
|
||||
@ -91,7 +92,7 @@ impl<P: Params> PluginStore<P> {
|
||||
}
|
||||
|
||||
/// Runs the created hook for all plugins in the store.
|
||||
pub(crate) fn created(&mut self, window: Window<P>) {
|
||||
pub(crate) fn created(&mut self, window: Window<R>) {
|
||||
self
|
||||
.store
|
||||
.values_mut()
|
||||
@ -99,14 +100,14 @@ impl<P: Params> PluginStore<P> {
|
||||
}
|
||||
|
||||
/// Runs the on_page_load hook for all plugins in the store.
|
||||
pub(crate) fn on_page_load(&mut self, window: Window<P>, payload: PageLoadPayload) {
|
||||
pub(crate) fn on_page_load(&mut self, window: Window<R>, 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<P>) {
|
||||
pub(crate) fn extend_api(&mut self, mut invoke: Invoke<R>) {
|
||||
let command = invoke.message.command.replace("plugin:", "");
|
||||
let mut tokens = command.split('|');
|
||||
// safe to unwrap: split always has a least one item
|
||||
|
@ -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<T: Send + Sync + 'static> 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<Self, InvokeError> {
|
||||
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
|
||||
Ok(command.message.state_ref().get())
|
||||
}
|
||||
}
|
||||
|
@ -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<P: Params>(
|
||||
pub(crate) async fn check_update_with_dialog<R: Runtime>(
|
||||
updater_config: UpdaterConfig,
|
||||
package_info: crate::api::PackageInfo,
|
||||
window: Window<P>,
|
||||
window: Window<R>,
|
||||
) {
|
||||
if let Some(endpoints) = updater_config.endpoints.clone() {
|
||||
// check updates
|
||||
@ -418,106 +418,96 @@ pub(crate) async fn check_update_with_dialog<P: Params>(
|
||||
|
||||
/// Experimental listener
|
||||
/// This function should be run on the main thread once.
|
||||
pub(crate) fn listener<P: Params>(
|
||||
pub(crate) fn listener<R: Runtime>(
|
||||
updater_config: UpdaterConfig,
|
||||
package_info: crate::api::PackageInfo,
|
||||
window: &Window<P>,
|
||||
window: &Window<R>,
|
||||
) {
|
||||
let isolated_window = window.clone();
|
||||
|
||||
// Wait to receive the event `"tauri://update"`
|
||||
window.listen(
|
||||
EVENT_CHECK_UPDATE
|
||||
.parse::<P::Event>()
|
||||
.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::<P::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::<P::Event>()
|
||||
.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<P: Params>(window: Window<P>, status: &str, error: Option<String>) {
|
||||
fn send_status_update<R: Runtime>(window: Window<R>, status: &str, error: Option<String>) {
|
||||
let _ = window.emit(
|
||||
&tauri_event::<P::Event>(EVENT_STATUS_UPDATE),
|
||||
EVENT_STATUS_UPDATE,
|
||||
Some(StatusEvent {
|
||||
error,
|
||||
status: String::from(status),
|
||||
|
@ -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<P: Params> {
|
||||
/// The webview window created by the runtime.
|
||||
window: DetachedWindow<P>,
|
||||
/// The manager to associate this webview window with.
|
||||
manager: WindowManager<P>,
|
||||
pub(crate) app_handle: AppHandle<P>,
|
||||
}
|
||||
/// 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<R: Runtime> {
|
||||
/// The webview window created by the runtime.
|
||||
window: DetachedWindow<R>,
|
||||
/// The manager to associate this webview window with.
|
||||
manager: WindowManager<R>,
|
||||
pub(crate) app_handle: AppHandle<R>,
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for Window<P> {
|
||||
impl<R: Runtime> Clone for Window<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
window: self.window.clone(),
|
||||
@ -107,49 +104,49 @@ impl<P: Params> Clone for Window<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Hash for Window<P> {
|
||||
impl<R: Runtime> Hash for Window<R> {
|
||||
/// Only use the [`Window`]'s label to represent its hash.
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.window.label.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Eq for Window<P> {}
|
||||
impl<P: Params> PartialEq for Window<P> {
|
||||
impl<R: Runtime> Eq for Window<R> {}
|
||||
impl<R: Runtime> PartialEq for Window<R> {
|
||||
/// Only use the [`Window`]'s label to compare equality.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.window.label.eq(&other.window.label)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Manager<P> for Window<P> {}
|
||||
impl<P: Params> ManagerBase<P> for Window<P> {
|
||||
fn manager(&self) -> &WindowManager<P> {
|
||||
impl<R: Runtime> Manager<R> for Window<R> {}
|
||||
impl<R: Runtime> ManagerBase<R> for Window<R> {
|
||||
fn manager(&self) -> &WindowManager<R> {
|
||||
&self.manager
|
||||
}
|
||||
|
||||
fn app_handle(&self) -> AppHandle<P> {
|
||||
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<R> {
|
||||
self.app_handle.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, P: Params> CommandArg<'de, P> for Window<P> {
|
||||
impl<'de, R: Runtime> CommandArg<'de, R> for Window<R> {
|
||||
/// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
|
||||
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
|
||||
Ok(command.message.window())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Window<P> {
|
||||
impl<R: Runtime> Window<R> {
|
||||
/// Create a new window that is attached to the manager.
|
||||
pub(crate) fn new(
|
||||
manager: WindowManager<P>,
|
||||
window: DetachedWindow<P>,
|
||||
app_handle: AppHandle<P>,
|
||||
manager: WindowManager<R>,
|
||||
window: DetachedWindow<R>,
|
||||
app_handle: AppHandle<R>,
|
||||
) -> Self {
|
||||
Self {
|
||||
window,
|
||||
@ -161,21 +158,21 @@ impl<P: Params> Window<P> {
|
||||
/// Creates a new webview window.
|
||||
pub fn create_window<F>(
|
||||
&mut self,
|
||||
label: P::Label,
|
||||
label: String,
|
||||
url: WindowUrl,
|
||||
setup: F,
|
||||
) -> crate::Result<Window<P>>
|
||||
) -> crate::Result<Window<R>>
|
||||
where
|
||||
F: FnOnce(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
<R::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
) -> (
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
<R::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
),
|
||||
{
|
||||
let (window_builder, webview_attributes) = setup(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder::new(),
|
||||
<R::Dispatcher as Dispatch>::WindowBuilder::new(),
|
||||
WebviewAttributes::new(url),
|
||||
);
|
||||
self.create_new_window(PendingWindow::new(
|
||||
@ -186,7 +183,7 @@ impl<P: Params> Window<P> {
|
||||
}
|
||||
|
||||
/// The current window's dispatcher.
|
||||
pub(crate) fn dispatcher(&self) -> <P::Runtime as Runtime>::Dispatcher {
|
||||
pub(crate) fn dispatcher(&self) -> R::Dispatcher {
|
||||
self.window.dispatcher.clone()
|
||||
}
|
||||
|
||||
@ -238,21 +235,16 @@ impl<P: Params> Window<P> {
|
||||
}
|
||||
|
||||
/// 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<E: ?Sized, S>(&self, event: &E, payload: S) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize,
|
||||
{
|
||||
pub fn emit<S: Serialize>(&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<P: Params> Window<P> {
|
||||
}
|
||||
|
||||
/// Emits an event on all windows except this one.
|
||||
pub fn emit_others<E: ?Sized, S>(&self, event: &E, payload: S) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize + Clone,
|
||||
{
|
||||
pub fn emit_others<S: Serialize + Clone>(&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<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
pub fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(Event) + Send + 'static,
|
||||
{
|
||||
@ -280,7 +267,7 @@ impl<P: Params> Window<P> {
|
||||
}
|
||||
|
||||
/// Listen to a an event on this window a single time.
|
||||
pub fn once<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
pub fn once<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(Event) + Send + 'static,
|
||||
{
|
||||
@ -289,11 +276,7 @@ impl<P: Params> Window<P> {
|
||||
}
|
||||
|
||||
/// Triggers an event on this window.
|
||||
pub fn trigger<E: ?Sized>(&self, event: &E, data: Option<String>)
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
{
|
||||
pub fn trigger(&self, event: &str, data: Option<String>) {
|
||||
let label = self.window.label.clone();
|
||||
self.manager.trigger(event, Some(label), data)
|
||||
}
|
||||
@ -311,7 +294,7 @@ impl<P: Params> Window<P> {
|
||||
/// Registers a menu event listener.
|
||||
#[cfg(feature = "menu")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))]
|
||||
pub fn on_menu_event<F: Fn(MenuEvent<P::MenuId>) + Send + 'static>(&self, f: F) -> uuid::Uuid {
|
||||
pub fn on_menu_event<F: Fn(MenuEvent) + Send + 'static>(&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<P: Params> Window<P> {
|
||||
|
||||
/// Gets a handle to the window menu.
|
||||
#[cfg(feature = "menu")]
|
||||
pub fn menu_handle(&self) -> MenuHandle<P> {
|
||||
pub fn menu_handle(&self) -> MenuHandle<R> {
|
||||
MenuHandle {
|
||||
ids: self.manager.menu_ids(),
|
||||
dispatcher: self.dispatcher(),
|
||||
|
@ -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<I: MenuId> {
|
||||
pub(crate) menu_item_id: I,
|
||||
pub struct MenuEvent {
|
||||
pub(crate) menu_item_id: MenuId,
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
impl<I: MenuId> MenuEvent<I> {
|
||||
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<P: Params> {
|
||||
pub(crate) ids: HashMap<u16, P::MenuId>,
|
||||
pub(crate) dispatcher: <P::Runtime as Runtime>::Dispatcher,
|
||||
}
|
||||
/// A handle to a system tray. Allows updating the context menu items.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct MenuHandle<R: Runtime> {
|
||||
pub(crate) ids: HashMap<MenuHash, MenuId>,
|
||||
pub(crate) dispatcher: R::Dispatcher,
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for MenuHandle<P> {
|
||||
impl<R: Runtime> Clone for MenuHandle<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
ids: self.ids.clone(),
|
||||
@ -41,15 +42,14 @@ impl<P: Params> Clone for MenuHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
crate::manager::default_args! {
|
||||
/// A handle to a system tray menu item.
|
||||
pub struct MenuItemHandle<P: Params> {
|
||||
id: u16,
|
||||
dispatcher: <P::Runtime as Runtime>::Dispatcher,
|
||||
}
|
||||
/// A handle to a system tray menu item.
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct MenuItemHandle<R: Runtime> {
|
||||
id: u16,
|
||||
dispatcher: R::Dispatcher,
|
||||
}
|
||||
|
||||
impl<P: Params> Clone for MenuItemHandle<P> {
|
||||
impl<R: Runtime> Clone for MenuItemHandle<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
id: self.id,
|
||||
@ -58,9 +58,9 @@ impl<P: Params> Clone for MenuItemHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> MenuHandle<P> {
|
||||
impl<R: Runtime> MenuHandle<R> {
|
||||
/// Gets a handle to the menu item that has the specified `id`.
|
||||
pub fn get_item(&self, id: &P::MenuId) -> MenuItemHandle<P> {
|
||||
pub fn get_item(&self, id: MenuIdRef<'_>) -> MenuItemHandle<R> {
|
||||
for (raw, item_id) in self.ids.iter() {
|
||||
if item_id == id {
|
||||
return MenuItemHandle {
|
||||
@ -107,7 +107,7 @@ impl<P: Params> MenuHandle<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> MenuItemHandle<P> {
|
||||
impl<R: Runtime> MenuItemHandle<R> {
|
||||
/// Modifies the enabled state of the menu item.
|
||||
pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
|
||||
self
|
||||
|
@ -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<P: Params> {
|
||||
invoke_handler: Box<dyn Fn(Invoke<P>) + Send + Sync>,
|
||||
struct MyAwesomePlugin<R: Runtime> {
|
||||
invoke_handler: Box<dyn Fn(Invoke<R>) + 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<P: Params> MyAwesomePlugin<P> {
|
||||
impl<R: Runtime> MyAwesomePlugin<R> {
|
||||
// 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<P: Params> MyAwesomePlugin<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Plugin<P> for MyAwesomePlugin<P> {
|
||||
impl<R: Runtime> Plugin<R> for MyAwesomePlugin<R> {
|
||||
/// The plugin name. Must be defined and used on the `invoke` calls.
|
||||
fn name(&self) -> &'static str {
|
||||
"awesome"
|
||||
@ -59,18 +59,18 @@ impl<P: Params> Plugin<P> for MyAwesomePlugin<P> {
|
||||
}
|
||||
|
||||
/// initialize plugin with the config provided on `tauri.conf.json > plugins > $yourPluginName` or the default value.
|
||||
fn initialize(&mut self, app: &App<P>, config: serde_json::Value) -> PluginResult<()> {
|
||||
fn initialize(&mut self, app: &App<R>, config: serde_json::Value) -> PluginResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Callback invoked when the Window is created.
|
||||
fn created(&mut self, window: Window<P>) {}
|
||||
fn created(&mut self, window: Window<R>) {}
|
||||
|
||||
/// Callback invoked when the webview performs a navigation.
|
||||
fn on_page_load(&mut self, window: Window<P>, payload: PageLoadPayload) {}
|
||||
fn on_page_load(&mut self, window: Window<R>, payload: PageLoadPayload) {}
|
||||
|
||||
/// Extend the invoke handler.
|
||||
fn extend_api(&mut self, message: Invoke<P>) {
|
||||
fn extend_api(&mut self, message: Invoke<R>) {
|
||||
(self.invoke_handler)(message)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
use tauri::{CustomMenuItem, Menu, MenuItem, Submenu};
|
||||
|
||||
pub fn get_menu() -> Menu<String> {
|
||||
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<String> {
|
||||
|
||||
let test_menu = Menu::new()
|
||||
.add_item(CustomMenuItem::new(
|
||||
"selected/disabled".into(),
|
||||
"selected/disabled",
|
||||
"Selected and disabled",
|
||||
))
|
||||
.add_native_item(MenuItem::Separator)
|
||||
|
@ -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<P: Params>(_: Window<P>) {
|
||||
fn command_arguments_wild(_: Window) {
|
||||
println!("we saw the wildcard!")
|
||||
}
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Params</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Simple custom `Params` types check.</h1>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "params",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"tauri": "node ../../tooling/cli.js/bin/tauri"
|
||||
}
|
||||
}
|
10
examples/params/src-tauri/.gitignore
vendored
10
examples/params/src-tauri/.gitignore
vendored
@ -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
|
@ -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
|
@ -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" ]
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<Event = Event, Label = Window, MenuId = Menu, SystemTrayMenuId = SystemMenu>
|
||||
{
|
||||
}
|
||||
impl<P> Params for P where
|
||||
P: tauri::Params<Event = Event, Label = Window, MenuId = Menu, SystemTrayMenuId = SystemMenu>
|
||||
{
|
||||
}
|
||||
|
||||
#[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<Self, Self::Err> {
|
||||
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<dyn std::error::Error>;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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<impl Params>) {
|
||||
dbg!(window.label());
|
||||
}
|
||||
|
||||
#[command]
|
||||
fn send_foo(window: tauri::Window<impl Params>) {
|
||||
window
|
||||
.emit(&Event::Foo, ())
|
||||
.expect("couldn't send Event::Foo");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::<Event, Window, Menu, SystemMenu, _, Wry>::new()
|
||||
.invoke_handler(tauri::generate_handler![log_window_label, send_foo])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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<P: Params>(Arc<Mutex<Window<P>>>);
|
||||
struct MainWindow<P: Params>(Arc<Mutex<Window<P>>>);
|
||||
struct SplashscreenWindow(Arc<Mutex<Window>>);
|
||||
struct MainWindow(Arc<Mutex<Window>>);
|
||||
|
||||
#[tauri::command]
|
||||
fn close_splashscreen<P: Params>(
|
||||
_: Window<P>, // force inference of P
|
||||
splashscreen: State<SplashscreenWindow<P>>,
|
||||
main: State<MainWindow<P>>,
|
||||
fn close_splashscreen(
|
||||
_: Window, // force inference of P
|
||||
splashscreen: State<SplashscreenWindow>,
|
||||
main: State<MainWindow>,
|
||||
) {
|
||||
// Close splashscreen
|
||||
splashscreen.0.lock().unwrap().close().unwrap();
|
||||
|
@ -1,5 +1,5 @@
|
||||
#[tauri::command(with_window)]
|
||||
fn exit<M: tauri::Params>(window: tauri::Window<P>) {
|
||||
fn exit(window: tauri::Window) {
|
||||
window.close().unwrap();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user