lib.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! Internal runtime between Tauri and the underlying webview runtime.
  5. #![cfg_attr(doc_cfg, feature(doc_cfg))]
  6. use serde::Deserialize;
  7. use std::{fmt::Debug, path::PathBuf, sync::mpsc::Sender};
  8. use uuid::Uuid;
  9. #[cfg(windows)]
  10. use winapi::shared::windef::HWND;
  11. /// Create window and system tray menus.
  12. pub mod menu;
  13. /// Types useful for interacting with a user's monitors.
  14. pub mod monitor;
  15. pub mod webview;
  16. pub mod window;
  17. use monitor::Monitor;
  18. use webview::WindowBuilder;
  19. use window::{
  20. dpi::{PhysicalPosition, PhysicalSize, Position, Size},
  21. DetachedWindow, PendingWindow, WindowEvent,
  22. };
  23. #[cfg(feature = "system-tray")]
  24. #[non_exhaustive]
  25. #[derive(Debug)]
  26. pub struct SystemTray {
  27. pub icon: Option<Icon>,
  28. pub menu: Option<menu::SystemTrayMenu>,
  29. #[cfg(target_os = "macos")]
  30. pub icon_as_template: bool,
  31. }
  32. #[cfg(feature = "system-tray")]
  33. impl Default for SystemTray {
  34. fn default() -> Self {
  35. Self {
  36. icon: None,
  37. menu: None,
  38. #[cfg(target_os = "macos")]
  39. icon_as_template: false,
  40. }
  41. }
  42. }
  43. #[cfg(feature = "system-tray")]
  44. impl SystemTray {
  45. /// Creates a new system tray that only renders an icon.
  46. pub fn new() -> Self {
  47. Default::default()
  48. }
  49. pub fn menu(&self) -> Option<&menu::SystemTrayMenu> {
  50. self.menu.as_ref()
  51. }
  52. /// Sets the tray icon. Must be a [`Icon::File`] on Linux and a [`Icon::Raw`] on Windows and macOS.
  53. pub fn with_icon(mut self, icon: Icon) -> Self {
  54. self.icon.replace(icon);
  55. self
  56. }
  57. /// Sets the tray icon as template.
  58. #[cfg(target_os = "macos")]
  59. pub fn with_icon_as_template(mut self, is_template: bool) -> Self {
  60. self.icon_as_template = is_template;
  61. self
  62. }
  63. /// Sets the menu to show when the system tray is right clicked.
  64. pub fn with_menu(mut self, menu: menu::SystemTrayMenu) -> Self {
  65. self.menu.replace(menu);
  66. self
  67. }
  68. }
  69. /// Type of user attention requested on a window.
  70. #[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
  71. #[serde(tag = "type")]
  72. pub enum UserAttentionType {
  73. /// ## Platform-specific
  74. /// - **macOS:** Bounces the dock icon until the application is in focus.
  75. /// - **Windows:** Flashes both the window and the taskbar button until the application is in focus.
  76. Critical,
  77. /// ## Platform-specific
  78. /// - **macOS:** Bounces the dock icon once.
  79. /// - **Windows:** Flashes the taskbar button until the application is in focus.
  80. Informational,
  81. }
  82. #[derive(Debug, thiserror::Error)]
  83. #[non_exhaustive]
  84. pub enum Error {
  85. /// Failed to create webview.
  86. #[error("failed to create webview: {0}")]
  87. CreateWebview(Box<dyn std::error::Error + Send>),
  88. /// Failed to create window.
  89. #[error("failed to create window")]
  90. CreateWindow,
  91. /// Failed to send message to webview.
  92. #[error("failed to send message to the webview")]
  93. FailedToSendMessage,
  94. /// Failed to serialize/deserialize.
  95. #[error("JSON error: {0}")]
  96. Json(#[from] serde_json::Error),
  97. /// Encountered an error creating the app system tray.
  98. #[cfg(feature = "system-tray")]
  99. #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
  100. #[error("error encountered during tray setup: {0}")]
  101. SystemTray(Box<dyn std::error::Error + Send>),
  102. /// Failed to load window icon.
  103. #[error("invalid icon: {0}")]
  104. InvalidIcon(Box<dyn std::error::Error + Send>),
  105. /// Failed to get monitor on window operation.
  106. #[error("failed to get monitor")]
  107. FailedToGetMonitor,
  108. /// Global shortcut error.
  109. #[error(transparent)]
  110. GlobalShortcut(Box<dyn std::error::Error + Send>),
  111. }
  112. /// Result type.
  113. pub type Result<T> = std::result::Result<T, Error>;
  114. /// A icon definition.
  115. #[derive(Debug, Clone)]
  116. #[non_exhaustive]
  117. pub enum Icon {
  118. /// Icon from file path.
  119. File(PathBuf),
  120. /// Icon from raw bytes.
  121. Raw(Vec<u8>),
  122. }
  123. impl Icon {
  124. /// Converts the icon to a the expected system tray format.
  125. /// We expect the code that passes the Icon enum to have already checked the platform.
  126. #[cfg(target_os = "linux")]
  127. pub fn into_tray_icon(self) -> PathBuf {
  128. match self {
  129. Icon::File(path) => path,
  130. Icon::Raw(_) => {
  131. panic!("linux requires the system menu icon to be a file path, not bytes.")
  132. }
  133. }
  134. }
  135. /// Converts the icon to a the expected system tray format.
  136. /// We expect the code that passes the Icon enum to have already checked the platform.
  137. #[cfg(not(target_os = "linux"))]
  138. pub fn into_tray_icon(self) -> Vec<u8> {
  139. match self {
  140. Icon::Raw(bytes) => bytes,
  141. Icon::File(_) => {
  142. panic!("non-linux system menu icons must be bytes, not a file path.")
  143. }
  144. }
  145. }
  146. }
  147. /// Event triggered on the event loop run.
  148. #[non_exhaustive]
  149. pub enum RunEvent {
  150. /// Event loop is exiting.
  151. Exit,
  152. /// Event loop is about to exit
  153. ExitRequested {
  154. /// Label of the last window managed by the runtime.
  155. window_label: String,
  156. tx: Sender<ExitRequestedEventAction>,
  157. },
  158. /// Window close was requested by the user.
  159. CloseRequested {
  160. /// The window label.
  161. label: String,
  162. /// A signal sender. If a `true` value is emitted, the window won't be closed.
  163. signal_tx: Sender<bool>,
  164. },
  165. /// Window closed.
  166. WindowClose(String),
  167. /// Application ready.
  168. Ready,
  169. /// Sent if the event loop is being resumed.
  170. Resumed,
  171. /// Emitted when all of the event loop’s input events have been processed and redraw processing is about to begin.
  172. ///
  173. /// This event is useful as a place to put your code that should be run after all state-changing events have been handled and you want to do stuff (updating state, performing calculations, etc) that happens as the “main body” of your event loop.
  174. MainEventsCleared,
  175. }
  176. /// Action to take when the event loop is about to exit
  177. #[derive(Debug)]
  178. pub enum ExitRequestedEventAction {
  179. /// Prevent the event loop from exiting
  180. Prevent,
  181. }
  182. /// A system tray event.
  183. #[derive(Debug)]
  184. pub enum SystemTrayEvent {
  185. MenuItemClick(u16),
  186. LeftClick {
  187. position: PhysicalPosition<f64>,
  188. size: PhysicalSize<f64>,
  189. },
  190. RightClick {
  191. position: PhysicalPosition<f64>,
  192. size: PhysicalSize<f64>,
  193. },
  194. DoubleClick {
  195. position: PhysicalPosition<f64>,
  196. size: PhysicalSize<f64>,
  197. },
  198. }
  199. /// Metadata for a runtime event loop iteration on `run_iteration`.
  200. #[derive(Debug, Clone, Default)]
  201. pub struct RunIteration {
  202. pub window_count: usize,
  203. }
  204. /// Application's activation policy. Corresponds to NSApplicationActivationPolicy.
  205. #[cfg(target_os = "macos")]
  206. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  207. #[non_exhaustive]
  208. pub enum ActivationPolicy {
  209. /// Corresponds to NSApplicationActivationPolicyRegular.
  210. Regular,
  211. /// Corresponds to NSApplicationActivationPolicyAccessory.
  212. Accessory,
  213. /// Corresponds to NSApplicationActivationPolicyProhibited.
  214. Prohibited,
  215. }
  216. /// A [`Send`] handle to the runtime.
  217. pub trait RuntimeHandle: Debug + Send + Sized + Clone + 'static {
  218. type Runtime: Runtime<Handle = Self>;
  219. /// Create a new webview window.
  220. fn create_window(
  221. &self,
  222. pending: PendingWindow<Self::Runtime>,
  223. ) -> crate::Result<DetachedWindow<Self::Runtime>>;
  224. #[cfg(all(windows, feature = "system-tray"))]
  225. #[cfg_attr(doc_cfg, doc(cfg(all(windows, feature = "system-tray"))))]
  226. fn remove_system_tray(&self) -> crate::Result<()>;
  227. }
  228. /// A global shortcut manager.
  229. pub trait GlobalShortcutManager: Debug {
  230. /// Whether the application has registered the given `accelerator`.
  231. ///
  232. /// # Panics
  233. ///
  234. /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure.
  235. /// - Panics when called on the main thread, usually on the `tauri::App#run`closure.
  236. ///
  237. /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic.
  238. fn is_registered(&self, accelerator: &str) -> crate::Result<bool>;
  239. /// Register a global shortcut of `accelerator`.
  240. ///
  241. /// # Panics
  242. ///
  243. /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure.
  244. /// - Panics when called on the main thread, usually on the `tauri::App#run`closure.
  245. ///
  246. /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic.
  247. fn register<F: Fn() + Send + 'static>(
  248. &mut self,
  249. accelerator: &str,
  250. handler: F,
  251. ) -> crate::Result<()>;
  252. /// Unregister all accelerators registered by the manager instance.
  253. ///
  254. /// # Panics
  255. ///
  256. /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure.
  257. /// - Panics when called on the main thread, usually on the `tauri::App#run`closure.
  258. ///
  259. /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic.
  260. fn unregister_all(&mut self) -> crate::Result<()>;
  261. /// Unregister the provided `accelerator`.
  262. ///
  263. /// # Panics
  264. ///
  265. /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure.
  266. /// - Panics when called on the main thread, usually on the `tauri::App#run`closure.
  267. ///
  268. /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic.
  269. fn unregister(&mut self, accelerator: &str) -> crate::Result<()>;
  270. }
  271. /// Clipboard manager.
  272. pub trait ClipboardManager: Debug {
  273. /// Writes the text into the clipboard as plain text.
  274. ///
  275. /// # Panics
  276. ///
  277. /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure.
  278. /// - Panics when called on the main thread, usually on the `tauri::App#run`closure.
  279. ///
  280. /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic.
  281. fn write_text<T: Into<String>>(&mut self, text: T) -> Result<()>;
  282. /// Read the content in the clipboard as plain text.
  283. ///
  284. /// # Panics
  285. ///
  286. /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure.
  287. /// - Panics when called on the main thread, usually on the `tauri::App#run`closure.
  288. ///
  289. /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic.
  290. fn read_text(&self) -> Result<Option<String>>;
  291. }
  292. /// The webview runtime interface.
  293. pub trait Runtime: Sized + 'static {
  294. /// The message dispatcher.
  295. type Dispatcher: Dispatch<Runtime = Self>;
  296. /// The runtime handle type.
  297. type Handle: RuntimeHandle<Runtime = Self>;
  298. /// The global shortcut manager type.
  299. type GlobalShortcutManager: GlobalShortcutManager + Clone + Send;
  300. /// The clipboard manager type.
  301. type ClipboardManager: ClipboardManager + Clone + Send;
  302. /// The tray handler type.
  303. #[cfg(feature = "system-tray")]
  304. type TrayHandler: menu::TrayHandle + Clone + Send;
  305. /// Creates a new webview runtime.
  306. fn new() -> crate::Result<Self>;
  307. /// Gets a runtime handle.
  308. fn handle(&self) -> Self::Handle;
  309. /// Gets the global shortcut manager.
  310. fn global_shortcut_manager(&self) -> Self::GlobalShortcutManager;
  311. /// Gets the clipboard manager.
  312. fn clipboard_manager(&self) -> Self::ClipboardManager;
  313. /// Create a new webview window.
  314. fn create_window(&self, pending: PendingWindow<Self>) -> crate::Result<DetachedWindow<Self>>;
  315. /// Adds the icon to the system tray with the specified menu items.
  316. #[cfg(feature = "system-tray")]
  317. #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
  318. fn system_tray(&self, system_tray: SystemTray) -> crate::Result<Self::TrayHandler>;
  319. /// Registers a system tray event handler.
  320. #[cfg(feature = "system-tray")]
  321. #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
  322. fn on_system_tray_event<F: Fn(&SystemTrayEvent) + Send + 'static>(&mut self, f: F) -> Uuid;
  323. /// Sets the activation policy for the application. It is set to `NSApplicationActivationPolicyRegular` by default.
  324. #[cfg(target_os = "macos")]
  325. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  326. fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
  327. /// Runs the one step of the webview runtime event loop and returns control flow to the caller.
  328. #[cfg(any(target_os = "windows", target_os = "macos"))]
  329. fn run_iteration<F: Fn(RunEvent) + 'static>(&mut self, callback: F) -> RunIteration;
  330. /// Run the webview runtime.
  331. fn run<F: Fn(RunEvent) + 'static>(self, callback: F);
  332. }
  333. /// Webview dispatcher. A thread-safe handle to the webview API.
  334. pub trait Dispatch: Debug + Clone + Send + Sized + 'static {
  335. /// The runtime this [`Dispatch`] runs under.
  336. type Runtime: Runtime;
  337. /// The winoow builder type.
  338. type WindowBuilder: WindowBuilder + Clone;
  339. /// Run a task on the main thread.
  340. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()>;
  341. /// Registers a window event handler.
  342. fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> Uuid;
  343. /// Registers a window event handler.
  344. fn on_menu_event<F: Fn(&window::MenuEvent) + Send + 'static>(&self, f: F) -> Uuid;
  345. // GETTERS
  346. /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
  347. fn scale_factor(&self) -> crate::Result<f64>;
  348. /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
  349. fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>>;
  350. /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
  351. fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>>;
  352. /// Returns the physical size of the window's client area.
  353. ///
  354. /// The client area is the content of the window, excluding the title bar and borders.
  355. fn inner_size(&self) -> crate::Result<PhysicalSize<u32>>;
  356. /// Returns the physical size of the entire window.
  357. ///
  358. /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
  359. fn outer_size(&self) -> crate::Result<PhysicalSize<u32>>;
  360. /// Gets the window's current fullscreen state.
  361. fn is_fullscreen(&self) -> crate::Result<bool>;
  362. /// Gets the window's current maximized state.
  363. fn is_maximized(&self) -> crate::Result<bool>;
  364. /// Gets the window’s current decoration state.
  365. fn is_decorated(&self) -> crate::Result<bool>;
  366. /// Gets the window’s current resizable state.
  367. fn is_resizable(&self) -> crate::Result<bool>;
  368. /// Gets the window's current vibility state.
  369. fn is_visible(&self) -> crate::Result<bool>;
  370. /// Gets the window menu current visibility state.
  371. fn is_menu_visible(&self) -> crate::Result<bool>;
  372. /// Returns the monitor on which the window currently resides.
  373. ///
  374. /// Returns None if current monitor can't be detected.
  375. fn current_monitor(&self) -> crate::Result<Option<Monitor>>;
  376. /// Returns the primary monitor of the system.
  377. ///
  378. /// Returns None if it can't identify any monitor as a primary one.
  379. fn primary_monitor(&self) -> crate::Result<Option<Monitor>>;
  380. /// Returns the list of all the monitors available on the system.
  381. fn available_monitors(&self) -> crate::Result<Vec<Monitor>>;
  382. /// Returns the native handle that is used by this window.
  383. #[cfg(windows)]
  384. fn hwnd(&self) -> crate::Result<HWND>;
  385. /// Returns the native handle that is used by this window.
  386. #[cfg(target_os = "macos")]
  387. fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void>;
  388. /// Returns the `ApplicatonWindow` from gtk crate that is used by this window.
  389. #[cfg(any(
  390. target_os = "linux",
  391. target_os = "dragonfly",
  392. target_os = "freebsd",
  393. target_os = "netbsd",
  394. target_os = "openbsd"
  395. ))]
  396. fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow>;
  397. // SETTERS
  398. /// Centers the window.
  399. fn center(&self) -> crate::Result<()>;
  400. /// Opens the dialog to prints the contents of the webview.
  401. fn print(&self) -> crate::Result<()>;
  402. /// Requests user attention to the window.
  403. ///
  404. /// Providing `None` will unset the request for user attention.
  405. fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> crate::Result<()>;
  406. /// Create a new webview window.
  407. fn create_window(
  408. &mut self,
  409. pending: PendingWindow<Self::Runtime>,
  410. ) -> crate::Result<DetachedWindow<Self::Runtime>>;
  411. /// Updates the window resizable flag.
  412. fn set_resizable(&self, resizable: bool) -> crate::Result<()>;
  413. /// Updates the window title.
  414. fn set_title<S: Into<String>>(&self, title: S) -> crate::Result<()>;
  415. /// Maximizes the window.
  416. fn maximize(&self) -> crate::Result<()>;
  417. /// Unmaximizes the window.
  418. fn unmaximize(&self) -> crate::Result<()>;
  419. /// Minimizes the window.
  420. fn minimize(&self) -> crate::Result<()>;
  421. /// Unminimizes the window.
  422. fn unminimize(&self) -> crate::Result<()>;
  423. /// Shows the window menu.
  424. fn show_menu(&self) -> crate::Result<()>;
  425. /// Hides the window menu.
  426. fn hide_menu(&self) -> crate::Result<()>;
  427. /// Shows the window.
  428. fn show(&self) -> crate::Result<()>;
  429. /// Hides the window.
  430. fn hide(&self) -> crate::Result<()>;
  431. /// Closes the window.
  432. fn close(&self) -> crate::Result<()>;
  433. /// Updates the hasDecorations flag.
  434. fn set_decorations(&self, decorations: bool) -> crate::Result<()>;
  435. /// Updates the window alwaysOnTop flag.
  436. fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()>;
  437. /// Resizes the window.
  438. fn set_size(&self, size: Size) -> crate::Result<()>;
  439. /// Updates the window min size.
  440. fn set_min_size(&self, size: Option<Size>) -> crate::Result<()>;
  441. /// Updates the window max size.
  442. fn set_max_size(&self, size: Option<Size>) -> crate::Result<()>;
  443. /// Updates the window position.
  444. fn set_position(&self, position: Position) -> crate::Result<()>;
  445. /// Updates the window fullscreen state.
  446. fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()>;
  447. /// Bring the window to front and focus.
  448. fn set_focus(&self) -> crate::Result<()>;
  449. /// Updates the window icon.
  450. fn set_icon(&self, icon: Icon) -> crate::Result<()>;
  451. /// Whether to show the window icon in the task bar or not.
  452. fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()>;
  453. /// Starts dragging the window.
  454. fn start_dragging(&self) -> crate::Result<()>;
  455. /// Executes javascript on the window this [`Dispatch`] represents.
  456. fn eval_script<S: Into<String>>(&self, script: S) -> crate::Result<()>;
  457. /// Applies the specified `update` to the menu item associated with the given `id`.
  458. fn update_menu_item(&self, id: u16, update: menu::MenuUpdate) -> crate::Result<()>;
  459. }