mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-01-31 00:35:19 +01:00
refactor(core): menu and system-tray feature flags (#1765)
This commit is contained in:
committed by
GitHub
parent
08c1c5ca5c
commit
22676df57a
8
.github/CONTRIBUTING.md
vendored
8
.github/CONTRIBUTING.md
vendored
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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" ]
|
||||
|
||||
@@ -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<dyn FnOnce(&EventLoopWindowTarget<Message>) -> Result<WebView> + Send>;
|
||||
type MainThreadTask = Box<dyn FnOnce() + Send>;
|
||||
type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
|
||||
type WindowEventListeners = Arc<Mutex<HashMap<Uuid, WindowEventHandler>>>;
|
||||
type MenuEventHandler = Box<dyn Fn(&MenuEvent) + Send>;
|
||||
type MenuEventListeners = Arc<Mutex<HashMap<Uuid, MenuEventHandler>>>;
|
||||
type SystemTrayEventHandler = Box<dyn Fn(&SystemTrayEvent) + Send>;
|
||||
type SystemTrayEventListeners = HashMap<Uuid, SystemTrayEventHandler>;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
@@ -219,73 +221,6 @@ impl From<Position> for PositionWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CustomMenuWrapper(WryCustomMenu);
|
||||
|
||||
impl<I: MenuId> From<CustomMenuItem<I>> for CustomMenuWrapper {
|
||||
fn from(item: CustomMenuItem<I>) -> Self {
|
||||
Self(WryCustomMenu {
|
||||
id: WryMenuId(item.id_value()),
|
||||
name: item.name,
|
||||
keyboard_accelerators: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct MenuItemWrapper(WryMenuItem);
|
||||
|
||||
impl<I: MenuId> From<MenuItem<I>> for MenuItemWrapper {
|
||||
fn from(item: MenuItem<I>) -> 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<I: MenuId> From<Menu<I>> for MenuWrapper {
|
||||
fn from(menu: Menu<I>) -> Self {
|
||||
Self(WryMenu {
|
||||
title: menu.title,
|
||||
items: menu
|
||||
.items
|
||||
.into_iter()
|
||||
.map(|m| MenuItemWrapper::from(m).0)
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: MenuId> From<SystemTrayMenuItem<I>> for MenuItemWrapper {
|
||||
fn from(item: SystemTrayMenuItem<I>) -> 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<I: MenuId>(self, menu: Vec<Menu<I>>) -> 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<Message>,
|
||||
task_tx: Sender<MainThreadTask>,
|
||||
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<F: Fn(&MenuEvent) + Send + 'static>(&self, f: F) -> Uuid {
|
||||
let id = Uuid::new_v4();
|
||||
self
|
||||
@@ -817,7 +756,9 @@ pub struct Wry {
|
||||
webviews: Mutex<HashMap<WindowId, WebView>>,
|
||||
task_tx: Sender<MainThreadTask>,
|
||||
window_event_listeners: WindowEventListeners,
|
||||
#[cfg(feature = "menu")]
|
||||
menu_event_listeners: MenuEventListeners,
|
||||
#[cfg(feature = "system-tray")]
|
||||
system_tray_event_listeners: SystemTrayEventListeners,
|
||||
task_rx: Receiver<MainThreadTask>,
|
||||
}
|
||||
@@ -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<I: MenuId>(
|
||||
&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<I: MenuId>(
|
||||
&self,
|
||||
icon: Vec<u8>,
|
||||
@@ -911,6 +856,7 @@ impl Runtime for Wry {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "system-tray")]
|
||||
fn on_system_tray_event<F: Fn(&SystemTrayEvent) + Send + 'static>(&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,
|
||||
|
||||
92
core/tauri-runtime-wry/src/menu.rs
Normal file
92
core/tauri-runtime-wry/src/menu.rs
Normal file
@@ -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<dyn Fn(&MenuEvent) + Send>;
|
||||
pub type MenuEventListeners = Arc<Mutex<HashMap<Uuid, MenuEventHandler>>>;
|
||||
pub type SystemTrayEventHandler = Box<dyn Fn(&SystemTrayEvent) + Send>;
|
||||
pub type SystemTrayEventListeners = HashMap<Uuid, SystemTrayEventHandler>;
|
||||
|
||||
pub struct CustomMenuWrapper(pub WryCustomMenu);
|
||||
|
||||
impl<I: MenuId> From<CustomMenuItem<I>> for CustomMenuWrapper {
|
||||
fn from(item: CustomMenuItem<I>) -> Self {
|
||||
Self(WryCustomMenu {
|
||||
id: WryMenuId(item.id_value()),
|
||||
name: item.name,
|
||||
keyboard_accelerators: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MenuItemWrapper(pub WryMenuItem);
|
||||
|
||||
impl<I: MenuId> From<MenuItem<I>> for MenuItemWrapper {
|
||||
fn from(item: MenuItem<I>) -> 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<I: MenuId> From<Menu<I>> for MenuWrapper {
|
||||
fn from(menu: Menu<I>) -> Self {
|
||||
Self(WryMenu {
|
||||
title: menu.title,
|
||||
items: menu
|
||||
.items
|
||||
.into_iter()
|
||||
.map(|m| MenuItemWrapper::from(m).0)
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: MenuId> From<SystemTrayMenuItem<I>> for MenuItemWrapper {
|
||||
fn from(item: SystemTrayMenuItem<I>) -> Self {
|
||||
match item {
|
||||
SystemTrayMenuItem::Custom(custom) => {
|
||||
Self(WryMenuItem::Custom(CustomMenuWrapper::from(custom).0))
|
||||
}
|
||||
SystemTrayMenuItem::Separator => Self(WryMenuItem::Separator),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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<T> 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<dyn std::error::Error + Send>),
|
||||
/// Failed to load window icon.
|
||||
@@ -108,22 +119,29 @@ pub trait Runtime: Sized + 'static {
|
||||
) -> crate::Result<DetachedWindow<P>>;
|
||||
|
||||
/// 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<I: MenuId>(
|
||||
&self,
|
||||
icon: std::path::PathBuf,
|
||||
menu: Vec<SystemTrayMenuItem<I>>,
|
||||
menu: Vec<menu::SystemTrayMenuItem<I>>,
|
||||
) -> 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<I: MenuId>(
|
||||
&self,
|
||||
icon: Vec<u8>,
|
||||
menu: Vec<SystemTrayMenuItem<I>>,
|
||||
menu: Vec<menu::SystemTrayMenuItem<I>>,
|
||||
) -> 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<F: Fn(&SystemTrayEvent) + Send + 'static>(&mut self, f: F) -> Uuid;
|
||||
|
||||
/// Run the webview runtime.
|
||||
@@ -145,7 +163,9 @@ pub trait Dispatch: Clone + Send + Sized + 'static {
|
||||
fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> Uuid;
|
||||
|
||||
/// Registers a window event handler.
|
||||
fn on_menu_event<F: Fn(&MenuEvent) + Send + 'static>(&self, f: F) -> Uuid;
|
||||
#[cfg(feature = "menu")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))]
|
||||
fn on_menu_event<F: Fn(&window::MenuEvent) + Send + 'static>(&self, f: F) -> Uuid;
|
||||
|
||||
// GETTERS
|
||||
|
||||
|
||||
@@ -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<T> MenuId for T where T: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {}
|
||||
use super::MenuId;
|
||||
|
||||
/// A window menu.
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -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<I: MenuId>(self, menu: Vec<Menu<I>>) -> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ pub struct DetachedWindow<M: Params> {
|
||||
/// 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: <M::Runtime as Runtime>::Dispatcher,
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = [ ]
|
||||
|
||||
@@ -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
|
||||
/// ```
|
||||
|
||||
@@ -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<P> = Box<dyn Fn(WindowMenuEvent<P>) + Send + Sync>;
|
||||
pub(crate) type GlobalWindowEventListener<P> = Box<dyn Fn(GlobalWindowEvent<P>) + Send + Sync>;
|
||||
#[cfg(feature = "system-tray")]
|
||||
type SystemTrayEventListener<P> =
|
||||
Box<dyn Fn(&AppHandle<P>, SystemTrayEvent<<P as Params>::SystemTrayMenuId>) + Send + Sync>;
|
||||
|
||||
/// System tray event.
|
||||
#[cfg(feature = "system-tray")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
|
||||
pub struct SystemTrayEvent<I: MenuId> {
|
||||
menu_item_id: I,
|
||||
}
|
||||
|
||||
#[cfg(feature = "system-tray")]
|
||||
impl<I: MenuId> SystemTrayEvent<I> {
|
||||
/// The menu item id.
|
||||
pub fn menu_item_id(&self) -> &I {
|
||||
@@ -42,11 +51,14 @@ impl<I: MenuId> SystemTrayEvent<I> {
|
||||
}
|
||||
|
||||
/// A menu event that was triggered on a window.
|
||||
#[cfg(feature = "menu")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))]
|
||||
pub struct WindowMenuEvent<P: Params> {
|
||||
pub(crate) menu_item_id: P::MenuId,
|
||||
pub(crate) window: Window<P>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
impl<P: Params> WindowMenuEvent<P> {
|
||||
/// 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<MID>>,
|
||||
|
||||
/// Menu event handlers that listens to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_event_listeners: Vec<GlobalMenuEventListener<Args<E, L, MID, TID, A, R>>>,
|
||||
|
||||
/// Window event handlers that listens to all windows.
|
||||
window_event_listeners: Vec<GlobalWindowEventListener<Args<E, L, MID, TID, A, R>>>,
|
||||
|
||||
/// The app system tray menu items.
|
||||
#[cfg(feature = "system-tray")]
|
||||
system_tray: Vec<SystemTrayMenuItem<TID>>,
|
||||
|
||||
/// System tray event handlers.
|
||||
#[cfg(feature = "system-tray")]
|
||||
system_tray_event_listeners: Vec<SystemTrayEventListener<Args<E, L, MID, TID, A, R>>>,
|
||||
}
|
||||
|
||||
@@ -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<SystemTrayMenuItem<TID>>) -> 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<Menu<MID>>) -> 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<Args<E, L, MID, TID, A, R>>) + 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<Args<E, L, MID, TID, A, R>>, SystemTrayEvent<TID>) + Send + Sync + 'static,
|
||||
>(
|
||||
@@ -445,6 +473,7 @@ where
|
||||
|
||||
/// Runs the configured Tauri application.
|
||||
pub fn run(mut self, context: Context<A>) -> 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<I: MenuId>(items: &[SystemTrayMenuItem<I>]) -> HashMap<u32, I> {
|
||||
let mut map = HashMap::new();
|
||||
for item in items {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<P: Params>: sealed::ManagerBase<P> {
|
||||
}
|
||||
|
||||
/// Add `state` to the state managed by the application.
|
||||
/// See [`tauri::Builder#manage`] for instructions.
|
||||
/// See [`crate::Builder#manage`] for instructions.
|
||||
fn manage<T>(&self, state: T)
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
|
||||
@@ -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<P: Params> {
|
||||
/// The webview protocols protocols available to all windows.
|
||||
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol>>,
|
||||
/// The menu set to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu: Vec<Menu<P::MenuId>>,
|
||||
/// Maps runtime id to a strongly typed menu id.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_ids: HashMap<u32, P::MenuId>,
|
||||
/// Menu event listeners to all windows.
|
||||
#[cfg(feature = "menu")]
|
||||
menu_event_listeners: Arc<Vec<GlobalMenuEventListener<P>>>,
|
||||
/// Window event listeners to all windows.
|
||||
window_event_listeners: Arc<Vec<GlobalWindowEventListener<P>>>,
|
||||
menu_ids: HashMap<u32, P::MenuId>,
|
||||
}
|
||||
|
||||
/// A [Zero Sized Type] marker representing a full [`Params`].
|
||||
@@ -148,6 +162,7 @@ impl<P: Params> Clone for WindowManager<P> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
fn get_menu_ids<I: MenuId>(menu: &[Menu<I>]) -> HashMap<u32, I> {
|
||||
let mut map = HashMap::new();
|
||||
for m in menu {
|
||||
@@ -169,11 +184,12 @@ impl<P: Params> WindowManager<P> {
|
||||
on_page_load: Box<OnPageLoad<P>>,
|
||||
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol>>,
|
||||
state: StateManager,
|
||||
menu: Vec<Menu<P::MenuId>>,
|
||||
menu_event_listeners: Vec<GlobalMenuEventListener<P>>,
|
||||
window_event_listeners: Vec<GlobalWindowEventListener<P>>,
|
||||
#[cfg(feature = "menu")] (menu, menu_event_listeners): (
|
||||
Vec<Menu<P::MenuId>>,
|
||||
Vec<GlobalMenuEventListener<P>>,
|
||||
),
|
||||
) -> Self {
|
||||
let menu_ids = get_menu_ids(&menu);
|
||||
Self {
|
||||
inner: Arc::new(InnerWindowManager {
|
||||
windows: Mutex::default(),
|
||||
@@ -188,10 +204,13 @@ impl<P: Params> WindowManager<P> {
|
||||
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<P: Params> WindowManager<P> {
|
||||
}
|
||||
|
||||
/// Get the menu ids mapper.
|
||||
#[cfg(feature = "menu")]
|
||||
pub(crate) fn menu_ids(&self) -> HashMap<u32, P::MenuId> {
|
||||
self.inner.menu_ids.clone()
|
||||
}
|
||||
@@ -259,6 +279,7 @@ impl<P: Params> WindowManager<P> {
|
||||
}
|
||||
}
|
||||
|
||||
#[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<P: Params> WindowManager<P> {
|
||||
});
|
||||
}
|
||||
});
|
||||
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<u32>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
fn on_menu_event<P: Params>(window: &Window<P>, event: &MenuEvent<P::MenuId>) -> crate::Result<()> {
|
||||
window.emit(
|
||||
&MENU_EVENT
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<I: MenuId> {
|
||||
pub(crate) menu_item_id: I,
|
||||
}
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
impl<I: MenuId> MenuEvent<I> {
|
||||
/// The menu item id.
|
||||
pub fn menu_item_id(&self) -> &I {
|
||||
@@ -287,6 +291,8 @@ impl<P: Params> Window<P> {
|
||||
}
|
||||
|
||||
/// Registers a menu event listener.
|
||||
#[cfg(feature = "menu")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))]
|
||||
pub fn on_menu_event<F: Fn(MenuEvent<P::MenuId>) + Send + 'static>(&self, f: F) {
|
||||
let menu_ids = self.manager.menu_ids();
|
||||
self.window.dispatcher.on_menu_event(move |event| {
|
||||
|
||||
@@ -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" ]
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user