tray.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. pub use crate::{
  5. runtime::{
  6. menu::{
  7. MenuHash, MenuId, MenuIdRef, MenuUpdate, SystemTrayMenu, SystemTrayMenuEntry, TrayHandle,
  8. },
  9. window::dpi::{PhysicalPosition, PhysicalSize},
  10. SystemTray,
  11. },
  12. Icon, Runtime,
  13. };
  14. use tauri_macros::default_runtime;
  15. use std::{
  16. collections::HashMap,
  17. sync::{Arc, Mutex},
  18. };
  19. pub(crate) fn get_menu_ids(map: &mut HashMap<MenuHash, MenuId>, menu: &SystemTrayMenu) {
  20. for item in &menu.items {
  21. match item {
  22. SystemTrayMenuEntry::CustomItem(c) => {
  23. map.insert(c.id, c.id_str.clone());
  24. }
  25. SystemTrayMenuEntry::Submenu(s) => get_menu_ids(map, &s.inner),
  26. _ => {}
  27. }
  28. }
  29. }
  30. /// System tray event.
  31. #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
  32. #[non_exhaustive]
  33. pub enum SystemTrayEvent {
  34. /// Tray context menu item was clicked.
  35. #[non_exhaustive]
  36. MenuItemClick {
  37. /// The id of the menu item.
  38. id: MenuId,
  39. },
  40. /// Tray icon received a left click.
  41. ///
  42. /// ## Platform-specific
  43. ///
  44. /// - **Linux:** Unsupported
  45. #[non_exhaustive]
  46. LeftClick {
  47. /// The position of the tray icon.
  48. position: PhysicalPosition<f64>,
  49. /// The size of the tray icon.
  50. size: PhysicalSize<f64>,
  51. },
  52. /// Tray icon received a right click.
  53. ///
  54. /// ## Platform-specific
  55. ///
  56. /// - **Linux:** Unsupported
  57. /// - **macOS:** `Ctrl` + `Left click` fire this event.
  58. #[non_exhaustive]
  59. RightClick {
  60. /// The position of the tray icon.
  61. position: PhysicalPosition<f64>,
  62. /// The size of the tray icon.
  63. size: PhysicalSize<f64>,
  64. },
  65. /// Fired when a menu item receive a `Double click`
  66. ///
  67. /// ## Platform-specific
  68. ///
  69. /// - **macOS / Linux:** Unsupported
  70. ///
  71. #[non_exhaustive]
  72. DoubleClick {
  73. /// The position of the tray icon.
  74. position: PhysicalPosition<f64>,
  75. /// The size of the tray icon.
  76. size: PhysicalSize<f64>,
  77. },
  78. }
  79. /// A handle to a system tray. Allows updating the context menu items.
  80. #[default_runtime(crate::Wry, wry)]
  81. #[derive(Debug)]
  82. pub struct SystemTrayHandle<R: Runtime> {
  83. pub(crate) ids: Arc<Mutex<HashMap<MenuHash, MenuId>>>,
  84. pub(crate) inner: R::TrayHandler,
  85. }
  86. impl<R: Runtime> Clone for SystemTrayHandle<R> {
  87. fn clone(&self) -> Self {
  88. Self {
  89. ids: self.ids.clone(),
  90. inner: self.inner.clone(),
  91. }
  92. }
  93. }
  94. /// A handle to a system tray menu item.
  95. #[default_runtime(crate::Wry, wry)]
  96. #[derive(Debug)]
  97. pub struct SystemTrayMenuItemHandle<R: Runtime> {
  98. id: MenuHash,
  99. tray_handler: R::TrayHandler,
  100. }
  101. impl<R: Runtime> Clone for SystemTrayMenuItemHandle<R> {
  102. fn clone(&self) -> Self {
  103. Self {
  104. id: self.id,
  105. tray_handler: self.tray_handler.clone(),
  106. }
  107. }
  108. }
  109. impl<R: Runtime> SystemTrayHandle<R> {
  110. /// Gets a handle to the menu item that has the specified `id`.
  111. pub fn get_item(&self, id: MenuIdRef<'_>) -> SystemTrayMenuItemHandle<R> {
  112. let ids = self.ids.lock().unwrap();
  113. let iter = ids.iter();
  114. for (raw, item_id) in iter {
  115. if item_id == id {
  116. return SystemTrayMenuItemHandle {
  117. id: *raw,
  118. tray_handler: self.inner.clone(),
  119. };
  120. }
  121. }
  122. panic!("item id not found")
  123. }
  124. /// Updates the tray icon.
  125. pub fn set_icon(&self, icon: Icon) -> crate::Result<()> {
  126. self.inner.set_icon(icon.try_into()?).map_err(Into::into)
  127. }
  128. /// Updates the tray menu.
  129. pub fn set_menu(&self, menu: SystemTrayMenu) -> crate::Result<()> {
  130. let mut ids = HashMap::new();
  131. get_menu_ids(&mut ids, &menu);
  132. self.inner.set_menu(menu)?;
  133. *self.ids.lock().unwrap() = ids;
  134. Ok(())
  135. }
  136. /// Support [macOS tray icon template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) to adjust automatically based on taskbar color.
  137. #[cfg(target_os = "macos")]
  138. pub fn set_icon_as_template(&self, is_template: bool) -> crate::Result<()> {
  139. self
  140. .inner
  141. .set_icon_as_template(is_template)
  142. .map_err(Into::into)
  143. }
  144. }
  145. impl<R: Runtime> SystemTrayMenuItemHandle<R> {
  146. /// Modifies the enabled state of the menu item.
  147. pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
  148. self
  149. .tray_handler
  150. .update_item(self.id, MenuUpdate::SetEnabled(enabled))
  151. .map_err(Into::into)
  152. }
  153. /// Modifies the title (label) of the menu item.
  154. pub fn set_title<S: Into<String>>(&self, title: S) -> crate::Result<()> {
  155. self
  156. .tray_handler
  157. .update_item(self.id, MenuUpdate::SetTitle(title.into()))
  158. .map_err(Into::into)
  159. }
  160. /// Modifies the selected state of the menu item.
  161. pub fn set_selected(&self, selected: bool) -> crate::Result<()> {
  162. self
  163. .tray_handler
  164. .update_item(self.id, MenuUpdate::SetSelected(selected))
  165. .map_err(Into::into)
  166. }
  167. #[cfg(target_os = "macos")]
  168. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  169. pub fn set_native_image(&self, image: crate::NativeImage) -> crate::Result<()> {
  170. self
  171. .tray_handler
  172. .update_item(self.id, MenuUpdate::SetNativeImage(image))
  173. .map_err(Into::into)
  174. }
  175. }