diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e37d457ad..6af3729a2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -80,6 +80,14 @@ The code for the bundler is located in `[Tauri repo root]/tooling/bundler`, and The code for Tauri Core is located in `[Tauri repo root]/core/tauri`, and the Rust API, Macros, and Utils are in `[Tauri repo root]/core/tauri-(api/macros/utils)`. The easiest way to test your changes is to use the `[Tauri repo root]/examples/helloworld` app. It automatically rebuilds and uses your local copy of the Tauri core packages. Just run `yarn tauri build` or `yarn tauri dev` in the helloworld app directory after making changes to test them out. To use your local changes in another project, edit its `src-tauri/Cargo.toml` file so that the `tauri` key looks like `tauri = { path = "PATH", features = [ "api-all", "cli" ] }`, where `PATH` is the relative path to `[Tauri repo root]/core/tauri`. Then, your local copy of the Tauri core packages will be rebuilt and used whenever you build that project. +#### Building the documentation locally + +You can build the Rust documentation locally running the following script: + +```bash +$ RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --open +``` + ### Developing the JS API The JS API provides bindings between the developer's JS in the Webview and the builtin Tauri APIs, written in Rust. Its code is located in `[Tauri repo root]/tooling/api`. After making changes to the code, run `yarn build` to build it. To test your changes, we recommend using the API example app, located in `[Tauri repo root]/examples/api`. It will automatically use your local copy of the JS API and provides a helpful UI to test the various commands. diff --git a/core/tauri-build/src/codegen/context.rs b/core/tauri-build/src/codegen/context.rs index 7eb2bc3f0..54e86f4e6 100644 --- a/core/tauri-build/src/codegen/context.rs +++ b/core/tauri-build/src/codegen/context.rs @@ -13,10 +13,6 @@ use tauri_codegen::{context_codegen, ContextData}; // TODO docs /// A builder for generating a Tauri application context during compile time. -/// -/// Meant to be used with [`tauri::include_codegen_context!`] inside your application code. -/// -/// [`tauri::include_codegen_context!`]: https://docs.rs/tauri/0.12/tauri/macro.include_codegen_context.html #[cfg_attr(doc_cfg, doc(cfg(feature = "codegen")))] #[derive(Debug)] pub struct CodegenContext { diff --git a/core/tauri-runtime-wry/Cargo.toml b/core/tauri-runtime-wry/Cargo.toml index 65eb5de46..3e673af59 100644 --- a/core/tauri-runtime-wry/Cargo.toml +++ b/core/tauri-runtime-wry/Cargo.toml @@ -10,8 +10,13 @@ description = "Wry bindings to the Tauri runtime" edition = "2018" [dependencies] -wry = "0.9.1" +wry = { version = "0.9.2", default-features = false, features = ["file-drop", "protocol", "win32"] } tauri-runtime = { version = "0.0.0", path = "../tauri-runtime" } tauri-utils = { version = "1.0.0-beta-rc.1", path = "../tauri-utils" } image = "0.23" uuid = { version = "0.8.2", features = [ "v4" ] } + +[features] +dox = [ "wry/dox" ] +menu = [ "wry/menu" ] +system-tray = [ "wry/tray" ] diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index e0f4b1171..8555a41eb 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -5,18 +5,24 @@ //! The [`wry`] Tauri [`Runtime`]. use tauri_runtime::{ - menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem}, monitor::Monitor, webview::{ FileDropEvent, FileDropHandler, RpcRequest, WebviewRpcHandler, WindowBuilder, WindowBuilderBase, }, window::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}, - DetachedWindow, MenuEvent, PendingWindow, WindowEvent, + DetachedWindow, PendingWindow, WindowEvent, }, - Dispatch, Error, Icon, Params, Result, Runtime, SystemTrayEvent, + Dispatch, Error, Icon, Params, Result, Runtime, }; +#[cfg(feature = "menu")] +use tauri_runtime::window::MenuEvent; +#[cfg(feature = "system-tray")] +use tauri_runtime::SystemTrayEvent; +#[cfg(feature = "system-tray")] +use wry::application::platform::system_tray::SystemTrayBuilder; + use image::{GenericImageView, Pixel}; use tauri_utils::config::WindowConfig; use uuid::Uuid; @@ -29,12 +35,7 @@ use wry::{ }, event::{Event, WindowEvent as WryWindowEvent}, event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget}, - menu::{ - CustomMenu as WryCustomMenu, Menu as WryMenu, MenuId as WryMenuId, MenuItem as WryMenuItem, - MenuType, - }, monitor::MonitorHandle, - platform::system_tray::SystemTrayBuilder, window::{Fullscreen, Icon as WindowIcon, Window, WindowBuilder as WryWindowBuilder, WindowId}, }, webview::{ @@ -52,15 +53,16 @@ use std::{ }, }; +#[cfg(any(feature = "menu", feature = "system-tray"))] +mod menu; +#[cfg(any(feature = "menu", feature = "system-tray"))] +use menu::*; + type CreateWebviewHandler = Box) -> Result + Send>; type MainThreadTask = Box; type WindowEventHandler = Box; type WindowEventListeners = Arc>>; -type MenuEventHandler = Box; -type MenuEventListeners = Arc>>; -type SystemTrayEventHandler = Box; -type SystemTrayEventListeners = HashMap; #[repr(C)] #[derive(Debug)] @@ -219,73 +221,6 @@ impl From for PositionWrapper { } } -pub struct CustomMenuWrapper(WryCustomMenu); - -impl From> for CustomMenuWrapper { - fn from(item: CustomMenuItem) -> Self { - Self(WryCustomMenu { - id: WryMenuId(item.id_value()), - name: item.name, - keyboard_accelerators: None, - }) - } -} - -struct MenuItemWrapper(WryMenuItem); - -impl From> for MenuItemWrapper { - fn from(item: MenuItem) -> Self { - match item { - MenuItem::Custom(custom) => Self(WryMenuItem::Custom(CustomMenuWrapper::from(custom).0)), - MenuItem::About(v) => Self(WryMenuItem::About(v)), - MenuItem::Hide => Self(WryMenuItem::Hide), - MenuItem::Services => Self(WryMenuItem::Services), - MenuItem::HideOthers => Self(WryMenuItem::HideOthers), - MenuItem::ShowAll => Self(WryMenuItem::ShowAll), - MenuItem::CloseWindow => Self(WryMenuItem::CloseWindow), - MenuItem::Quit => Self(WryMenuItem::Quit), - MenuItem::Copy => Self(WryMenuItem::Copy), - MenuItem::Cut => Self(WryMenuItem::Cut), - MenuItem::Undo => Self(WryMenuItem::Undo), - MenuItem::Redo => Self(WryMenuItem::Redo), - MenuItem::SelectAll => Self(WryMenuItem::SelectAll), - MenuItem::Paste => Self(WryMenuItem::Paste), - MenuItem::EnterFullScreen => Self(WryMenuItem::EnterFullScreen), - MenuItem::Minimize => Self(WryMenuItem::Minimize), - MenuItem::Zoom => Self(WryMenuItem::Zoom), - MenuItem::Separator => Self(WryMenuItem::Separator), - _ => unimplemented!(), - } - } -} - -pub struct MenuWrapper(WryMenu); - -impl From> for MenuWrapper { - fn from(menu: Menu) -> Self { - Self(WryMenu { - title: menu.title, - items: menu - .items - .into_iter() - .map(|m| MenuItemWrapper::from(m).0) - .collect(), - }) - } -} - -impl From> for MenuItemWrapper { - fn from(item: SystemTrayMenuItem) -> Self { - match item { - SystemTrayMenuItem::Custom(custom) => { - Self(WryMenuItem::Custom(CustomMenuWrapper::from(custom).0)) - } - SystemTrayMenuItem::Separator => Self(WryMenuItem::Separator), - _ => unimplemented!(), - } - } -} - #[derive(Debug, Clone, Default)] pub struct WindowBuilderWrapper(WryWindowBuilder); @@ -320,6 +255,7 @@ impl WindowBuilder for WindowBuilderWrapper { window } + #[cfg(feature = "menu")] fn menu(self, menu: Vec>) -> Self { Self( self.0.with_menu( @@ -401,6 +337,7 @@ impl WindowBuilder for WindowBuilderWrapper { self.0.window.window_icon.is_some() } + #[cfg(feature = "menu")] fn has_menu(&self) -> bool { self.0.window.window_menu.is_some() } @@ -481,6 +418,7 @@ struct DispatcherContext { proxy: EventLoopProxy, task_tx: Sender, window_event_listeners: WindowEventListeners, + #[cfg(feature = "menu")] menu_event_listeners: MenuEventListeners, } @@ -526,6 +464,7 @@ impl Dispatch for WryDispatcher { id } + #[cfg(feature = "menu")] fn on_menu_event(&self, f: F) -> Uuid { let id = Uuid::new_v4(); self @@ -817,7 +756,9 @@ pub struct Wry { webviews: Mutex>, task_tx: Sender, window_event_listeners: WindowEventListeners, + #[cfg(feature = "menu")] menu_event_listeners: MenuEventListeners, + #[cfg(feature = "system-tray")] system_tray_event_listeners: SystemTrayEventListeners, task_rx: Receiver, } @@ -834,7 +775,9 @@ impl Runtime for Wry { task_tx, task_rx, window_event_listeners: Default::default(), + #[cfg(feature = "menu")] menu_event_listeners: Default::default(), + #[cfg(feature = "system-tray")] system_tray_event_listeners: HashMap::default(), }) } @@ -851,6 +794,7 @@ impl Runtime for Wry { proxy: proxy.clone(), task_tx: self.task_tx.clone(), window_event_listeners: self.window_event_listeners.clone(), + #[cfg(feature = "menu")] menu_event_listeners: self.menu_event_listeners.clone(), }, pending, @@ -862,6 +806,7 @@ impl Runtime for Wry { proxy, task_tx: self.task_tx.clone(), window_event_listeners: self.window_event_listeners.clone(), + #[cfg(feature = "menu")] menu_event_listeners: self.menu_event_listeners.clone(), }, }; @@ -875,7 +820,7 @@ impl Runtime for Wry { Ok(DetachedWindow { label, dispatcher }) } - #[cfg(target_os = "linux")] + #[cfg(all(feature = "system-tray", target_os = "linux"))] fn system_tray( &self, icon: std::path::PathBuf, @@ -893,7 +838,7 @@ impl Runtime for Wry { Ok(()) } - #[cfg(not(target_os = "linux"))] + #[cfg(all(feature = "system-tray", not(target_os = "linux")))] fn system_tray( &self, icon: Vec, @@ -911,6 +856,7 @@ impl Runtime for Wry { Ok(()) } + #[cfg(feature = "system-tray")] fn on_system_tray_event(&mut self, f: F) -> Uuid { let id = Uuid::new_v4(); self.system_tray_event_listeners.insert(id, Box::new(f)); @@ -924,8 +870,11 @@ impl Runtime for Wry { }; let task_rx = self.task_rx; let window_event_listeners = self.window_event_listeners.clone(); + #[cfg(feature = "menu")] let menu_event_listeners = self.menu_event_listeners.clone(); + #[cfg(feature = "system-tray")] let system_tray_event_listeners = self.system_tray_event_listeners; + self.event_loop.run(move |event, event_loop, control_flow| { *control_flow = ControlFlow::Wait; @@ -940,6 +889,7 @@ impl Runtime for Wry { } match event { + #[cfg(feature = "menu")] Event::MenuEvent { menu_id, origin: MenuType::Menubar, @@ -951,6 +901,7 @@ impl Runtime for Wry { handler(&event); } } + #[cfg(feature = "system-tray")] Event::MenuEvent { menu_id, origin: MenuType::SystemTray, diff --git a/core/tauri-runtime-wry/src/menu.rs b/core/tauri-runtime-wry/src/menu.rs new file mode 100644 index 000000000..42f5f97b3 --- /dev/null +++ b/core/tauri-runtime-wry/src/menu.rs @@ -0,0 +1,92 @@ +// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +pub use tauri_runtime::{ + menu::{CustomMenuItem, Menu, MenuItem, SystemTrayMenuItem}, + window::MenuEvent, + MenuId, SystemTrayEvent, +}; +pub use wry::application::menu::{ + CustomMenu as WryCustomMenu, Menu as WryMenu, MenuId as WryMenuId, MenuItem as WryMenuItem, + MenuType, +}; + +use uuid::Uuid; + +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; + +pub type MenuEventHandler = Box; +pub type MenuEventListeners = Arc>>; +pub type SystemTrayEventHandler = Box; +pub type SystemTrayEventListeners = HashMap; + +pub struct CustomMenuWrapper(pub WryCustomMenu); + +impl From> for CustomMenuWrapper { + fn from(item: CustomMenuItem) -> Self { + Self(WryCustomMenu { + id: WryMenuId(item.id_value()), + name: item.name, + keyboard_accelerators: None, + }) + } +} + +pub struct MenuItemWrapper(pub WryMenuItem); + +impl From> for MenuItemWrapper { + fn from(item: MenuItem) -> Self { + match item { + MenuItem::Custom(custom) => Self(WryMenuItem::Custom(CustomMenuWrapper::from(custom).0)), + MenuItem::About(v) => Self(WryMenuItem::About(v)), + MenuItem::Hide => Self(WryMenuItem::Hide), + MenuItem::Services => Self(WryMenuItem::Services), + MenuItem::HideOthers => Self(WryMenuItem::HideOthers), + MenuItem::ShowAll => Self(WryMenuItem::ShowAll), + MenuItem::CloseWindow => Self(WryMenuItem::CloseWindow), + MenuItem::Quit => Self(WryMenuItem::Quit), + MenuItem::Copy => Self(WryMenuItem::Copy), + MenuItem::Cut => Self(WryMenuItem::Cut), + MenuItem::Undo => Self(WryMenuItem::Undo), + MenuItem::Redo => Self(WryMenuItem::Redo), + MenuItem::SelectAll => Self(WryMenuItem::SelectAll), + MenuItem::Paste => Self(WryMenuItem::Paste), + MenuItem::EnterFullScreen => Self(WryMenuItem::EnterFullScreen), + MenuItem::Minimize => Self(WryMenuItem::Minimize), + MenuItem::Zoom => Self(WryMenuItem::Zoom), + MenuItem::Separator => Self(WryMenuItem::Separator), + _ => unimplemented!(), + } + } +} + +pub struct MenuWrapper(pub WryMenu); + +impl From> for MenuWrapper { + fn from(menu: Menu) -> Self { + Self(WryMenu { + title: menu.title, + items: menu + .items + .into_iter() + .map(|m| MenuItemWrapper::from(m).0) + .collect(), + }) + } +} + +impl From> for MenuItemWrapper { + fn from(item: SystemTrayMenuItem) -> Self { + match item { + SystemTrayMenuItem::Custom(custom) => { + Self(WryMenuItem::Custom(CustomMenuWrapper::from(custom).0)) + } + SystemTrayMenuItem::Separator => Self(WryMenuItem::Separator), + _ => unimplemented!(), + } + } +} diff --git a/core/tauri-runtime/Cargo.toml b/core/tauri-runtime/Cargo.toml index 0fa455ac3..5428f6263 100644 --- a/core/tauri-runtime/Cargo.toml +++ b/core/tauri-runtime/Cargo.toml @@ -9,9 +9,23 @@ repository = "https://github.com/tauri-apps/tauri" description = "Runtime for Tauri applications" edition = "2018" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ "--cfg", "doc_cfg" ] +default-target = "x86_64-unknown-linux-gnu" +targets = [ + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin" +] + [dependencies] serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" thiserror = "1.0" tauri-utils = { version = "1.0.0-beta-rc.1", path = "../tauri-utils" } uuid = { version = "0.8.2", features = [ "v4" ] } + +[features] +menu = [] +system-tray = [] diff --git a/core/tauri-runtime/src/lib.rs b/core/tauri-runtime/src/lib.rs index 8ad8304d7..db9b3b767 100644 --- a/core/tauri-runtime/src/lib.rs +++ b/core/tauri-runtime/src/lib.rs @@ -4,12 +4,17 @@ //! Internal runtime between Tauri and the underlying webview runtime. -use std::path::PathBuf; +#![cfg_attr(doc_cfg, feature(doc_cfg))] +use std::{fmt::Debug, hash::Hash, path::PathBuf}; + +use serde::Serialize; use tauri_utils::assets::Assets; use uuid::Uuid; /// Create window and system tray menus. +#[cfg(any(feature = "menu", feature = "system-tray"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "menu", feature = "system-tray"))))] pub mod menu; /// Types useful for interacting with a user's monitors. pub mod monitor; @@ -17,15 +22,19 @@ pub mod tag; pub mod webview; pub mod window; -use menu::{MenuId, SystemTrayMenuItem}; use monitor::Monitor; use tag::Tag; use webview::WindowBuilder; use window::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, - DetachedWindow, MenuEvent, PendingWindow, WindowEvent, + DetachedWindow, PendingWindow, WindowEvent, }; +/// A type that can be derived into a menu id. +pub trait MenuId: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {} + +impl MenuId for T where T: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {} + #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub enum Error { @@ -41,7 +50,9 @@ pub enum Error { /// Failed to serialize/deserialize. #[error("JSON error: {0}")] Json(#[from] serde_json::Error), - /// Encountered an error creating the app system tray, + /// Encountered an error creating the app system tray. + #[cfg(feature = "menu")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] #[error("error encountered during tray setup: {0}")] SystemTray(Box), /// Failed to load window icon. @@ -108,22 +119,29 @@ pub trait Runtime: Sized + 'static { ) -> crate::Result>; /// Adds the icon to the system tray with the specified menu items. - #[cfg(target_os = "linux")] + #[cfg(all(feature = "system-tray", target_os = "linux"))] + #[cfg_attr(doc_cfg, doc(cfg(all(feature = "system-tray", target_os = "linux"))))] fn system_tray( &self, icon: std::path::PathBuf, - menu: Vec>, + menu: Vec>, ) -> crate::Result<()>; /// Adds the icon to the system tray with the specified menu items. - #[cfg(not(target_os = "linux"))] + #[cfg(all(feature = "system-tray", not(target_os = "linux")))] + #[cfg_attr( + doc_cfg, + doc(cfg(all(feature = "system-tray", not(target_os = "linux")))) + )] fn system_tray( &self, icon: Vec, - menu: Vec>, + menu: Vec>, ) -> crate::Result<()>; /// Registers a system tray event handler. + #[cfg(feature = "system-tray")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] fn on_system_tray_event(&mut self, f: F) -> Uuid; /// Run the webview runtime. @@ -145,7 +163,9 @@ pub trait Dispatch: Clone + Send + Sized + 'static { fn on_window_event(&self, f: F) -> Uuid; /// Registers a window event handler. - fn on_menu_event(&self, f: F) -> Uuid; + #[cfg(feature = "menu")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] + fn on_menu_event(&self, f: F) -> Uuid; // GETTERS diff --git a/core/tauri-runtime/src/menu.rs b/core/tauri-runtime/src/menu.rs index 249cb5bfb..bca164af6 100644 --- a/core/tauri-runtime/src/menu.rs +++ b/core/tauri-runtime/src/menu.rs @@ -2,18 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::{ - collections::hash_map::DefaultHasher, - fmt::Debug, - hash::{Hash, Hasher}, -}; +use std::{collections::hash_map::DefaultHasher, hash::Hasher}; -use serde::Serialize; - -/// A type that can be derived into a menu id. -pub trait MenuId: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {} - -impl MenuId for T where T: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {} +use super::MenuId; /// A window menu. #[derive(Debug, Clone)] diff --git a/core/tauri-runtime/src/webview.rs b/core/tauri-runtime/src/webview.rs index ba85507b7..ff8976356 100644 --- a/core/tauri-runtime/src/webview.rs +++ b/core/tauri-runtime/src/webview.rs @@ -2,13 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -//! Items specific to the [`Runtime`](crate::runtime::Runtime)'s webview. +//! Items specific to the [`Runtime`](crate::Runtime)'s webview. -use crate::{ - menu::{Menu, MenuId}, - window::DetachedWindow, - Icon, -}; +use crate::{window::DetachedWindow, Icon}; + +#[cfg(feature = "menu")] +use crate::{menu::Menu, MenuId}; use serde::Deserialize; use serde_json::Value as JsonValue; @@ -80,14 +79,14 @@ impl WebviewAttributes { } } -/// Do **NOT** implement this trait except for use in a custom [`Runtime`](crate::runtime::Runtime). +/// Do **NOT** implement this trait except for use in a custom [`Runtime`](crate::Runtime). /// /// This trait is separate from [`WindowBuilder`] to prevent "accidental" implementation. pub trait WindowBuilderBase: 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) +/// This trait is only meant to be implemented by a custom [`Runtime`](crate::Runtime) /// and not by applications. pub trait WindowBuilder: WindowBuilderBase { /// Initializes a new window attributes builder. @@ -97,6 +96,8 @@ pub trait WindowBuilder: WindowBuilderBase { fn with_config(config: WindowConfig) -> Self; /// Sets the menu for the window. + #[cfg(feature = "menu")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] fn menu(self, menu: Vec>) -> Self; /// The initial position of the window's. @@ -143,6 +144,8 @@ pub trait WindowBuilder: WindowBuilderBase { fn has_icon(&self) -> bool; /// Whether the menu was set or not. + #[cfg(feature = "menu")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] fn has_menu(&self) -> bool; } diff --git a/core/tauri-runtime/src/window.rs b/core/tauri-runtime/src/window.rs index 9f8b91205..229fba4c5 100644 --- a/core/tauri-runtime/src/window.rs +++ b/core/tauri-runtime/src/window.rs @@ -117,7 +117,7 @@ pub struct DetachedWindow { /// Name of the window pub label: M::Label, - /// The [`Dispatch`](crate::runtime::Dispatch) associated with the window. + /// The [`Dispatch`](crate::Dispatch) associated with the window. pub dispatcher: ::Dispatcher, } diff --git a/core/tauri/Cargo.toml b/core/tauri/Cargo.toml index 3c715feca..bb2f74034 100644 --- a/core/tauri/Cargo.toml +++ b/core/tauri/Cargo.toml @@ -11,7 +11,14 @@ edition = "2018" exclude = [ "/test" ] [package.metadata.docs.rs] -features = [ "api-all" ] +all-features = true +rustdoc-args = [ "--cfg", "doc_cfg" ] +default-target = "x86_64-unknown-linux-gnu" +targets = [ + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin" +] [dependencies] serde_json = { version = "1.0", features = [ "raw_value" ] } @@ -66,12 +73,16 @@ tokio-test = "0.4.1" mockito = "0.30" [features] -default = ["wry"] -wry = ["tauri-runtime-wry"] +default = [ "wry" ] +dox = [ "tauri-runtime-wry/dox" ] +wry = [ "tauri-runtime-wry" ] cli = [ "clap" ] custom-protocol = [ "tauri-macros/custom-protocol" ] api-all = [ "notification-all", "global-shortcut-all", "updater" ] updater = [ "reqwest/default-tls" ] +menu = [ "tauri-runtime/menu", "tauri-runtime-wry/menu" ] +system-tray = [ "tauri-runtime/system-tray", "tauri-runtime-wry/system-tray" ] +# allowlist fs-all = [ ] fs-read-text-file = [ ] fs-read-binary-file = [ ] diff --git a/core/tauri/src/api/rpc.rs b/core/tauri/src/api/rpc.rs index 9aa6fc8d2..15d6362cc 100644 --- a/core/tauri/src/api/rpc.rs +++ b/core/tauri/src/api/rpc.rs @@ -59,7 +59,7 @@ fn escape_json_parse(json: &RawValue) -> String { /// This will serialize primitive JSON types (e.g. booleans, strings, numbers, etc.) as JavaScript literals, /// but will serialize arrays and objects whose serialized JSON string is smaller than 1 GB and larger /// than 10 KiB with `JSON.parse('...')`. -/// https://github.com/GoogleChromeLabs/json-parse-benchmark +/// See [json-parse-benchmark](https://github.com/GoogleChromeLabs/json-parse-benchmark). /// /// # Examples /// ``` diff --git a/core/tauri/src/app.rs b/core/tauri/src/app.rs index 3b36de7f7..bfba202d7 100644 --- a/core/tauri/src/app.rs +++ b/core/tauri/src/app.rs @@ -9,11 +9,10 @@ use crate::{ manager::{Args, WindowManager}, plugin::{Plugin, PluginStore}, runtime::{ - menu::{Menu, MenuId, SystemTrayMenuItem}, tag::Tag, webview::{CustomProtocol, WebviewAttributes, WindowBuilder}, window::{PendingWindow, WindowEvent}, - Dispatch, Params, Runtime, + Dispatch, MenuId, Params, Runtime, }, sealed::{ManagerBase, RuntimeOrDispatch}, Context, Invoke, Manager, StateManager, Window, @@ -21,19 +20,29 @@ use crate::{ use std::{collections::HashMap, sync::Arc}; +#[cfg(feature = "menu")] +use crate::runtime::menu::Menu; +#[cfg(feature = "system-tray")] +use crate::runtime::menu::SystemTrayMenuItem; + #[cfg(feature = "updater")] use crate::updater; +#[cfg(feature = "menu")] pub(crate) type GlobalMenuEventListener

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

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

= Box, SystemTrayEvent<

::SystemTrayMenuId>) + Send + Sync>; /// System tray event. +#[cfg(feature = "system-tray")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] pub struct SystemTrayEvent { menu_item_id: I, } +#[cfg(feature = "system-tray")] impl SystemTrayEvent { /// The menu item id. pub fn menu_item_id(&self) -> &I { @@ -42,11 +51,14 @@ impl SystemTrayEvent { } /// A menu event that was triggered on a window. +#[cfg(feature = "menu")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] pub struct WindowMenuEvent { pub(crate) menu_item_id: P::MenuId, pub(crate) window: Window

, } +#[cfg(feature = "menu")] impl WindowMenuEvent

{ /// The menu item id. pub fn menu_item_id(&self) -> &P::MenuId { @@ -220,18 +232,22 @@ where state: StateManager, /// The menu set to all windows. + #[cfg(feature = "menu")] menu: Vec>, /// Menu event handlers that listens to all windows. + #[cfg(feature = "menu")] menu_event_listeners: Vec>>, /// Window event handlers that listens to all windows. window_event_listeners: Vec>>, /// The app system tray menu items. + #[cfg(feature = "system-tray")] system_tray: Vec>, /// System tray event handlers. + #[cfg(feature = "system-tray")] system_tray_event_listeners: Vec>>, } @@ -254,10 +270,14 @@ where plugins: PluginStore::default(), uri_scheme_protocols: Default::default(), state: StateManager::new(), + #[cfg(feature = "menu")] menu: Vec::new(), + #[cfg(feature = "menu")] menu_event_listeners: Vec::new(), window_event_listeners: Vec::new(), + #[cfg(feature = "system-tray")] system_tray: Vec::new(), + #[cfg(feature = "system-tray")] system_tray_event_listeners: Vec::new(), } } @@ -373,18 +393,24 @@ 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, items: Vec>) -> Self { self.system_tray = items; self } /// 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: Vec>) -> Self { self.menu = menu; self } /// Registers a menu event handler for all windows. + #[cfg(feature = "menu")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] pub fn on_menu_event< F: Fn(WindowMenuEvent>) + Send + Sync + 'static, >( @@ -407,6 +433,8 @@ where } /// Registers a system tray event handler. + #[cfg(feature = "system-tray")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] pub fn on_system_tray_event< F: Fn(&AppHandle>, SystemTrayEvent) + Send + Sync + 'static, >( @@ -445,6 +473,7 @@ where /// Runs the configured Tauri application. pub fn run(mut self, context: Context) -> crate::Result<()> { + #[cfg(feature = "system-tray")] let system_tray_icon = context.system_tray_icon.clone(); let manager = WindowManager::with_handlers( context, @@ -453,9 +482,9 @@ where self.on_page_load, self.uri_scheme_protocols, self.state, - self.menu, - self.menu_event_listeners, self.window_event_listeners, + #[cfg(feature = "menu")] + (self.menu, self.menu_event_listeners), ); // set up all the windows defined in the config @@ -504,6 +533,7 @@ where (self.setup)(&mut app).map_err(|e| crate::Error::Setup(e))?; + #[cfg(feature = "system-tray")] if !self.system_tray.is_empty() { let ids = get_menu_ids(&self.system_tray); app @@ -534,6 +564,7 @@ where } } +#[cfg(feature = "system-tray")] fn get_menu_ids(items: &[SystemTrayMenuItem]) -> HashMap { let mut map = HashMap::new(); for item in items { diff --git a/core/tauri/src/command.rs b/core/tauri/src/command.rs index 594c33ace..88cab9a86 100644 --- a/core/tauri/src/command.rs +++ b/core/tauri/src/command.rs @@ -32,8 +32,8 @@ pub struct CommandItem<'a, P: Params> { /// # Provided Implementations /// /// Tauri implements [`CommandArg`] automatically for a number of types. -/// * [`tauri::Window`] -/// * [`tauri::State`] +/// * [`crate::Window`] +/// * [`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 { diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index a66eb5ef0..01f872af1 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -9,12 +9,12 @@ //! The user interface in Tauri apps currently leverages Cocoa/WebKit on macOS, gtk-webkit2 on Linux and MSHTML (IE10/11) or Webkit via Edge on Windows. //! Tauri uses (and contributes to) the MIT licensed project that you can find at [webview](https://github.com/webview/webview). #![warn(missing_docs, rust_2018_idioms)] +#![cfg_attr(doc_cfg, feature(doc_cfg))] /// The Tauri error enum. pub use error::Error; pub use tauri_macros::{command, generate_handler}; -/// Core API. pub mod api; pub(crate) mod app; /// Async runtime. @@ -53,29 +53,41 @@ use serde::Serialize; use std::{borrow::Borrow, collections::HashMap, path::PathBuf, sync::Arc}; // Export types likely to be used by the application. +#[cfg(any(feature = "menu", feature = "system-tray"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "menu", feature = "system-tray"))))] +pub use runtime::menu::CustomMenuItem; pub use { self::api::assets::Assets, self::api::{ config::{Config, WindowUrl}, PackageInfo, }, - self::app::{App, Builder, GlobalWindowEvent, SystemTrayEvent, WindowMenuEvent}, + self::app::{App, Builder, GlobalWindowEvent}, self::hooks::{ Invoke, InvokeError, InvokeHandler, InvokeMessage, InvokeResolver, InvokeResponse, OnPageLoad, PageLoadPayload, SetupHook, }, self::runtime::{ - menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem}, tag::{Tag, TagRef}, webview::{WebviewAttributes, WindowBuilder}, window::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size}, WindowEvent, }, - Params, + MenuId, Params, }, self::state::{State, StateManager}, - self::window::{MenuEvent, Monitor, Window}, + self::window::{Monitor, Window}, +}; +#[cfg(feature = "system-tray")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] +pub use {self::app::SystemTrayEvent, self::runtime::menu::SystemTrayMenuItem}; +#[cfg(feature = "menu")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] +pub use { + self::app::WindowMenuEvent, + self::runtime::menu::{Menu, MenuItem}, + self::window::MenuEvent, }; /// Reads the config file at compile time and generates a [`Context`] based on its content. @@ -217,7 +229,7 @@ pub trait Manager: sealed::ManagerBase

{ } /// Add `state` to the state managed by the application. - /// See [`tauri::Builder#manage`] for instructions. + /// See [`crate::Builder#manage`] for instructions. fn manage(&self, state: T) where T: Send + Sync + 'static, diff --git a/core/tauri/src/manager.rs b/core/tauri/src/manager.rs index 30f4db8bb..cbefede8d 100644 --- a/core/tauri/src/manager.rs +++ b/core/tauri/src/manager.rs @@ -9,12 +9,11 @@ use crate::{ path::{resolve_path, BaseDirectory}, PackageInfo, }, - app::{GlobalMenuEventListener, GlobalWindowEvent, GlobalWindowEventListener, WindowMenuEvent}, + app::{GlobalWindowEvent, GlobalWindowEventListener}, event::{Event, EventHandler, Listeners}, hooks::{InvokeHandler, OnPageLoad, PageLoadPayload}, plugin::PluginStore, runtime::{ - menu::{Menu, MenuId, MenuItem}, private::ParamsBase, tag::{tags_to_javascript_array, Tag, TagRef, ToJsString}, webview::{ @@ -22,10 +21,20 @@ use crate::{ WindowBuilder, }, window::{dpi::PhysicalSize, DetachedWindow, PendingWindow, WindowEvent}, - Icon, Params, Runtime, + Icon, MenuId, Params, Runtime, }, - App, Context, Invoke, MenuEvent, StateManager, Window, + App, Context, Invoke, StateManager, Window, }; + +#[cfg(feature = "menu")] +use crate::app::{GlobalMenuEventListener, WindowMenuEvent}; + +#[cfg(feature = "menu")] +use crate::{ + runtime::menu::{Menu, MenuItem}, + MenuEvent, +}; + use serde::Serialize; use serde_json::Value as JsonValue; use std::borrow::Borrow; @@ -45,6 +54,7 @@ const WINDOW_DESTROYED_EVENT: &str = "tauri://destroyed"; const WINDOW_FOCUS_EVENT: &str = "tauri://focus"; const WINDOW_BLUR_EVENT: &str = "tauri://blur"; 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`] @@ -83,12 +93,16 @@ pub struct InnerWindowManager { /// The webview protocols protocols available to all windows. uri_scheme_protocols: HashMap>, /// The menu set to all windows. + #[cfg(feature = "menu")] menu: Vec>, + /// Maps runtime id to a strongly typed menu id. + #[cfg(feature = "menu")] + menu_ids: HashMap, /// Menu event listeners to all windows. + #[cfg(feature = "menu")] menu_event_listeners: Arc>>, /// Window event listeners to all windows. window_event_listeners: Arc>>, - menu_ids: HashMap, } /// A [Zero Sized Type] marker representing a full [`Params`]. @@ -148,6 +162,7 @@ impl Clone for WindowManager

{ } } +#[cfg(feature = "menu")] fn get_menu_ids(menu: &[Menu]) -> HashMap { let mut map = HashMap::new(); for m in menu { @@ -169,11 +184,12 @@ impl WindowManager

{ on_page_load: Box>, uri_scheme_protocols: HashMap>, state: StateManager, - menu: Vec>, - menu_event_listeners: Vec>, window_event_listeners: Vec>, + #[cfg(feature = "menu")] (menu, menu_event_listeners): ( + Vec>, + Vec>, + ), ) -> Self { - let menu_ids = get_menu_ids(&menu); Self { inner: Arc::new(InnerWindowManager { windows: Mutex::default(), @@ -188,10 +204,13 @@ impl WindowManager

{ salts: Mutex::default(), package_info: context.package_info, uri_scheme_protocols, + #[cfg(feature = "menu")] + menu_ids: get_menu_ids(&menu), + #[cfg(feature = "menu")] menu, + #[cfg(feature = "menu")] menu_event_listeners: Arc::new(menu_event_listeners), window_event_listeners: Arc::new(window_event_listeners), - menu_ids, }), _marker: Args::default(), } @@ -208,6 +227,7 @@ impl WindowManager

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

{ } } + #[cfg(feature = "menu")] if !pending.window_builder.has_menu() { pending.window_builder = pending.window_builder.menu(self.inner.menu.clone()); } @@ -471,8 +492,8 @@ mod test { Box::new(|_, _| ()), Default::default(), StateManager::new(), - Vec::new(), Default::default(), + #[cfg(feature = "menu")] Default::default(), ); @@ -565,17 +586,20 @@ impl WindowManager

{ }); } }); - let window_ = window.clone(); - let menu_event_listeners = self.inner.menu_event_listeners.clone(); - window.on_menu_event(move |event| { - let _ = on_menu_event(&window_, &event); - for handler in menu_event_listeners.iter() { - handler(WindowMenuEvent { - window: window_.clone(), - menu_item_id: event.menu_item_id.clone(), - }); - } - }); + #[cfg(feature = "menu")] + { + let window_ = window.clone(); + let menu_event_listeners = self.inner.menu_event_listeners.clone(); + window.on_menu_event(move |event| { + let _ = on_menu_event(&window_, &event); + for handler in menu_event_listeners.iter() { + handler(WindowMenuEvent { + window: window_.clone(), + menu_item_id: event.menu_item_id.clone(), + }); + } + }); + } // insert the window into our manager { @@ -762,6 +786,7 @@ struct ScaleFactorChanged { size: PhysicalSize, } +#[cfg(feature = "menu")] fn on_menu_event(window: &Window

, event: &MenuEvent) -> crate::Result<()> { window.emit( &MENU_EVENT diff --git a/core/tauri/src/state.rs b/core/tauri/src/state.rs index c99207c71..1f3798913 100644 --- a/core/tauri/src/state.rs +++ b/core/tauri/src/state.rs @@ -12,7 +12,7 @@ pub struct State<'r, T: Send + Sync + 'static>(&'r T); impl<'r, T: Send + Sync + 'static> State<'r, T> { /// Retrieve a borrow to the underlying value with a lifetime of `'r`. /// Using this method is typically unnecessary as `State` implements - /// [`Deref`] with a [`Deref::Target`] of `T`. + /// [`std::ops::Deref`] with a [`std::ops::Deref::Target`] of `T`. #[inline(always)] pub fn inner(&self) -> &'r T { self.0 diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index cd5203e6a..f53d43909 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +#[cfg(feature = "menu")] +use crate::runtime::MenuId; use crate::{ api::config::WindowUrl, command::{CommandArg, CommandItem}, event::{Event, EventHandler}, manager::WindowManager, runtime::{ - menu::MenuId, monitor::Monitor as RuntimeMonitor, tag::{TagRef, ToJsString}, webview::{InvokePayload, WebviewAttributes, WindowBuilder}, @@ -31,11 +32,14 @@ use std::{ }; /// The window menu event. +#[cfg(feature = "menu")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] #[derive(Debug, Clone)] pub struct MenuEvent { pub(crate) menu_item_id: I, } +#[cfg(feature = "menu")] impl MenuEvent { /// The menu item id. pub fn menu_item_id(&self) -> &I { @@ -287,6 +291,8 @@ impl Window

{ } /// Registers a menu event listener. + #[cfg(feature = "menu")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))] pub fn on_menu_event) + Send + 'static>(&self, f: F) { let menu_ids = self.manager.menu_ids(); self.window.dispatcher.on_menu_event(move |event| { diff --git a/examples/api/src-tauri/Cargo.toml b/examples/api/src-tauri/Cargo.toml index c96877f0c..2728379e3 100644 --- a/examples/api/src-tauri/Cargo.toml +++ b/examples/api/src-tauri/Cargo.toml @@ -11,7 +11,7 @@ tauri-build = { path = "../../../core/tauri-build" } [dependencies] serde_json = "1.0" serde = { version = "1.0", features = [ "derive" ] } -tauri = { path = "../../../core/tauri", features = ["api-all", "cli", "updater"] } +tauri = { path = "../../../core/tauri", features = ["api-all", "cli", "updater", "system-tray", "menu"] } [features] default = [ "custom-protocol" ] diff --git a/tooling/cli.rs/src/helpers/manifest.rs b/tooling/cli.rs/src/helpers/manifest.rs index 41af17e89..30a78c280 100644 --- a/tooling/cli.rs/src/helpers/manifest.rs +++ b/tooling/cli.rs/src/helpers/manifest.rs @@ -43,6 +43,9 @@ pub fn rewrite_manifest(config: ConfigHandle) -> crate::Result<()> { if config.tauri.updater.active { features.push("updater").unwrap(); } + if config.tauri.system_tray.is_some() { + features.push("system-tray").unwrap(); + } if let Some(tauri) = tauri_entry.as_table_mut() { let manifest_features = tauri.entry("features"); @@ -51,6 +54,15 @@ pub fn rewrite_manifest(config: ConfigHandle) -> crate::Result<()> { match tauri { Value::InlineTable(table) => { let manifest_features = table.get_or_insert("features", Value::Array(Default::default())); + if let Value::Array(f) = &manifest_features { + for feat in f.iter() { + if let Value::String(feature) = feat { + if feature.value() == "menu" { + features.push("menu").unwrap(); + } + } + } + } *manifest_features = Value::Array(features); } Value::String(version) => {