Skip to content

Commit

Permalink
feat(api/tray): add TrayIcon.getById/removeById (#9155)
Browse files Browse the repository at this point in the history
* feat(api/tray): add `TrayIcon.getById/removeById`

closes #9135

* generate

* add permissions

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
  • Loading branch information
amrbashir and lucasfernog authored Mar 12, 2024
1 parent e227fe0 commit acdd768
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 55 deletions.
5 changes: 5 additions & 0 deletions .changes/api-tray-by-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tauri-apps/api': 'patch:feat'
---

Add `TrayIcon.getById` and `TrayIcon.removeById` static methods.
5 changes: 5 additions & 0 deletions .changes/core-app-tray-remove-tray-apis-removed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tauri': 'patch:breaking'
---

Removed `App/AppHandle::tray` and `App/AppHandle::remove_tray`, use `App/AppHandle::tray_by_id` and `App/AppHandle::remove_tray_by_id` instead. If these APIs were used to access tray icon configured in `tauri.conf.json`, you can use `App/AppHandle::tray_by_id` with ID `main` or the configured value.
2 changes: 2 additions & 0 deletions core/tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
"tray",
&[
("new", false),
("get_by_id", false),
("remove_by_id", false),
("set_icon", false),
("set_menu", false),
("set_tooltip", false),
Expand Down
4 changes: 4 additions & 0 deletions core/tauri/permissions/tray/autogenerated/reference.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
| Permission | Description |
|------|-----|
|`allow-get-by-id`|Enables the get_by_id command without any pre-configured scope.|
|`deny-get-by-id`|Denies the get_by_id command without any pre-configured scope.|
|`allow-new`|Enables the new command without any pre-configured scope.|
|`deny-new`|Denies the new command without any pre-configured scope.|
|`allow-remove-by-id`|Enables the remove_by_id command without any pre-configured scope.|
|`deny-remove-by-id`|Denies the remove_by_id command without any pre-configured scope.|
|`allow-set-icon`|Enables the set_icon command without any pre-configured scope.|
|`deny-set-icon`|Denies the set_icon command without any pre-configured scope.|
|`allow-set-icon-as-template`|Enables the set_icon_as_template command without any pre-configured scope.|
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

58 changes: 6 additions & 52 deletions core/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,13 +509,7 @@ macro_rules! shared_app_impl {
&self,
handler: F,
) {
self
.manager
.menu
.global_event_listeners
.lock()
.unwrap()
.push(Box::new(handler));
self.manager.menu.on_menu_event(handler)
}

/// Registers a global tray icon menu event listener.
Expand All @@ -525,35 +519,7 @@ macro_rules! shared_app_impl {
&self,
handler: F,
) {
self
.manager
.tray
.global_event_listeners
.lock()
.unwrap()
.push(Box::new(handler));
}

/// Gets the first tray icon registered,
/// usually the one configured in the Tauri configuration file.
#[cfg(all(desktop, feature = "tray-icon"))]
#[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "tray-icon"))))]
pub fn tray(&self) -> Option<TrayIcon<R>> {
self.manager.tray.icons.lock().unwrap().first().cloned()
}

/// Removes the first tray icon registered, usually the one configured in
/// tauri config file, from tauri's internal state and returns it.
///
/// Note that dropping the returned icon, will cause the tray icon to disappear.
#[cfg(all(desktop, feature = "tray-icon"))]
#[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "tray-icon"))))]
pub fn remove_tray(&self) -> Option<TrayIcon<R>> {
let mut icons = self.manager.tray.icons.lock().unwrap();
if !icons.is_empty() {
return Some(icons.swap_remove(0));
}
None
self.manager.tray.on_tray_icon_event(handler)
}

/// Gets a tray icon using the provided id.
Expand All @@ -564,33 +530,21 @@ macro_rules! shared_app_impl {
I: ?Sized,
TrayIconId: PartialEq<&'a I>,
{
self
.manager
.tray
.icons
.lock()
.unwrap()
.iter()
.find(|t| t.id() == &id)
.cloned()
self.manager.tray.tray_by_id(id)
}

/// Removes a tray icon using the provided id from tauri's internal state and returns it.
///
/// Note that dropping the returned icon, will cause the tray icon to disappear.
/// Note that dropping the returned icon, may cause the tray icon to disappear
/// if it wasn't cloned somewhere else or referenced by JS.
#[cfg(all(desktop, feature = "tray-icon"))]
#[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "tray-icon"))))]
pub fn remove_tray_by_id<'a, I>(&self, id: &'a I) -> Option<TrayIcon<R>>
where
I: ?Sized,
TrayIconId: PartialEq<&'a I>,
{
let mut icons = self.manager.tray.icons.lock().unwrap();
let idx = icons.iter().position(|t| t.id() == &id);
if let Some(idx) = idx {
return Some(icons.swap_remove(idx));
}
None
self.manager.tray.remove_tray_by_id(id)
}

/// Gets the app's configuration, defined on the `tauri.conf.json` file.
Expand Down
10 changes: 9 additions & 1 deletion core/tauri/src/manager/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
};

use crate::{
menu::{Menu, MenuId},
menu::{Menu, MenuEvent, MenuId},
AppHandle, Runtime, Window,
};

Expand Down Expand Up @@ -87,4 +87,12 @@ impl<R: Runtime> MenuManager<R> {
None
}
}

pub fn on_menu_event<F: Fn(&AppHandle<R>, MenuEvent) + Send + Sync + 'static>(&self, handler: F) {
self
.global_event_listeners
.lock()
.unwrap()
.push(Box::new(handler));
}
}
42 changes: 41 additions & 1 deletion core/tauri/src/manager/tray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{collections::HashMap, fmt, sync::Mutex};
use crate::{
app::GlobalTrayIconEventListener,
image::Image,
tray::{TrayIcon, TrayIconId},
tray::{TrayIcon, TrayIconEvent, TrayIconId},
AppHandle, Runtime,
};

Expand All @@ -28,3 +28,43 @@ impl<R: Runtime> fmt::Debug for TrayManager<R> {
.finish()
}
}

impl<R: Runtime> TrayManager<R> {
pub fn on_tray_icon_event<F: Fn(&AppHandle<R>, TrayIconEvent) + Send + Sync + 'static>(
&self,
handler: F,
) {
self
.global_event_listeners
.lock()
.unwrap()
.push(Box::new(handler));
}

pub fn tray_by_id<'a, I>(&self, id: &'a I) -> Option<TrayIcon<R>>
where
I: ?Sized,
TrayIconId: PartialEq<&'a I>,
{
self
.icons
.lock()
.unwrap()
.iter()
.find(|t| t.id() == &id)
.cloned()
}

pub fn remove_tray_by_id<'a, I>(&self, id: &'a I) -> Option<TrayIcon<R>>
where
I: ?Sized,
TrayIconId: PartialEq<&'a I>,
{
let mut icons = self.icons.lock().unwrap();
let idx = icons.iter().position(|t| t.id() == &id);
if let Some(idx) = idx {
return Some(icons.swap_remove(idx));
}
None
}
}
21 changes: 21 additions & 0 deletions core/tauri/src/tray/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,25 @@ fn new<R: Runtime>(
Ok((rid, id))
}

#[command(root = "crate")]
fn get_by_id<R: Runtime>(app: AppHandle<R>, id: &str) -> crate::Result<Option<ResourceId>> {
let tray = app.tray_by_id(id);
let maybe_rid = tray.map(|tray| {
let mut resources_table = app.resources_table();
resources_table.add(tray)
});
Ok(maybe_rid)
}

#[command(root = "crate")]
fn remove_by_id<R: Runtime>(app: AppHandle<R>, id: &str) -> crate::Result<()> {
app
.remove_tray_by_id(id)
.ok_or_else(|| anyhow::anyhow!("Can't find a tray associated with this id: {id}"))
.map(|_| ())
.map_err(Into::into)
}

#[command(root = "crate")]
fn set_icon<R: Runtime>(
app: AppHandle<R>,
Expand Down Expand Up @@ -196,6 +215,8 @@ pub(crate) fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("tray")
.invoke_handler(crate::generate_handler![
new,
get_by_id,
remove_by_id,
set_icon,
set_menu,
set_tooltip,
Expand Down
17 changes: 17 additions & 0 deletions tooling/api/src/tray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,23 @@ export class TrayIcon extends Resource {
this.id = id
}

/** Gets a tray icon using the provided id. */
static async getById(id: string): Promise<TrayIcon | null> {
return invoke<number>('plugin:tray|get_by_id', { id }).then((rid) =>
rid ? new TrayIcon(rid, id) : null
)
}

/**
* Removes a tray icon using the provided id from tauri's internal state.
*
* Note that this may cause the tray icon to disappear
* if it wasn't cloned somewhere else or referenced by JS.
*/
static async removeById(id: string): Promise<void> {
return invoke('plugin:tray|remove_by_id', { id })
}

/**
* Creates a new {@linkcode TrayIcon}
*
Expand Down

0 comments on commit acdd768

Please sign in to comment.