tray.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. import type { Menu, Submenu } from './menu'
  5. import { Channel, invoke, Resource } from './core'
  6. import { Image, transformImage } from './image'
  7. /**
  8. * Describes a tray event emitted when a tray icon is clicked
  9. *
  10. * #### Platform-specific:
  11. *
  12. * - **Linux**: Unsupported. The event is not emitted even though the icon is shown,
  13. * the icon will still show a context menu on right click.
  14. */
  15. export interface TrayIconEvent {
  16. /** Id of the tray icon which triggered this event. */
  17. id: string
  18. /** Physical X Position of the click the triggered this event. */
  19. x: number
  20. /** Physical Y Position of the click the triggered this event. */
  21. y: number
  22. /** Position and size of the tray icon. */
  23. iconRect: {
  24. /** The x-coordinate of the upper-left corner of the rectangle. */
  25. left: number
  26. /** The y-coordinate of the upper-left corner of the rectangle. */
  27. top: number
  28. /** The x-coordinate of the lower-right corner of the rectangle. */
  29. right: number
  30. /** The y-coordinate of the lower-right corner of the rectangle. */
  31. bottom: number
  32. }
  33. /** The click type that triggered this event. */
  34. clickType: 'Left' | 'Right' | 'Double'
  35. }
  36. /**
  37. * Tray icon types and utilities.
  38. *
  39. * This package is also accessible with `window.__TAURI__.tray` when [`app.withGlobalTauri`](https://tauri.app/v1/api/config/#appconfig.withglobaltauri) in `tauri.conf.json` is set to `true`.
  40. * @module
  41. */
  42. /** {@link TrayIcon.new|`TrayIcon`} creation options */
  43. export interface TrayIconOptions {
  44. /** The tray icon id. If undefined, a random one will be assigned */
  45. id?: string
  46. /** The tray icon menu */
  47. menu?: Menu | Submenu
  48. /**
  49. * The tray icon which could be icon bytes or path to the icon file.
  50. *
  51. * Note that you need the `image-ico` or `image-png` Cargo features to use this API.
  52. * To enable it, change your Cargo.toml file:
  53. * ```toml
  54. * [dependencies]
  55. * tauri = { version = "...", features = ["...", "image-png"] }
  56. * ```
  57. */
  58. icon?: string | Uint8Array | ArrayBuffer | number[] | Image
  59. /** The tray icon tooltip */
  60. tooltip?: string
  61. /**
  62. * The tray title
  63. *
  64. * #### Platform-specific
  65. *
  66. * - **Linux:** The title will not be shown unless there is an icon
  67. * as well. The title is useful for numerical and other frequently
  68. * updated information. In general, it shouldn't be shown unless a
  69. * user requests it as it can take up a significant amount of space
  70. * on the user's panel. This may not be shown in all visualizations.
  71. * - **Windows:** Unsupported.
  72. */
  73. title?: string
  74. /**
  75. * The tray icon temp dir path. **Linux only**.
  76. *
  77. * On Linux, we need to write the icon to the disk and usually it will
  78. * be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
  79. */
  80. tempDirPath?: string
  81. /**
  82. * Use the icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**.
  83. */
  84. iconAsTemplate?: boolean
  85. /** Whether to show the tray menu on left click or not, default is `true`. **macOS only**. */
  86. menuOnLeftClick?: boolean
  87. /** A handler for an event on the tray icon. */
  88. action?: (event: TrayIconEvent) => void
  89. }
  90. /**
  91. * Tray icon class and associated methods. This type constructor is private,
  92. * instead, you should use the static method {@linkcode TrayIcon.new}.
  93. *
  94. * #### Warning
  95. *
  96. * Unlike Rust, javascript does not have any way to run cleanup code
  97. * when an object is being removed by garbage collection, but this tray icon
  98. * will be cleaned up when the tauri app exists, however if you want to cleanup
  99. * this object early, you need to call {@linkcode TrayIcon.close}.
  100. *
  101. * @example
  102. * ```ts
  103. * import { TrayIcon } from '@tauri-apps/api/tray';
  104. * const tray = await TrayIcon.new({ tooltip: 'awesome tray tooltip' });
  105. * tray.set_tooltip('new tooltip');
  106. * ```
  107. */
  108. export class TrayIcon extends Resource {
  109. /** The id associated with this tray icon. */
  110. public id: string
  111. private constructor(rid: number, id: string) {
  112. super(rid)
  113. this.id = id
  114. }
  115. /** Gets a tray icon using the provided id. */
  116. static async getById(id: string): Promise<TrayIcon | null> {
  117. return invoke<number>('plugin:tray|get_by_id', { id }).then((rid) =>
  118. rid ? new TrayIcon(rid, id) : null
  119. )
  120. }
  121. /**
  122. * Removes a tray icon using the provided id from tauri's internal state.
  123. *
  124. * Note that this may cause the tray icon to disappear
  125. * if it wasn't cloned somewhere else or referenced by JS.
  126. */
  127. static async removeById(id: string): Promise<void> {
  128. return invoke('plugin:tray|remove_by_id', { id })
  129. }
  130. /**
  131. * Creates a new {@linkcode TrayIcon}
  132. *
  133. * #### Platform-specific:
  134. *
  135. * - **Linux:** Sometimes the icon won't be visible unless a menu is set.
  136. * Setting an empty {@linkcode Menu} is enough.
  137. */
  138. static async new(options?: TrayIconOptions): Promise<TrayIcon> {
  139. if (options?.menu) {
  140. // @ts-expect-error we only need the rid and kind
  141. options.menu = [options.menu.rid, options.menu.kind]
  142. }
  143. if (options?.icon) {
  144. options.icon = transformImage(options.icon)
  145. }
  146. const handler = new Channel<TrayIconEvent>()
  147. if (options?.action) {
  148. handler.onmessage = options.action
  149. delete options.action
  150. }
  151. return invoke<[number, string]>('plugin:tray|new', {
  152. options: options ?? {},
  153. handler
  154. }).then(([rid, id]) => new TrayIcon(rid, id))
  155. }
  156. /**
  157. * Sets a new tray icon. If `null` is provided, it will remove the icon.
  158. *
  159. * Note that you need the `image-ico` or `image-png` Cargo features to use this API.
  160. * To enable it, change your Cargo.toml file:
  161. * ```toml
  162. * [dependencies]
  163. * tauri = { version = "...", features = ["...", "image-png"] }
  164. * ```
  165. */
  166. async setIcon(
  167. icon: string | Image | Uint8Array | ArrayBuffer | number[] | null
  168. ): Promise<void> {
  169. let trayIcon = null
  170. if (icon) {
  171. trayIcon = transformImage(icon)
  172. }
  173. return invoke('plugin:tray|set_icon', { rid: this.rid, icon: trayIcon })
  174. }
  175. /**
  176. * Sets a new tray menu.
  177. *
  178. * #### Platform-specific:
  179. *
  180. * - **Linux**: once a menu is set it cannot be removed so `null` has no effect
  181. */
  182. async setMenu(menu: Menu | Submenu | null): Promise<void> {
  183. if (menu) {
  184. // @ts-expect-error we only need the rid and kind
  185. menu = [menu.rid, menu.kind]
  186. }
  187. return invoke('plugin:tray|set_menu', { rid: this.rid, menu })
  188. }
  189. /**
  190. * Sets the tooltip for this tray icon.
  191. *
  192. * ## Platform-specific:
  193. *
  194. * - **Linux:** Unsupported
  195. */
  196. async setTooltip(tooltip: string | null): Promise<void> {
  197. return invoke('plugin:tray|set_tooltip', { rid: this.rid, tooltip })
  198. }
  199. /**
  200. * Sets the tooltip for this tray icon.
  201. *
  202. * ## Platform-specific:
  203. *
  204. * - **Linux:** The title will not be shown unless there is an icon
  205. * as well. The title is useful for numerical and other frequently
  206. * updated information. In general, it shouldn't be shown unless a
  207. * user requests it as it can take up a significant amount of space
  208. * on the user's panel. This may not be shown in all visualizations.
  209. * - **Windows:** Unsupported
  210. */
  211. async setTitle(title: string | null): Promise<void> {
  212. return invoke('plugin:tray|set_title', { rid: this.rid, title })
  213. }
  214. /** Show or hide this tray icon. */
  215. async setVisible(visible: boolean): Promise<void> {
  216. return invoke('plugin:tray|set_visible', { rid: this.rid, visible })
  217. }
  218. /**
  219. * Sets the tray icon temp dir path. **Linux only**.
  220. *
  221. * On Linux, we need to write the icon to the disk and usually it will
  222. * be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
  223. */
  224. async setTempDirPath(path: string | null): Promise<void> {
  225. return invoke('plugin:tray|set_temp_dir_path', { rid: this.rid, path })
  226. }
  227. /** Sets the current icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only** */
  228. async setIconAsTemplate(asTemplate: boolean): Promise<void> {
  229. return invoke('plugin:tray|set_icon_as_template', {
  230. rid: this.rid,
  231. asTemplate
  232. })
  233. }
  234. /** Disable or enable showing the tray menu on left click. **macOS only**. */
  235. async setMenuOnLeftClick(onLeft: boolean): Promise<void> {
  236. return invoke('plugin:tray|set_show_menu_on_left_click', {
  237. rid: this.rid,
  238. onLeft
  239. })
  240. }
  241. }