From 7fab1c039bd2a50bea7dc96a681ef734e2cf1635 Mon Sep 17 00:00:00 2001 From: chip Date: Sun, 11 Apr 2021 16:44:01 -0700 Subject: [PATCH] refactor(tauri): expose all items meant to be public (#1454) --- core/tauri-codegen/src/context.rs | 4 +- core/tauri-macros/src/lib.rs | 13 +- core/tauri/src/endpoints.rs | 2 +- core/tauri/src/endpoints/event.rs | 5 +- core/tauri/src/endpoints/global_shortcut.rs | 2 +- core/tauri/src/endpoints/internal.rs | 2 +- core/tauri/src/endpoints/shell.rs | 2 +- core/tauri/src/endpoints/window.rs | 13 +- core/tauri/src/error.rs | 2 +- core/tauri/src/hooks.rs | 3 +- core/tauri/src/lib.rs | 291 +++++++++- core/tauri/src/plugin.rs | 6 +- core/tauri/src/runtime/app.rs | 21 +- .../src/runtime/{flavor => flavors}/mod.rs | 0 .../src/runtime/{flavor => flavors}/wry.rs | 87 +-- core/tauri/src/runtime/manager.rs | 16 +- core/tauri/src/runtime/mod.rs | 278 +--------- core/tauri/src/runtime/tag.rs | 4 +- core/tauri/src/runtime/webview.rs | 46 +- core/tauri/src/runtime/window.rs | 518 +++++++++--------- core/tauri/src/{runtime => }/updater.rs | 4 +- 21 files changed, 683 insertions(+), 636 deletions(-) rename core/tauri/src/runtime/{flavor => flavors}/mod.rs (100%) rename core/tauri/src/runtime/{flavor => flavors}/wry.rs (89%) rename core/tauri/src/{runtime => }/updater.rs (98%) diff --git a/core/tauri-codegen/src/context.rs b/core/tauri-codegen/src/context.rs index 70f47a3d4..3dac30d34 100644 --- a/core/tauri-codegen/src/context.rs +++ b/core/tauri-codegen/src/context.rs @@ -8,7 +8,7 @@ use quote::quote; use std::path::PathBuf; use tauri_api::config::Config; -/// Necessary data needed by [`codegen_context`] to generate code for a Tauri application context. +/// Necessary data needed by [`context_codegen`] to generate code for a Tauri application context. pub struct ContextData { pub dev: bool, pub config: Config, @@ -16,7 +16,7 @@ pub struct ContextData { pub context_path: TokenStream, } -/// Build an `AsTauriContext` implementation for including in application code. +/// Build a `tauri::Context` for including in application code. pub fn context_codegen(data: ContextData) -> Result { let ContextData { dev, diff --git a/core/tauri-macros/src/lib.rs b/core/tauri-macros/src/lib.rs index 122da6cdc..f1cae1b6c 100644 --- a/core/tauri-macros/src/lib.rs +++ b/core/tauri-macros/src/lib.rs @@ -26,18 +26,7 @@ pub fn generate_handler(item: TokenStream) -> TokenStream { gen.into() } -/// Reads a Tauri config file and generates an [`AsTauriContext`] based on the content. -/// -/// The default config file path is a `tauri.conf.json` file inside the Cargo manifest directory of -/// the crate being built. -/// -/// # Custom Config Path -/// -/// You may pass a string literal to this macro to specify a custom path for the Tauri config file. -/// If the path is relative, it will be search for relative to the Cargo manifest of the compiling -/// crate. -/// -/// todo: link the [`AsTauriContext`] docs +/// Reads a Tauri config file and generates a `::tauri::Context` based on the content. #[proc_macro] pub fn generate_context(items: TokenStream) -> TokenStream { // this macro is exported from the context module diff --git a/core/tauri/src/endpoints.rs b/core/tauri/src/endpoints.rs index ca5e7457f..d1586e928 100644 --- a/core/tauri/src/endpoints.rs +++ b/core/tauri/src/endpoints.rs @@ -5,7 +5,7 @@ use crate::{ api::{config::Config, PackageInfo}, hooks::InvokeMessage, - runtime::Params, + Params, }; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; diff --git a/core/tauri/src/endpoints/event.rs b/core/tauri/src/endpoints/event.rs index 4afab8e7a..c4b57a0e9 100644 --- a/core/tauri/src/endpoints/event.rs +++ b/core/tauri/src/endpoints/event.rs @@ -2,10 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::{ - endpoints::InvokeResponse, - runtime::{sealed::ManagerPrivate, window::Window, Manager, Params}, -}; +use crate::{endpoints::InvokeResponse, sealed::ManagerPrivate, Manager, Params, Window}; use serde::Deserialize; /// The API descriptor. diff --git a/core/tauri/src/endpoints/global_shortcut.rs b/core/tauri/src/endpoints/global_shortcut.rs index c9803493f..22909d5be 100644 --- a/core/tauri/src/endpoints/global_shortcut.rs +++ b/core/tauri/src/endpoints/global_shortcut.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use super::InvokeResponse; -use crate::runtime::{window::Window, Dispatch, Params}; +use crate::{runtime::Dispatch, Params, Window}; use once_cell::sync::Lazy; use serde::Deserialize; use std::sync::{Arc, Mutex}; diff --git a/core/tauri/src/endpoints/internal.rs b/core/tauri/src/endpoints/internal.rs index 872f75ee3..6049308b5 100644 --- a/core/tauri/src/endpoints/internal.rs +++ b/core/tauri/src/endpoints/internal.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use super::InvokeResponse; -use crate::{runtime::window::Window, Params}; +use crate::{Params, Window}; use serde::Deserialize; /// The API descriptor. diff --git a/core/tauri/src/endpoints/shell.rs b/core/tauri/src/endpoints/shell.rs index 20a5ec6d2..8ec855c79 100644 --- a/core/tauri/src/endpoints/shell.rs +++ b/core/tauri/src/endpoints/shell.rs @@ -8,7 +8,7 @@ use crate::{ rpc::format_callback, }, endpoints::InvokeResponse, - runtime::{window::Window, Params}, + Params, Window, }; use once_cell::sync::Lazy; use serde::Deserialize; diff --git a/core/tauri/src/endpoints/window.rs b/core/tauri/src/endpoints/window.rs index cf83974b0..f73bad2d3 100644 --- a/core/tauri/src/endpoints/window.rs +++ b/core/tauri/src/endpoints/window.rs @@ -3,15 +3,12 @@ // SPDX-License-Identifier: MIT use crate::{ - endpoints::InvokeResponse, - runtime::{ - webview::{Icon, WindowConfig}, - window::{PendingWindow, Window}, - Manager, Params, - }, + api::config::WindowConfig, endpoints::InvokeResponse, runtime::window::PendingWindow, Manager, + Params, Window, }; use serde::Deserialize; +use crate::Icon; use std::path::PathBuf; #[derive(Deserialize)] @@ -35,7 +32,7 @@ impl Into for IconDto { #[serde(tag = "cmd", rename_all = "camelCase")] pub enum Cmd { CreateWebview { - options: crate::api::config::WindowConfig, + options: WindowConfig, }, SetResizable { resizable: bool, @@ -123,7 +120,7 @@ impl Cmd { }); let url = options.url.clone(); - let pending = PendingWindow::new(WindowConfig(options), label.clone(), url); + let pending = PendingWindow::with_config(options, label.clone(), url); window.create_window(pending)?.emit_others_internal( "tauri://window-created".to_string(), Some(WindowCreatedEvent { diff --git a/core/tauri/src/error.rs b/core/tauri/src/error.rs index 20ac9ff4e..e3d56ca1a 100644 --- a/core/tauri/src/error.rs +++ b/core/tauri/src/error.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -/// The plugin error type. +/// Runtime errors that can happen inside a Tauri application. #[derive(Debug, thiserror::Error)] pub enum Error { /// Failed to create webview. diff --git a/core/tauri/src/hooks.rs b/core/tauri/src/hooks.rs index 1ac5cc323..40ccf4386 100644 --- a/core/tauri/src/hooks.rs +++ b/core/tauri/src/hooks.rs @@ -4,7 +4,8 @@ use crate::{ api::rpc::{format_callback, format_callback_result}, - runtime::{app::App, window::Window, Params}, + runtime::app::App, + Params, Window, }; use serde::{Deserialize, Serialize}; use std::future::Future; diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index a96e23598..2114a45af 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -14,7 +14,7 @@ pub use error::Error; pub use tauri_api as api; pub(crate) use tauri_api::private::async_runtime; -pub use tauri_macros::*; +pub use tauri_macros::{command, generate_handler}; /// The Tauri-specific settings for your runtime e.g. notification permission status. pub mod settings; @@ -24,28 +24,63 @@ mod endpoints; mod error; mod event; mod hooks; -/// The plugin manager module contains helpers to manage runtime plugins. pub mod plugin; -/// The internal runtime between an [`App`] and the webview. pub mod runtime; +#[cfg(feature = "updater")] +mod updater; -/// Tauri result type. +/// `Result` pub type Result = std::result::Result; /// A task to run on the main thread. pub type SyncTask = Box; -/// types likely to be used by applications +use crate::api::assets::Assets; +use crate::api::config::Config; +use crate::event::{Event, EventHandler}; +use crate::runtime::tag::Tag; +use crate::runtime::window::PendingWindow; +use crate::runtime::{Dispatch, Runtime}; +use serde::Serialize; +use std::collections::HashMap; +use std::path::PathBuf; + +// Export types likely to be used by the application. pub use { api::config::WindowUrl, hooks::InvokeMessage, - runtime::app::Builder, + runtime::app::{App, Builder}, runtime::webview::Attributes, - runtime::window::Window, - runtime::{Context, Manager, Params}, + runtime::window::export::Window, }; -/// Easy helper function to use the Tauri Context you made during build time. +/// Reads the config file at compile time and generates a [`Context`] based on its content. +/// +/// The default config file path is a `tauri.conf.json` file inside the Cargo manifest directory of +/// the crate being built. +/// +/// # Custom Config Path +/// +/// You may pass a string literal to this macro to specify a custom path for the Tauri config file. +/// If the path is relative, it will be search for relative to the Cargo manifest of the compiling +/// crate. +/// +/// # Note +/// +/// This macro should not be called if you are using [`tauri-build`] to generate the context from +/// inside your build script as it will just cause excess computations that will be discarded. Use +/// either the [`tauri-build] method or this macro - not both. +/// +/// [`tauri-build`]: https://docs.rs/tauri-build +pub use tauri_macros::generate_context; + +/// Include a [`Context`] that was generated by [`tauri-build`] inside your build script. +/// +/// You should either use [`tauri-build`] and this macro to include the compile time generated code, +/// or [`generate_context!`]. Do not use both at the same time, as they generate the same code and +/// will cause excess computations that will be discarded. +/// +/// [`tauri-build`]: https://docs.rs/tauri-build #[macro_export] macro_rules! tauri_build_context { () => { @@ -53,6 +88,244 @@ macro_rules! tauri_build_context { }; } +/// A icon definition. +pub enum Icon { + /// Icon from file path. + File(PathBuf), + /// Icon from raw bytes. + Raw(Vec), +} + +/// User supplied data required inside of a Tauri application. +pub struct Context { + /// The config the application was prepared with. + pub config: Config, + + /// The assets to be served directly by Tauri. + pub assets: A, + + /// The default window icon Tauri should use when creating windows. + pub default_window_icon: Option>, + + /// Package information. + pub package_info: tauri_api::PackageInfo, +} + +/// Types associated with the running Tauri application. +pub trait Params: sealed::ParamsPrivate { + /// 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; + + /// Assets that Tauri should serve from itself. + type Assets: Assets; + + /// The underlying webview runtime used by the Tauri application. + type Runtime: Runtime; +} + +/// Manages a running application. +pub trait Manager: sealed::ManagerPrivate { + /// The [`Config`] the manager was created with. + fn config(&self) -> &Config { + self.manager().config() + } + + /// Emits a event to all windows. + fn emit_all(&self, event: M::Event, payload: Option) -> Result<()> { + self.manager().emit_filter(event, payload, |_| true) + } + + /// Emits an event to a window with the specified label. + fn emit_to( + &self, + label: &M::Label, + event: M::Event, + payload: Option, + ) -> Result<()> { + self + .manager() + .emit_filter(event, payload, |w| w.label() == label) + } + + /// Creates a new [`Window`] on the [`Runtime`] and attaches it to the [`Manager`]. + fn create_window(&mut self, pending: PendingWindow) -> Result> { + use sealed::RuntimeOrDispatch::*; + + let labels = self.manager().labels().into_iter().collect::>(); + let pending = self.manager().prepare_window(pending, &labels)?; + match self.runtime() { + Runtime(runtime) => runtime.create_window(pending), + Dispatch(mut dispatcher) => dispatcher.create_window(pending), + } + .map(|window| self.manager().attach_window(window)) + } + + /// Listen to a global event. + fn listen_global(&self, event: M::Event, handler: F) -> EventHandler + where + F: Fn(Event) + Send + 'static, + { + self.manager().listen(event, None, handler) + } + + /// Listen to a global event only once. + fn once_global(&self, event: M::Event, handler: F) + where + F: Fn(Event) + Send + 'static, + { + self.manager().once(event, None, handler) + } + + /// Trigger a global event. + fn trigger_global(&self, event: M::Event, data: Option) { + self.manager().trigger(event, None, data) + } + + /// Remove an event listener. + fn unlisten(&self, handler_id: EventHandler) { + self.manager().unlisten(handler_id) + } + + /// Fetch a single window from the manager. + fn get_window(&self, label: &M::Label) -> Option> { + self.manager().get_window(label) + } + + /// Fetch all managed windows. + fn windows(&self) -> HashMap> { + self.manager().windows() + } +} + +/// Prevent implementation details from leaking out of the [`Manager`] and [`Params`] traits. +pub(crate) mod sealed { + use super::Params; + use crate::runtime::Runtime; + use crate::{ + api::{config::Config, PackageInfo}, + event::{Event, EventHandler}, + hooks::{InvokeMessage, PageLoadPayload}, + runtime::window::{DetachedWindow, PendingWindow}, + Window, + }; + use serde::Serialize; + use std::collections::{HashMap, HashSet}; + use uuid::Uuid; + + /// private manager api + pub trait ParamsPrivate: Clone + Send + Sized + 'static { + /// Pass messages not handled by modules or plugins to the running application + fn run_invoke_handler(&self, message: InvokeMessage); + + /// Ran once for every window when the page is loaded. + fn run_on_page_load(&self, window: Window, payload: PageLoadPayload); + + /// Pass a message to be handled by a plugin that expects the command. + fn extend_api(&self, command: String, message: InvokeMessage); + + /// Initialize all the plugins attached to the [`Manager`]. + fn initialize_plugins(&self) -> crate::Result<()>; + + /// Prepare a [`PendingWindow`] to be created by the [`Runtime`]. + /// + /// The passed labels should represent either all the windows in the manager. If the application + /// has not yet been started, the passed labels should represent all windows that will be + /// created before starting. + fn prepare_window( + &self, + pending: PendingWindow, + labels: &[M::Label], + ) -> crate::Result>; + + /// Attach a detached window to the manager. + fn attach_window(&self, window: DetachedWindow) -> Window; + + /// Emit an event to javascript windows that pass the predicate. + fn emit_filter_internal) -> bool>( + &self, + event: String, + payload: Option, + filter: F, + ) -> crate::Result<()>; + + /// Emit an event to javascript windows that pass the predicate. + fn emit_filter) -> bool>( + &self, + event: M::Event, + payload: Option, + predicate: F, + ) -> crate::Result<()>; + + /// All current window labels existing. + fn labels(&self) -> HashSet; + + /// The configuration the [`Manager`] was built with. + fn config(&self) -> &Config; + + /// App package information. + fn package_info(&self) -> &PackageInfo; + + /// Remove the specified event handler. + fn unlisten(&self, handler_id: EventHandler); + + /// Trigger an event. + fn trigger(&self, event: M::Event, window: Option, data: Option); + + /// Set up a listener to an event. + fn listen( + &self, + event: M::Event, + window: Option, + handler: F, + ) -> EventHandler; + + /// Set up a listener to and event that is automatically removed after called once. + fn once( + &self, + event: M::Event, + window: Option, + handler: F, + ); + + fn event_listeners_object_name(&self) -> String; + fn event_queue_object_name(&self) -> String; + fn event_emit_function_name(&self) -> String; + + /// Generate a random salt and store it in the manager + fn generate_salt(&self) -> Uuid; + + /// Verify that the passed salt is a valid salt in the manager. + fn verify_salt(&self, salt: String) -> bool; + + /// Get a single managed window. + fn get_window(&self, label: &M::Label) -> Option>; + + /// Get all managed windows. + fn windows(&self) -> HashMap>; + } + + /// Represents either a running [`Runtime`] or a dispatcher to it. + pub enum RuntimeOrDispatch<'m, M: Params> { + /// Mutable reference to the running [`Runtime`]. + Runtime(&'m mut M::Runtime), + + /// A dispatcher to the running [`Runtime`]. + Dispatch(::Dispatcher), + } + + /// Represents a managed handle to the application runner. + pub trait ManagerPrivate { + /// The manager behind the [`Managed`] item. + fn manager(&self) -> &M; + + /// The runtime or runtime dispatcher of the [`Managed`] item. + fn runtime(&mut self) -> RuntimeOrDispatch<'_, M>; + } +} + #[cfg(test)] mod test { use proptest::prelude::*; diff --git a/core/tauri/src/plugin.rs b/core/tauri/src/plugin.rs index 2e78571a4..be0bba8b3 100644 --- a/core/tauri/src/plugin.rs +++ b/core/tauri/src/plugin.rs @@ -2,10 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +//! Extend Tauri functionality. + use crate::{ api::config::PluginConfig, hooks::{InvokeMessage, PageLoadPayload}, - runtime::{window::Window, Params}, + Params, Window, }; use serde_json::Value as JsonValue; use std::collections::HashMap; @@ -44,7 +46,7 @@ pub trait Plugin: Send { } /// Plugin collection type. -pub struct PluginStore { +pub(crate) struct PluginStore { store: HashMap<&'static str, Box>>, } diff --git a/core/tauri/src/runtime/app.rs b/core/tauri/src/runtime/app.rs index 068820b26..59f5c8466 100644 --- a/core/tauri/src/runtime/app.rs +++ b/core/tauri/src/runtime/app.rs @@ -7,18 +7,19 @@ use crate::{ hooks::{InvokeHandler, InvokeMessage, OnPageLoad, PageLoadPayload, SetupHook}, plugin::{Plugin, PluginStore}, runtime::{ - flavor::wry::Wry, - manager::WindowManager, - sealed::{ManagerPrivate, ParamsPrivate}, - tag::Tag, - updater, - webview::{Attributes, WindowConfig}, - window::{PendingWindow, Window}, - Context, Dispatch, Manager, Params, Runtime, RuntimeOrDispatch, + flavors::wry::Wry, manager::WindowManager, tag::Tag, webview::Attributes, + window::PendingWindow, Dispatch, Runtime, }, + sealed::{ManagerPrivate, ParamsPrivate, RuntimeOrDispatch}, + Context, Manager, Params, Window, }; +#[cfg(feature = "updater")] +use crate::updater; + /// A handle to the currently running application. +/// +/// This type implements [`Manager`] which allows for manipulation of global application items. pub struct App { runtime: P::Runtime, manager: P, @@ -94,7 +95,7 @@ impl App { } } -/// The App builder. +/// Builds a Tauri application. pub struct Builder where E: Tag, @@ -202,7 +203,7 @@ where self .pending_windows - .push(PendingWindow::new(WindowConfig(config), label, url)); + .push(PendingWindow::with_config(config, label, url)); } manager.initialize_plugins()?; diff --git a/core/tauri/src/runtime/flavor/mod.rs b/core/tauri/src/runtime/flavors/mod.rs similarity index 100% rename from core/tauri/src/runtime/flavor/mod.rs rename to core/tauri/src/runtime/flavors/mod.rs diff --git a/core/tauri/src/runtime/flavor/wry.rs b/core/tauri/src/runtime/flavors/wry.rs similarity index 89% rename from core/tauri/src/runtime/flavor/wry.rs rename to core/tauri/src/runtime/flavors/wry.rs index f55af3f15..b18b30370 100644 --- a/core/tauri/src/runtime/flavor/wry.rs +++ b/core/tauri/src/runtime/flavors/wry.rs @@ -2,15 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -//! The [`wry`] webview runtime. +//! The [`wry`] Tauri [`Runtime`]. -use crate::runtime::{ - webview::{ - Attributes, AttributesPrivate, CustomProtocol, FileDropEvent, FileDropHandler, Icon, - RpcRequest, WebviewRpcHandler, WindowConfig, +use crate::{ + api::config::WindowConfig, + runtime::{ + webview::{ + Attributes, AttributesBase, CustomProtocol, FileDropEvent, FileDropHandler, RpcRequest, + WebviewRpcHandler, + }, + window::{DetachedWindow, PendingWindow}, + Dispatch, Params, Runtime, }, - window::{DetachedWindow, PendingWindow}, - Dispatch, Params, Runtime, + Icon, }; use std::{convert::TryFrom, path::PathBuf}; @@ -19,7 +23,7 @@ use std::fs::create_dir_all; #[cfg(target_os = "windows")] use tauri_api::path::{resolve_path, BaseDirectory}; -/// Wraps a Tauri icon into a format [`wry`] expects the icon to be in. +/// Wrapper around a [`wry::Icon`] that can be created from an [`Icon`]. pub struct WryIcon(wry::Icon); impl TryFrom for WryIcon { @@ -37,42 +41,43 @@ impl TryFrom for WryIcon { } } -impl AttributesPrivate for wry::Attributes { - fn url(mut self, url: String) -> Self { - self.url.replace(url); - self - } -} +impl AttributesBase for wry::Attributes {} +impl Attributes for wry::Attributes { + type Icon = WryIcon; -impl From for wry::Attributes { - fn from(window_config: WindowConfig) -> Self { + fn new() -> Self { + Default::default() + } + + fn with_config(config: WindowConfig) -> Self { let mut webview = wry::Attributes::default() - .title(window_config.0.title.to_string()) - .width(window_config.0.width) - .height(window_config.0.height) - .visible(window_config.0.visible) - .resizable(window_config.0.resizable) - .decorations(window_config.0.decorations) - .maximized(window_config.0.maximized) - .fullscreen(window_config.0.fullscreen) - .transparent(window_config.0.transparent) - .always_on_top(window_config.0.always_on_top); - if let Some(min_width) = window_config.0.min_width { + .title(config.title.to_string()) + .width(config.width) + .height(config.height) + .visible(config.visible) + .resizable(config.resizable) + .decorations(config.decorations) + .maximized(config.maximized) + .fullscreen(config.fullscreen) + .transparent(config.transparent) + .always_on_top(config.always_on_top); + + if let Some(min_width) = config.min_width { webview = webview.min_width(min_width); } - if let Some(min_height) = window_config.0.min_height { + if let Some(min_height) = config.min_height { webview = webview.min_height(min_height); } - if let Some(max_width) = window_config.0.max_width { + if let Some(max_width) = config.max_width { webview = webview.max_width(max_width); } - if let Some(max_height) = window_config.0.max_height { + if let Some(max_height) = config.max_height { webview = webview.max_height(max_height); } - if let Some(x) = window_config.0.x { + if let Some(x) = config.x { webview = webview.x(x); } - if let Some(y) = window_config.0.y { + if let Some(y) = config.y { webview = webview.y(y); } @@ -101,15 +106,6 @@ impl From for wry::Attributes { webview } -} - -/// The webview builder. -impl Attributes for wry::Attributes { - type Icon = WryIcon; - - fn new() -> Self { - Default::default() - } fn initialization_script(mut self, init: &str) -> Self { self.initialization_scripts.push(init.to_string()); @@ -210,6 +206,11 @@ impl Attributes for wry::Attributes { self } + fn url(mut self, url: String) -> Self { + self.url.replace(url); + self + } + fn build(self) -> Self { self } @@ -234,7 +235,7 @@ impl From for FileDropEvent { } } -/// A dispatcher for a [`wry`] runtime. +/// The Tauri [`Dispatch`] for [`Wry`]. #[derive(Clone)] pub struct WryDispatcher { window: wry::WindowProxy, @@ -440,7 +441,7 @@ impl Dispatch for WryDispatcher { } } -/// A wrapper around the wry Application interface. +/// A Tauri [`Runtime`] wrapper around [`wry::Application`]. pub struct Wry { inner: wry::Application, } diff --git a/core/tauri/src/runtime/manager.rs b/core/tauri/src/runtime/manager.rs index 50c2228da..6c56bdde7 100644 --- a/core/tauri/src/runtime/manager.rs +++ b/core/tauri/src/runtime/manager.rs @@ -12,15 +12,13 @@ use crate::{ hooks::{InvokeHandler, InvokeMessage, InvokePayload, OnPageLoad, PageLoadPayload}, plugin::PluginStore, runtime::{ - sealed::ParamsPrivate, tag::{tags_to_javascript_array, Tag, ToJavascript}, - webview::{ - Attributes, AttributesPrivate, CustomProtocol, FileDropEvent, FileDropHandler, - WebviewRpcHandler, - }, - window::{DetachedWindow, PendingWindow, Window}, - Context, Dispatch, Icon, Params, Runtime, + webview::{Attributes, CustomProtocol, FileDropEvent, FileDropHandler, WebviewRpcHandler}, + window::{DetachedWindow, PendingWindow}, + Dispatch, Icon, Runtime, }, + sealed::ParamsPrivate, + Context, Params, Window, }; use serde::Serialize; use serde_json::Value as JsonValue; @@ -344,7 +342,7 @@ where #[cfg(test)] mod test { use super::WindowManager; - use crate::{generate_context, plugin::PluginStore, runtime::flavor::wry::Wry}; + use crate::{generate_context, plugin::PluginStore, runtime::flavors::wry::Wry}; #[test] fn check_get_url() { @@ -361,7 +359,7 @@ mod test { #[cfg(dev)] { - use crate::runtime::sealed::ParamsPrivate; + use crate::sealed::ParamsPrivate; assert_eq!(manager.get_url(), manager.config().build.dev_path); } } diff --git a/core/tauri/src/runtime/mod.rs b/core/tauri/src/runtime/mod.rs index b4f98984a..1ab3193af 100644 --- a/core/tauri/src/runtime/mod.rs +++ b/core/tauri/src/runtime/mod.rs @@ -2,43 +2,23 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +//! Internal runtime between Tauri and the underlying webview runtime. + use crate::{ - api::{assets::Assets, config::Config}, - event::{Event, EventHandler}, runtime::{ - webview::{Attributes, AttributesPrivate, Icon, WindowConfig}, - window::{DetachedWindow, PendingWindow, Window}, + webview::AttributesBase, + window::{DetachedWindow, PendingWindow}, }, + Attributes, Icon, Params, }; -use serde::Serialize; use std::convert::TryFrom; pub(crate) mod app; -pub mod flavor; +pub mod flavors; pub(crate) mod manager; -pub(crate) mod tag; -#[cfg(feature = "updater")] -pub(crate) mod updater; -pub(crate) mod webview; -pub(crate) mod window; - -pub use self::tag::Tag; -use std::collections::HashMap; - -/// Important configurable items required by Tauri. -pub struct Context { - /// The config the application was prepared with. - pub config: Config, - - /// The assets to be served directly by Tauri. - pub assets: A, - - /// The default window icon Tauri should use when creating windows. - pub default_window_icon: Option>, - - /// Package information. - pub package_info: tauri_api::PackageInfo, -} +pub mod tag; +pub mod webview; +pub mod window; /// The webview runtime interface. pub trait Runtime: Sized + 'static { @@ -48,11 +28,11 @@ pub trait Runtime: Sized + 'static { /// Creates a new webview runtime. fn new() -> crate::Result; - /// Creates a new webview window. - fn create_window>( + /// Create a new webview window. + fn create_window>( &mut self, - pending: PendingWindow, - ) -> crate::Result>; + pending: PendingWindow

, + ) -> crate::Result>; /// Run the webview runtime. fn run(self); @@ -67,17 +47,13 @@ pub trait Dispatch: Clone + Send + Sized + 'static { type Icon: TryFrom; /// The webview builder type. - type Attributes: Attributes - + AttributesPrivate - + From - + Clone - + Send; + type Attributes: Attributes + AttributesBase + Clone + Send; - /// Creates a new webview window. - fn create_window>( + /// Create a new webview window. + fn create_window>( &mut self, - pending: PendingWindow, - ) -> crate::Result>; + pending: PendingWindow

, + ) -> crate::Result>; /// Updates the window resizable flag. fn set_resizable(&self, resizable: bool) -> crate::Result<()>; @@ -145,221 +121,3 @@ pub trait Dispatch: Clone + Send + Sized + 'static { /// Executes javascript on the window this [`Dispatch`] represents. fn eval_script>(&self, script: S) -> crate::Result<()>; } - -/// Prevent implementation details from leaking out of the [`Manager`] and [`Managed`] traits. -pub(crate) mod sealed { - use super::Params; - use crate::{ - api::{config::Config, PackageInfo}, - event::{Event, EventHandler}, - hooks::{InvokeMessage, PageLoadPayload}, - runtime::{ - window::{DetachedWindow, PendingWindow, Window}, - RuntimeOrDispatch, - }, - }; - use serde::Serialize; - use std::collections::{HashMap, HashSet}; - use uuid::Uuid; - - /// private manager api - pub trait ParamsPrivate: Clone + Send + Sized + 'static { - /// Pass messages not handled by modules or plugins to the running application - fn run_invoke_handler(&self, message: InvokeMessage); - - /// Ran once for every window when the page is loaded. - fn run_on_page_load(&self, window: Window, payload: PageLoadPayload); - - /// Pass a message to be handled by a plugin that expects the command. - fn extend_api(&self, command: String, message: InvokeMessage); - - /// Initialize all the plugins attached to the [`Manager`]. - fn initialize_plugins(&self) -> crate::Result<()>; - - /// Prepare a [`PendingWindow`] to be created by the [`Runtime`]. - /// - /// The passed labels should represent either all the windows in the manager. If the application - /// has not yet been started, the passed labels should represent all windows that will be - /// created before starting. - fn prepare_window( - &self, - pending: PendingWindow, - labels: &[M::Label], - ) -> crate::Result>; - - /// Attach a detached window to the manager. - fn attach_window(&self, window: DetachedWindow) -> Window; - - /// Emit an event to javascript windows that pass the predicate. - fn emit_filter_internal) -> bool>( - &self, - event: String, - payload: Option, - filter: F, - ) -> crate::Result<()>; - - /// Emit an event to javascript windows that pass the predicate. - fn emit_filter) -> bool>( - &self, - event: M::Event, - payload: Option, - predicate: F, - ) -> crate::Result<()>; - - /// All current window labels existing. - fn labels(&self) -> HashSet; - - /// The configuration the [`Manager`] was built with. - fn config(&self) -> &Config; - - /// App package information. - fn package_info(&self) -> &PackageInfo; - - /// Remove the specified event handler. - fn unlisten(&self, handler_id: EventHandler); - - /// Trigger an event. - fn trigger(&self, event: M::Event, window: Option, data: Option); - - /// Set up a listener to an event. - fn listen( - &self, - event: M::Event, - window: Option, - handler: F, - ) -> EventHandler; - - /// Set up a listener to and event that is automatically removed after called once. - fn once( - &self, - event: M::Event, - window: Option, - handler: F, - ); - - fn event_listeners_object_name(&self) -> String; - fn event_queue_object_name(&self) -> String; - fn event_emit_function_name(&self) -> String; - - /// Generate a random salt and store it in the manager - fn generate_salt(&self) -> Uuid; - - /// Verify that the passed salt is a valid salt in the manager. - fn verify_salt(&self, salt: String) -> bool; - - /// Get a single managed window. - fn get_window(&self, label: &M::Label) -> Option>; - - /// Get all managed windows. - fn windows(&self) -> HashMap>; - } - - /// Represents a managed handle to the application runner. - pub trait ManagerPrivate { - /// The manager behind the [`Managed`] item. - fn manager(&self) -> &M; - - /// The runtime or runtime dispatcher of the [`Managed`] item. - fn runtime(&mut self) -> RuntimeOrDispatch<'_, M>; - } -} - -/// Represents either a [`Runtime`] or its dispatcher. -pub enum RuntimeOrDispatch<'m, M: Params> { - /// Mutable reference to the [`Runtime`]. - Runtime(&'m mut M::Runtime), - - /// Copy of the [`Runtime`]'s dispatcher. - Dispatch(::Dispatcher), -} - -/// Represents a managed handle to the application runner -pub trait Manager: sealed::ManagerPrivate { - /// The [`Config`] the manager was created with. - fn config(&self) -> &Config { - self.manager().config() - } - - /// Emits a event to all windows. - fn emit_all( - &self, - event: M::Event, - payload: Option, - ) -> crate::Result<()> { - self.manager().emit_filter(event, payload, |_| true) - } - - /// Emits an event to a window with the specified label. - fn emit_to( - &self, - label: &M::Label, - event: M::Event, - payload: Option, - ) -> crate::Result<()> { - self - .manager() - .emit_filter(event, payload, |w| w.label() == label) - } - - /// Creates a new [`Window`] on the [`Runtime`] and attaches it to the [`Manager`]. - fn create_window(&mut self, pending: PendingWindow) -> crate::Result> { - let labels = self.manager().labels().into_iter().collect::>(); - let pending = self.manager().prepare_window(pending, &labels)?; - match self.runtime() { - RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending), - RuntimeOrDispatch::Dispatch(mut dispatcher) => dispatcher.create_window(pending), - } - .map(|window| self.manager().attach_window(window)) - } - - /// Listen to a global event. - fn listen_global(&self, event: M::Event, handler: F) -> EventHandler - where - F: Fn(Event) + Send + 'static, - { - self.manager().listen(event, None, handler) - } - - /// Listen to a global event only once. - fn once_global(&self, event: M::Event, handler: F) - where - F: Fn(Event) + Send + 'static, - { - self.manager().once(event, None, handler) - } - - /// Trigger a global event. - fn trigger_global(&self, event: M::Event, data: Option) { - self.manager().trigger(event, None, data) - } - - /// Remove an event listener. - fn unlisten(&self, handler_id: EventHandler) { - self.manager().unlisten(handler_id) - } - - /// Fetch a single window from the manager. - fn get_window(&self, label: &M::Label) -> Option> { - self.manager().get_window(label) - } - - /// Fetch all managed windows. - fn windows(&self) -> HashMap> { - self.manager().windows() - } -} - -/// Types that the manager needs to have passed in by the application. -pub trait Params: sealed::ParamsPrivate { - /// 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; - - /// Assets that Tauri should serve from itself. - type Assets: Assets; - - /// The underlying webview runtime used by the Tauri application. - type Runtime: Runtime; -} diff --git a/core/tauri/src/runtime/tag.rs b/core/tauri/src/runtime/tag.rs index 817e51576..726e50e9a 100644 --- a/core/tauri/src/runtime/tag.rs +++ b/core/tauri/src/runtime/tag.rs @@ -26,7 +26,7 @@ use std::{ /// # Handling Errors /// /// Because we leave it up to the type to implement [`FromStr`], if an error is returned during -/// parsing then Tauri will [`panic!`](std::panic) with the string it failed to parse. +/// 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 @@ -71,7 +71,7 @@ use std::{ /// 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) { +/// fn is_file_drop(tag: impl tauri::runtime::tag::Tag) { /// assert_eq!("tauri://file-drop", tag.to_string()); /// } /// diff --git a/core/tauri/src/runtime/webview.rs b/core/tauri/src/runtime/webview.rs index d2f5c767e..cfcfa5857 100644 --- a/core/tauri/src/runtime/webview.rs +++ b/core/tauri/src/runtime/webview.rs @@ -2,33 +2,32 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::runtime::window::DetachedWindow; +//! Items specific to the [`Runtime`](crate::runtime::Runtime)'s webview. + +use crate::runtime::Icon; +use crate::{api::config::WindowConfig, runtime::window::DetachedWindow}; use serde_json::Value as JsonValue; use std::{convert::TryFrom, path::PathBuf}; -/// A icon definition. -pub enum Icon { - /// Icon from file path. - File(PathBuf), - /// Icon from raw bytes. - Raw(Vec), -} +/// Do **NOT** implement this trait except for use in a custom [`Runtime`](crate::runtime::Runtime). +/// +/// This trait is separate from [`Attributes`] to prevent "accidental" implementation. +pub trait AttributesBase: Sized {} -pub struct WindowConfig(pub crate::api::config::WindowConfig); - -pub trait AttributesPrivate: Sized { - /// Sets the webview url. - fn url(self, url: String) -> Self; -} - -/// The webview builder. -pub trait Attributes: Sized { +/// A builder for all attributes related to a single webview. +/// +/// This trait is only meant to be implemented by a custom [`Runtime`](crate::runtime::Runtime) +/// and not by applications. +pub trait Attributes: AttributesBase { /// Expected icon format. type Icon: TryFrom; /// Initializes a new webview builder. fn new() -> Self; + /// Initializes a new webview builder from a [`WindowConfig`] + fn with_config(config: WindowConfig) -> Self; + /// Sets the init script. fn initialization_script(self, init: &str) -> Self; @@ -90,12 +89,13 @@ pub trait Attributes: Sized { /// User data path for the webview. Actually only supported on Windows. fn user_data_path(self, user_data_path: Option) -> Self; + /// Sets the webview url. + fn url(self, url: String) -> Self; + /// The full attributes. fn build(self) -> Self; } -// TODO: should probably expand the following documentation - /// Rpc request. pub struct RpcRequest { /// RPC command. @@ -104,9 +104,6 @@ pub struct RpcRequest { pub params: Option, } -/// Rpc handler. -pub type WebviewRpcHandler = Box, RpcRequest) + Send>; - /// Uses a custom handler to resolve file requests pub struct CustomProtocol { /// Name of the protocol @@ -126,6 +123,9 @@ pub enum FileDropEvent { Cancelled, } +/// Rpc handler. +pub(crate) type WebviewRpcHandler = Box, RpcRequest) + Send>; + /// File drop handler callback /// Return `true` in the callback to block the OS' default behavior of handling a file drop. -pub type FileDropHandler = Box) -> bool + Send>; +pub(crate) type FileDropHandler = Box) -> bool + Send>; diff --git a/core/tauri/src/runtime/window.rs b/core/tauri/src/runtime/window.rs index fb5a9538c..4b50b518e 100644 --- a/core/tauri/src/runtime/window.rs +++ b/core/tauri/src/runtime/window.rs @@ -2,16 +2,20 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +//! A layer between raw [`Runtime`] webview windows and Tauri. + +use crate::api::config::WindowConfig; use crate::{ api::config::WindowUrl, event::{Event, EventHandler}, hooks::{InvokeMessage, InvokePayload, PageLoadPayload}, runtime::{ - sealed::ManagerPrivate, tag::ToJavascript, - webview::{CustomProtocol, FileDropHandler, Icon, WebviewRpcHandler}, - Dispatch, Manager, Params, Runtime, RuntimeOrDispatch, + webview::{CustomProtocol, FileDropHandler, WebviewRpcHandler}, + Dispatch, Runtime, }, + sealed::{ManagerPrivate, RuntimeOrDispatch}, + Attributes, Icon, Manager, Params, }; use serde::Serialize; use serde_json::Value as JsonValue; @@ -42,13 +46,28 @@ pub struct PendingWindow { } impl PendingWindow { + /// Create a new [`PendingWindow`] with a label and starting url. pub fn new( - attributes: impl Into<<::Dispatcher as Dispatch>::Attributes>, + attributes: <::Dispatcher as Dispatch>::Attributes, label: M::Label, url: WindowUrl, ) -> Self { Self { - attributes: attributes.into(), + attributes, + label, + url, + rpc_handler: None, + custom_protocol: None, + file_drop_handler: None, + } + } + + /// Create a new [`PendingWindow`] from a [`WindowConfig`] with a label and starting url. + pub fn with_config(window_config: WindowConfig, label: M::Label, url: WindowUrl) -> Self { + Self { + attributes: <<::Dispatcher as Dispatch>::Attributes>::with_config( + window_config, + ), label, url, rpc_handler: None, @@ -60,7 +79,10 @@ impl PendingWindow { /// A webview window that is not yet managed by Tauri. pub struct DetachedWindow { + /// Name of the window pub label: M::Label, + + /// The [`Dispatch`](crate::runtime::Dispatch) associated with the window. pub dispatcher: ::Dispatcher, } @@ -88,285 +110,293 @@ impl PartialEq for DetachedWindow { } } -/// A webview window managed by Tarui. -/// -/// TODO: expand these docs since this is a pretty important type -pub struct Window { - /// The webview window created by the runtime. - window: DetachedWindow, +/// We want to export the runtime related window at the crate root, but not look like a re-export. +pub(crate) mod export { + use super::*; - /// The manager to associate this webview window with. - manager: M, -} + /// A webview window managed by Tauri. + /// + /// This type also implements [`Manager`] which allows you to manage other windows attached to + /// the same application. + /// + /// TODO: expand these docs since this is a pretty important type + pub struct Window { + /// The webview window created by the runtime. + window: DetachedWindow, -impl Clone for Window { - fn clone(&self) -> Self { - Self { - window: self.window.clone(), - manager: self.manager.clone(), - } - } -} - -impl Hash for Window { - /// Only use the [`Window`]'s label to represent its hash. - fn hash(&self, state: &mut H) { - self.window.label.hash(state) - } -} - -impl Eq for Window {} -impl PartialEq for Window { - /// Only use the [`Window`]'s label to compare equality. - fn eq(&self, other: &Self) -> bool { - self.window.label.eq(&other.window.label) - } -} - -impl Manager for Window {} -impl ManagerPrivate for Window { - fn manager(&self) -> &M { - &self.manager + /// The manager to associate this webview window with. + manager: M, } - fn runtime(&mut self) -> RuntimeOrDispatch<'_, M> { - RuntimeOrDispatch::Dispatch(self.dispatcher()) - } -} - -impl Window { - /// Create a new window that is attached to the manager. - pub(crate) fn new(manager: M, window: DetachedWindow) -> Self { - Self { manager, window } - } - - /// The current window's dispatcher. - pub(crate) fn dispatcher(&self) -> ::Dispatcher { - self.window.dispatcher.clone() - } - - /// How to handle this window receiving an [`InvokeMessage`]. - pub(crate) fn on_message(self, command: String, payload: InvokePayload) -> crate::Result<()> { - let manager = self.manager.clone(); - if &command == "__initialized" { - let payload: PageLoadPayload = serde_json::from_value(payload.inner)?; - manager.run_on_page_load(self, payload); - } else { - let message = InvokeMessage::new(self, command.to_string(), payload); - if let Some(module) = &message.payload.tauri_module { - let module = module.to_string(); - crate::endpoints::handle(module, message, manager.config(), manager.package_info()); - } else if command.starts_with("plugin:") { - manager.extend_api(command, message); - } else { - manager.run_invoke_handler(message); + impl Clone for Window { + fn clone(&self) -> Self { + Self { + window: self.window.clone(), + manager: self.manager.clone(), } } - - Ok(()) } - /// The label of this window. - pub fn label(&self) -> &M::Label { - &self.window.label + impl Hash for Window { + /// Only use the [`Window`]'s label to represent its hash. + fn hash(&self, state: &mut H) { + self.window.label.hash(state) + } } - pub(crate) fn emit_internal( - &self, - event: E, - payload: Option, - ) -> crate::Result<()> { - let js_payload = match payload { - Some(payload_value) => serde_json::to_value(payload_value)?, - None => JsonValue::Null, - }; - - self.eval(&format!( - "window['{}']({{event: {}, payload: {}}}, '{}')", - self.manager.event_emit_function_name(), - event.to_javascript()?, - js_payload, - self.manager.generate_salt(), - ))?; - - Ok(()) + impl Eq for Window {} + impl PartialEq for Window { + /// Only use the [`Window`]'s label to compare equality. + fn eq(&self, other: &Self) -> bool { + self.window.label.eq(&other.window.label) + } } - /// Emits an event to the current window. - pub fn emit(&self, event: &M::Event, payload: Option) -> crate::Result<()> { - self.emit_internal(event.clone(), payload) + impl Manager for Window {} + impl ManagerPrivate for Window { + fn manager(&self) -> &M { + &self.manager + } + + fn runtime(&mut self) -> RuntimeOrDispatch<'_, M> { + RuntimeOrDispatch::Dispatch(self.dispatcher()) + } } - pub(crate) fn emit_others_internal( - &self, - event: String, - payload: Option, - ) -> crate::Result<()> { - self - .manager - .emit_filter_internal(event, payload, |w| w != self) - } + impl Window { + /// Create a new window that is attached to the manager. + pub(crate) fn new(manager: M, window: DetachedWindow) -> Self { + Self { manager, window } + } - /// Emits an event on all windows except this one. - pub fn emit_others( - &self, - event: M::Event, - payload: Option, - ) -> crate::Result<()> { - self.manager.emit_filter(event, payload, |w| w != self) - } + /// The current window's dispatcher. + pub(crate) fn dispatcher(&self) -> ::Dispatcher { + self.window.dispatcher.clone() + } - /// Listen to an event on this window. - pub fn listen(&self, event: M::Event, handler: F) -> EventHandler - where - F: Fn(Event) + Send + 'static, - { - let label = self.window.label.clone(); - self.manager.listen(event, Some(label), handler) - } + /// How to handle this window receiving an [`InvokeMessage`]. + pub(crate) fn on_message(self, command: String, payload: InvokePayload) -> crate::Result<()> { + let manager = self.manager.clone(); + if &command == "__initialized" { + let payload: PageLoadPayload = serde_json::from_value(payload.inner)?; + manager.run_on_page_load(self, payload); + } else { + let message = InvokeMessage::new(self, command.to_string(), payload); + if let Some(module) = &message.payload.tauri_module { + let module = module.to_string(); + crate::endpoints::handle(module, message, manager.config(), manager.package_info()); + } else if command.starts_with("plugin:") { + manager.extend_api(command, message); + } else { + manager.run_invoke_handler(message); + } + } - /// Listen to a an event on this window a single time. - pub fn once(&self, event: M::Event, handler: F) - where - F: Fn(Event) + Send + 'static, - { - let label = self.window.label.clone(); - self.manager.once(event, Some(label), handler) - } + Ok(()) + } - /// Triggers an event on this window. - pub(crate) fn trigger(&self, event: M::Event, data: Option) { - let label = self.window.label.clone(); - self.manager.trigger(event, Some(label), data) - } + /// The label of this window. + pub fn label(&self) -> &M::Label { + &self.window.label + } - /// Evaluates JavaScript on this window. - pub fn eval(&self, js: &str) -> crate::Result<()> { - self.window.dispatcher.eval_script(js) - } + pub(crate) fn emit_internal( + &self, + event: E, + payload: Option, + ) -> crate::Result<()> { + let js_payload = match payload { + Some(payload_value) => serde_json::to_value(payload_value)?, + None => JsonValue::Null, + }; - /// Determines if this window should be resizable. - pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> { - self.window.dispatcher.set_resizable(resizable) - } + self.eval(&format!( + "window['{}']({{event: {}, payload: {}}}, '{}')", + self.manager.event_emit_function_name(), + event.to_javascript()?, + js_payload, + self.manager.generate_salt(), + ))?; - /// Set this window's title. - pub fn set_title(&self, title: &str) -> crate::Result<()> { - self.window.dispatcher.set_title(title.to_string()) - } + Ok(()) + } - /// Maximizes this window. - pub fn maximize(&self) -> crate::Result<()> { - self.window.dispatcher.maximize() - } + /// Emits an event to the current window. + pub fn emit(&self, event: &M::Event, payload: Option) -> crate::Result<()> { + self.emit_internal(event.clone(), payload) + } - /// Un-maximizes this window. - pub fn unmaximize(&self) -> crate::Result<()> { - self.window.dispatcher.unmaximize() - } + pub(crate) fn emit_others_internal( + &self, + event: String, + payload: Option, + ) -> crate::Result<()> { + self + .manager + .emit_filter_internal(event, payload, |w| w != self) + } - /// Minimizes this window. - pub fn minimize(&self) -> crate::Result<()> { - self.window.dispatcher.minimize() - } + /// Emits an event on all windows except this one. + pub fn emit_others( + &self, + event: M::Event, + payload: Option, + ) -> crate::Result<()> { + self.manager.emit_filter(event, payload, |w| w != self) + } - /// Un-minimizes this window. - pub fn unminimize(&self) -> crate::Result<()> { - self.window.dispatcher.unminimize() - } + /// Listen to an event on this window. + pub fn listen(&self, event: M::Event, handler: F) -> EventHandler + where + F: Fn(Event) + Send + 'static, + { + let label = self.window.label.clone(); + self.manager.listen(event, Some(label), handler) + } - /// Show this window. - pub fn show(&self) -> crate::Result<()> { - self.window.dispatcher.show() - } + /// Listen to a an event on this window a single time. + pub fn once(&self, event: M::Event, handler: F) + where + F: Fn(Event) + Send + 'static, + { + let label = self.window.label.clone(); + self.manager.once(event, Some(label), handler) + } - /// Hide this window. - pub fn hide(&self) -> crate::Result<()> { - self.window.dispatcher.hide() - } + /// Triggers an event on this window. + pub(crate) fn trigger(&self, event: M::Event, data: Option) { + let label = self.window.label.clone(); + self.manager.trigger(event, Some(label), data) + } - /// Closes this window. - pub fn close(&self) -> crate::Result<()> { - self.window.dispatcher.close() - } + /// Evaluates JavaScript on this window. + pub fn eval(&self, js: &str) -> crate::Result<()> { + self.window.dispatcher.eval_script(js) + } - /// Determines if this window should be [decorated]. - /// - /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration - pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> { - self.window.dispatcher.set_decorations(decorations) - } + /// Determines if this window should be resizable. + pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> { + self.window.dispatcher.set_resizable(resizable) + } - /// Determines if this window should always be on top of other windows. - pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> { - self.window.dispatcher.set_always_on_top(always_on_top) - } + /// Set this window's title. + pub fn set_title(&self, title: &str) -> crate::Result<()> { + self.window.dispatcher.set_title(title.to_string()) + } - /// Sets this window's width. - pub fn set_width(&self, width: impl Into) -> crate::Result<()> { - self.window.dispatcher.set_width(width.into()) - } + /// Maximizes this window. + pub fn maximize(&self) -> crate::Result<()> { + self.window.dispatcher.maximize() + } - /// Sets this window's height. - pub fn set_height(&self, height: impl Into) -> crate::Result<()> { - self.window.dispatcher.set_height(height.into()) - } + /// Un-maximizes this window. + pub fn unmaximize(&self) -> crate::Result<()> { + self.window.dispatcher.unmaximize() + } - /// Resizes this window. - pub fn resize(&self, width: impl Into, height: impl Into) -> crate::Result<()> { - self.window.dispatcher.resize(width.into(), height.into()) - } + /// Minimizes this window. + pub fn minimize(&self) -> crate::Result<()> { + self.window.dispatcher.minimize() + } - /// Sets this window's minimum size. - pub fn set_min_size( - &self, - min_width: impl Into, - min_height: impl Into, - ) -> crate::Result<()> { - self - .window - .dispatcher - .set_min_size(min_width.into(), min_height.into()) - } + /// Un-minimizes this window. + pub fn unminimize(&self) -> crate::Result<()> { + self.window.dispatcher.unminimize() + } - /// Sets this window's maximum size. - pub fn set_max_size( - &self, - max_width: impl Into, - max_height: impl Into, - ) -> crate::Result<()> { - self - .window - .dispatcher - .set_max_size(max_width.into(), max_height.into()) - } + /// Show this window. + pub fn show(&self) -> crate::Result<()> { + self.window.dispatcher.show() + } - /// Sets this window's x position. - pub fn set_x(&self, x: impl Into) -> crate::Result<()> { - self.window.dispatcher.set_x(x.into()) - } + /// Hide this window. + pub fn hide(&self) -> crate::Result<()> { + self.window.dispatcher.hide() + } - /// Sets this window's y position. - pub fn set_y(&self, y: impl Into) -> crate::Result<()> { - self.window.dispatcher.set_y(y.into()) - } + /// Closes this window. + pub fn close(&self) -> crate::Result<()> { + self.window.dispatcher.close() + } - /// Sets this window's position. - pub fn set_position(&self, x: impl Into, y: impl Into) -> crate::Result<()> { - self.window.dispatcher.set_position(x.into(), y.into()) - } + /// Determines if this window should be [decorated]. + /// + /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration + pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> { + self.window.dispatcher.set_decorations(decorations) + } - /// Determines if this window should be fullscreen. - pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> { - self.window.dispatcher.set_fullscreen(fullscreen) - } + /// Determines if this window should always be on top of other windows. + pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> { + self.window.dispatcher.set_always_on_top(always_on_top) + } - /// Sets this window' icon. - pub fn set_icon(&self, icon: Icon) -> crate::Result<()> { - self.window.dispatcher.set_icon(icon.try_into()?) - } + /// Sets this window's width. + pub fn set_width(&self, width: impl Into) -> crate::Result<()> { + self.window.dispatcher.set_width(width.into()) + } - pub(crate) fn verify_salt(&self, salt: String) -> bool { - self.manager.verify_salt(salt) + /// Sets this window's height. + pub fn set_height(&self, height: impl Into) -> crate::Result<()> { + self.window.dispatcher.set_height(height.into()) + } + + /// Resizes this window. + pub fn resize(&self, width: impl Into, height: impl Into) -> crate::Result<()> { + self.window.dispatcher.resize(width.into(), height.into()) + } + + /// Sets this window's minimum size. + pub fn set_min_size( + &self, + min_width: impl Into, + min_height: impl Into, + ) -> crate::Result<()> { + self + .window + .dispatcher + .set_min_size(min_width.into(), min_height.into()) + } + + /// Sets this window's maximum size. + pub fn set_max_size( + &self, + max_width: impl Into, + max_height: impl Into, + ) -> crate::Result<()> { + self + .window + .dispatcher + .set_max_size(max_width.into(), max_height.into()) + } + + /// Sets this window's x position. + pub fn set_x(&self, x: impl Into) -> crate::Result<()> { + self.window.dispatcher.set_x(x.into()) + } + + /// Sets this window's y position. + pub fn set_y(&self, y: impl Into) -> crate::Result<()> { + self.window.dispatcher.set_y(y.into()) + } + + /// Sets this window's position. + pub fn set_position(&self, x: impl Into, y: impl Into) -> crate::Result<()> { + self.window.dispatcher.set_position(x.into(), y.into()) + } + + /// Determines if this window should be fullscreen. + pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> { + self.window.dispatcher.set_fullscreen(fullscreen) + } + + /// Sets this window' icon. + pub fn set_icon(&self, icon: Icon) -> crate::Result<()> { + self.window.dispatcher.set_icon(icon.try_into()?) + } + + pub(crate) fn verify_salt(&self, salt: String) -> bool { + self.manager.verify_salt(salt) + } } } diff --git a/core/tauri/src/runtime/updater.rs b/core/tauri/src/updater.rs similarity index 98% rename from core/tauri/src/runtime/updater.rs rename to core/tauri/src/updater.rs index 2df437f1d..bd1314088 100644 --- a/core/tauri/src/runtime/updater.rs +++ b/core/tauri/src/updater.rs @@ -8,14 +8,14 @@ use crate::{ config::UpdaterConfig, dialog::{ask, AskResponse}, }, - runtime::{window::Window, Params}, + Params, Window, }; // Check for new updates pub const EVENT_CHECK_UPDATE: &str = "tauri://update"; // New update available pub const EVENT_UPDATE_AVAILABLE: &str = "tauri://update-available"; -// Used to intialize an update *should run check-update first (once you received the update available event)* +// Used to initialize an update *should run check-update first (once you received the update available event)* pub const EVENT_INSTALL_UPDATE: &str = "tauri://update-install"; // Send updater status or error even if dialog is enabled, you should // always listen for this event. It'll send you the install progress