From c4410daa85616340e911c8243fdaa69e6906fd49 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Fri, 24 May 2024 20:56:32 +0300 Subject: [PATCH] feat(tray): add `enter`, `move` and `leave` events (#9777) * feat(tray): add `enter`, `move` and `leave` events closes #8584 * update api example * check button state [skip ci] * fix enum [skip ci] --------- Co-authored-by: Lucas Nogueira Co-authored-by: Lucas Nogueira --- .changes/tray-icon-event.md | 10 ++ Cargo.lock | 4 +- core/tauri/Cargo.toml | 2 +- core/tauri/src/app.rs | 2 +- core/tauri/src/tray/mod.rs | 186 ++++++++++++++++++++++------- examples/api/src-tauri/Cargo.lock | 15 +-- examples/api/src-tauri/src/tray.rs | 9 +- tooling/api/src/tray.ts | 92 ++++++++++---- 8 files changed, 236 insertions(+), 84 deletions(-) create mode 100644 .changes/tray-icon-event.md diff --git a/.changes/tray-icon-event.md b/.changes/tray-icon-event.md new file mode 100644 index 000000000..eae9fc890 --- /dev/null +++ b/.changes/tray-icon-event.md @@ -0,0 +1,10 @@ +--- +"tauri": "patch:breaking" +"@tauri-apps/api": "patch:breaking" +--- + +This release contains breaking changes to the tray event structure because of newly added events: +- Changed `TrayIconEvent` to be an enum instead of a struct. +- Added `MouseButtonState` and `MouseButton` enums. +- Removed `ClickType` enum and replaced it with `MouseButton` enum. +- Added `MouseButtonState` enum. diff --git a/Cargo.lock b/Cargo.lock index e60c13a73..ab4bf0f2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4077,9 +4077,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.13.5" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39240037d755a1832e752d64f99078c3b0b21c09a71c12405070c75ef4e7cd3c" +checksum = "f79da804c7d1fd82da182b39d4fe5ac1044b08117358b23b41daf88840a3e70d" dependencies = [ "cocoa", "core-graphics", diff --git a/core/tauri/Cargo.toml b/core/tauri/Cargo.toml index ce284b5a5..95a4b7a22 100644 --- a/core/tauri/Cargo.toml +++ b/core/tauri/Cargo.toml @@ -79,7 +79,7 @@ specta = { version = "^2.0.0-rc.9", optional = true, default-features = false, f [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"windows\", target_os = \"macos\"))".dependencies] muda = { version = "0.13.4", default-features = false, features = [ "serde" ] } -tray-icon = { version = "0.13", default-features = false, features = [ "serde" ], optional = true } +tray-icon = { version = "0.14", default-features = false, features = [ "serde" ], optional = true } [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] gtk = { version = "0.18", features = [ "v3_24" ] } diff --git a/core/tauri/src/app.rs b/core/tauri/src/app.rs index fa8cd95dc..2d64e1090 100644 --- a/core/tauri/src/app.rs +++ b/core/tauri/src/app.rs @@ -1947,7 +1947,7 @@ fn on_event_loop_event( } for (id, listener) in &*app_handle.manager.tray.event_listeners.lock().unwrap() { - if e.id == id { + if e.id() == id { if let Some(tray) = app_handle.tray_by_id(id) { listener(&tray, e.clone()); } diff --git a/core/tauri/src/tray/mod.rs b/core/tauri/src/tray/mod.rs index 7f0919ff4..56f7ea646 100644 --- a/core/tauri/src/tray/mod.rs +++ b/core/tauri/src/tray/mod.rs @@ -19,69 +19,165 @@ use serde::Serialize; use std::path::Path; pub use tray_icon::TrayIconId; -/// Describes the click type that triggered this tray icon event. +/// Describes the mouse button state. #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize)] -pub enum ClickType { - /// Left mouse click. - Left, - /// Right mouse click. - Right, - /// Double left mouse click. - Double, +pub enum MouseButtonState { + /// Mouse button pressed. + Up, + /// Mouse button released. + Down, } -impl Default for ClickType { +impl Default for MouseButtonState { + fn default() -> Self { + Self::Up + } +} + +impl From for MouseButtonState { + fn from(value: tray_icon::MouseButtonState) -> Self { + match value { + tray_icon::MouseButtonState::Up => MouseButtonState::Up, + tray_icon::MouseButtonState::Down => MouseButtonState::Down, + } + } +} + +/// Describes which mouse button triggered the event.. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize)] +pub enum MouseButton { + /// Left mouse button. + Left, + /// Right mouse button. + Right, + /// Middle mouse button. + Middle, +} + +impl Default for MouseButton { fn default() -> Self { Self::Left } } -/// Describes a tray event emitted when a tray icon is clicked -/// -/// ## Platform-specific: -/// -/// - **Linux**: Unsupported. The event is not emitted even though the icon is shown, -/// the icon will still show a context menu on right click. -#[derive(Debug, Clone, Default, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TrayIconEvent { - /// Id of the tray icon which triggered this event. - pub id: TrayIconId, - /// Physical Position of the click the triggered this event. - pub position: PhysicalPosition, - /// Position and size of the tray icon - pub icon_rect: Rect, - /// The click type that triggered this event. - pub click_type: ClickType, -} - -impl TrayIconEvent { - /// Returns the id of the tray icon which triggered this event. - pub fn id(&self) -> &TrayIconId { - &self.id +impl From for MouseButton { + fn from(value: tray_icon::MouseButton) -> Self { + match value { + tray_icon::MouseButton::Left => MouseButton::Left, + tray_icon::MouseButton::Right => MouseButton::Right, + tray_icon::MouseButton::Middle => MouseButton::Middle, + } } } -impl From for ClickType { - fn from(value: tray_icon::ClickType) -> Self { - match value { - tray_icon::ClickType::Left => Self::Left, - tray_icon::ClickType::Right => Self::Right, - tray_icon::ClickType::Double => Self::Double, +/// Describes a tray icon event. +/// +/// ## Platform-specific: +/// +/// - **Linux**: Unsupported. The event is not emmited even though the icon is shown +/// and will still show a context menu on right click. +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub enum TrayIconEvent { + /// A click happened on the tray icon. + Click { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + /// Mouse button that triggered this event. + button: MouseButton, + /// Mouse button state when this event was triggered. + button_state: MouseButtonState, + }, + /// The mouse entered the tray icon region. + Enter { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + }, + /// The mouse moved over the tray icon region. + Move { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + }, + /// The mouse left the tray icon region. + Leave { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + }, +} + +impl TrayIconEvent { + /// Get the id of the tray icon that triggered this event. + pub fn id(&self) -> &TrayIconId { + match self { + TrayIconEvent::Click { id, .. } => id, + TrayIconEvent::Enter { id, .. } => id, + TrayIconEvent::Move { id, .. } => id, + TrayIconEvent::Leave { id, .. } => id, } } } impl From for TrayIconEvent { fn from(value: tray_icon::TrayIconEvent) -> Self { - Self { - id: value.id, - position: value.position, - icon_rect: Rect { - position: value.icon_rect.position.into(), - size: value.icon_rect.size.into(), + match value { + tray_icon::TrayIconEvent::Click { + id, + position, + rect, + button, + button_state, + } => TrayIconEvent::Click { + id, + position, + rect: Rect { + position: rect.position.into(), + size: rect.size.into(), + }, + button: button.into(), + button_state: button_state.into(), }, - click_type: value.click_type.into(), + tray_icon::TrayIconEvent::Enter { id, position, rect } => TrayIconEvent::Enter { + id, + position, + rect: Rect { + position: rect.position.into(), + size: rect.size.into(), + }, + }, + tray_icon::TrayIconEvent::Move { id, position, rect } => TrayIconEvent::Move { + id, + position, + rect: Rect { + position: rect.position.into(), + size: rect.size.into(), + }, + }, + tray_icon::TrayIconEvent::Leave { id, position, rect } => TrayIconEvent::Leave { + id, + position, + rect: Rect { + position: rect.position.into(), + size: rect.size.into(), + }, + }, + _ => todo!(), } } } diff --git a/examples/api/src-tauri/Cargo.lock b/examples/api/src-tauri/Cargo.lock index bf733a25a..cc680c3ba 100644 --- a/examples/api/src-tauri/Cargo.lock +++ b/examples/api/src-tauri/Cargo.lock @@ -107,7 +107,6 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-sample", - "tauri-plugin-xcode", "tiny_http", ] @@ -3140,16 +3139,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "tauri-plugin-xcode" -version = "0.0.0" -dependencies = [ - "serde", - "tauri", - "tauri-plugin", - "thiserror", -] - [[package]] name = "tauri-runtime" version = "2.0.0-beta.17" @@ -3521,9 +3510,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.13.5" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39240037d755a1832e752d64f99078c3b0b21c09a71c12405070c75ef4e7cd3c" +checksum = "f79da804c7d1fd82da182b39d4fe5ac1044b08117358b23b41daf88840a3e70d" dependencies = [ "cocoa", "core-graphics", diff --git a/examples/api/src-tauri/src/tray.rs b/examples/api/src-tauri/src/tray.rs index c98804074..af6553b31 100644 --- a/examples/api/src-tauri/src/tray.rs +++ b/examples/api/src-tauri/src/tray.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use tauri::{ menu::{Menu, MenuItem}, - tray::{ClickType, TrayIconBuilder}, + tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, Manager, Runtime, WebviewUrl, }; @@ -108,7 +108,12 @@ pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { _ => {} }) .on_tray_icon_event(|tray, event| { - if event.click_type == ClickType::Left { + if let TrayIconEvent::Click { + button: MouseButton::Left, + button_state: MouseButtonState::Up, + .. + } = event + { let app = tray.app_handle(); if let Some(window) = app.get_webview_window("main") { let _ = window.show(); diff --git a/tooling/api/src/tray.ts b/tooling/api/src/tray.ts index 9cae3a4ec..dd37d29cf 100644 --- a/tooling/api/src/tray.ts +++ b/tooling/api/src/tray.ts @@ -5,16 +5,13 @@ import type { Menu, Submenu } from './menu' import { Channel, invoke, Resource } from './core' import { Image, transformImage } from './image' +import { PhysicalPosition, PhysicalSize } from './dpi' -/** - * Describes a tray event emitted when a tray icon is clicked - * - * #### Platform-specific: - * - * - **Linux**: Unsupported. The event is not emitted even though the icon is shown, - * the icon will still show a context menu on right click. - */ -export interface TrayIconEvent { +export type MouseButtonState = 'Up' | 'Down' +export type MouseButton = 'Left' | 'Right' | 'Middle' + +/** A click happened on the tray icon. */ +export interface TrayIconClickEvent { /** Id of the tray icon which triggered this event. */ id: string /** Physical X Position of the click the triggered this event. */ @@ -22,20 +19,75 @@ export interface TrayIconEvent { /** Physical Y Position of the click the triggered this event. */ y: number /** Position and size of the tray icon. */ - iconRect: { - /** The x-coordinate of the upper-left corner of the rectangle. */ - left: number - /** The y-coordinate of the upper-left corner of the rectangle. */ - top: number - /** The x-coordinate of the lower-right corner of the rectangle. */ - right: number - /** The y-coordinate of the lower-right corner of the rectangle. */ - bottom: number + rect: { + position: PhysicalPosition + size: PhysicalSize } - /** The click type that triggered this event. */ - clickType: 'Left' | 'Right' | 'Double' + /** Mouse button that triggered this event. */ + button: MouseButton + /** Mouse button state when this event was triggered. */ + button_state: MouseButtonState } +/** The mouse entered the tray icon region. */ +export interface TrayIconEnterEvent { + /** Id of the tray icon which triggered this event. */ + id: string + /** Physical X Position of the click the triggered this event. */ + x: number + /** Physical Y Position of the click the triggered this event. */ + y: number + /** Position and size of the tray icon. */ + rect: { + position: PhysicalPosition + size: PhysicalSize + } +} + +/** The mouse moved over the tray icon region. */ +export interface TrayIconMoveEvent { + /** Id of the tray icon which triggered this event. */ + id: string + /** Physical X Position of the click the triggered this event. */ + x: number + /** Physical Y Position of the click the triggered this event. */ + y: number + /** Position and size of the tray icon. */ + rect: { + position: PhysicalPosition + size: PhysicalSize + } +} + +/** The mouse left the tray icon region. */ +export interface TrayIconLeaveEvent { + /** Id of the tray icon which triggered this event. */ + id: string + /** Physical X Position of the click the triggered this event. */ + x: number + /** Physical Y Position of the click the triggered this event. */ + y: number + /** Position and size of the tray icon. */ + rect: { + position: PhysicalPosition + size: PhysicalSize + } +} + +/** + * Describes a tray icon event. + * + * #### Platform-specific: + * + * - **Linux**: Unsupported. The event is not emitted even though the icon is shown, + * the icon will still show a context menu on right click. + */ +export type TrayIconEvent = + | { click: TrayIconClickEvent } + | { enter: TrayIconEnterEvent } + | { move: TrayIconMoveEvent } + | { leave: TrayIconLeaveEvent } + /** * Tray icon types and utilities. *