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 <lucas@tauri.studio>
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
Amr Bashir 2024-05-24 20:56:32 +03:00 committed by GitHub
parent 276c4b1438
commit c4410daa85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 236 additions and 84 deletions

View File

@ -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.

4
Cargo.lock generated
View File

@ -4077,9 +4077,9 @@ dependencies = [
[[package]] [[package]]
name = "tray-icon" name = "tray-icon"
version = "0.13.5" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39240037d755a1832e752d64f99078c3b0b21c09a71c12405070c75ef4e7cd3c" checksum = "f79da804c7d1fd82da182b39d4fe5ac1044b08117358b23b41daf88840a3e70d"
dependencies = [ dependencies = [
"cocoa", "cocoa",
"core-graphics", "core-graphics",

View File

@ -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] [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" ] } 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] [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" ] } gtk = { version = "0.18", features = [ "v3_24" ] }

View File

@ -1947,7 +1947,7 @@ fn on_event_loop_event<R: Runtime>(
} }
for (id, listener) in &*app_handle.manager.tray.event_listeners.lock().unwrap() { 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) { if let Some(tray) = app_handle.tray_by_id(id) {
listener(&tray, e.clone()); listener(&tray, e.clone());
} }

View File

@ -19,69 +19,165 @@ use serde::Serialize;
use std::path::Path; use std::path::Path;
pub use tray_icon::TrayIconId; 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)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize)]
pub enum ClickType { pub enum MouseButtonState {
/// Left mouse click. /// Mouse button pressed.
Left, Up,
/// Right mouse click. /// Mouse button released.
Right, Down,
/// Double left mouse click.
Double,
} }
impl Default for ClickType { impl Default for MouseButtonState {
fn default() -> Self {
Self::Up
}
}
impl From<tray_icon::MouseButtonState> 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 { fn default() -> Self {
Self::Left Self::Left
} }
} }
/// Describes a tray event emitted when a tray icon is clicked impl From<tray_icon::MouseButton> for MouseButton {
/// fn from(value: tray_icon::MouseButton) -> Self {
/// ## Platform-specific: match value {
/// tray_icon::MouseButton::Left => MouseButton::Left,
/// - **Linux**: Unsupported. The event is not emitted even though the icon is shown, tray_icon::MouseButton::Right => MouseButton::Right,
/// the icon will still show a context menu on right click. tray_icon::MouseButton::Middle => MouseButton::Middle,
#[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<f64>,
/// 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<tray_icon::ClickType> for ClickType { /// Describes a tray icon event.
fn from(value: tray_icon::ClickType) -> Self { ///
match value { /// ## Platform-specific:
tray_icon::ClickType::Left => Self::Left, ///
tray_icon::ClickType::Right => Self::Right, /// - **Linux**: Unsupported. The event is not emmited even though the icon is shown
tray_icon::ClickType::Double => Self::Double, /// 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<f64>,
/// 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<f64>,
/// 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<f64>,
/// 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<f64>,
/// 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<tray_icon::TrayIconEvent> for TrayIconEvent { impl From<tray_icon::TrayIconEvent> for TrayIconEvent {
fn from(value: tray_icon::TrayIconEvent) -> Self { fn from(value: tray_icon::TrayIconEvent) -> Self {
Self { match value {
id: value.id, tray_icon::TrayIconEvent::Click {
position: value.position, id,
icon_rect: Rect { position,
position: value.icon_rect.position.into(), rect,
size: value.icon_rect.size.into(), 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!(),
} }
} }
} }

View File

@ -107,7 +107,6 @@ dependencies = [
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-sample", "tauri-plugin-sample",
"tauri-plugin-xcode",
"tiny_http", "tiny_http",
] ]
@ -3140,16 +3139,6 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "tauri-plugin-xcode"
version = "0.0.0"
dependencies = [
"serde",
"tauri",
"tauri-plugin",
"thiserror",
]
[[package]] [[package]]
name = "tauri-runtime" name = "tauri-runtime"
version = "2.0.0-beta.17" version = "2.0.0-beta.17"
@ -3521,9 +3510,9 @@ dependencies = [
[[package]] [[package]]
name = "tray-icon" name = "tray-icon"
version = "0.13.5" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39240037d755a1832e752d64f99078c3b0b21c09a71c12405070c75ef4e7cd3c" checksum = "f79da804c7d1fd82da182b39d4fe5ac1044b08117358b23b41daf88840a3e70d"
dependencies = [ dependencies = [
"cocoa", "cocoa",
"core-graphics", "core-graphics",

View File

@ -5,7 +5,7 @@
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use tauri::{ use tauri::{
menu::{Menu, MenuItem}, menu::{Menu, MenuItem},
tray::{ClickType, TrayIconBuilder}, tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
Manager, Runtime, WebviewUrl, Manager, Runtime, WebviewUrl,
}; };
@ -108,7 +108,12 @@ pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
_ => {} _ => {}
}) })
.on_tray_icon_event(|tray, event| { .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(); let app = tray.app_handle();
if let Some(window) = app.get_webview_window("main") { if let Some(window) = app.get_webview_window("main") {
let _ = window.show(); let _ = window.show();

View File

@ -5,16 +5,13 @@
import type { Menu, Submenu } from './menu' import type { Menu, Submenu } from './menu'
import { Channel, invoke, Resource } from './core' import { Channel, invoke, Resource } from './core'
import { Image, transformImage } from './image' import { Image, transformImage } from './image'
import { PhysicalPosition, PhysicalSize } from './dpi'
/** export type MouseButtonState = 'Up' | 'Down'
* Describes a tray event emitted when a tray icon is clicked export type MouseButton = 'Left' | 'Right' | 'Middle'
*
* #### Platform-specific: /** A click happened on the tray icon. */
* export interface TrayIconClickEvent {
* - **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 {
/** Id of the tray icon which triggered this event. */ /** Id of the tray icon which triggered this event. */
id: string id: string
/** Physical X Position of the click the triggered this event. */ /** 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. */ /** Physical Y Position of the click the triggered this event. */
y: number y: number
/** Position and size of the tray icon. */ /** Position and size of the tray icon. */
iconRect: { rect: {
/** The x-coordinate of the upper-left corner of the rectangle. */ position: PhysicalPosition
left: number size: PhysicalSize
/** 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
} }
/** The click type that triggered this event. */ /** Mouse button that triggered this event. */
clickType: 'Left' | 'Right' | 'Double' 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. * Tray icon types and utilities.
* *