Browse Source

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>
Amr Bashir 1 year ago
parent
commit
c4410daa85

+ 10 - 0
.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.

+ 2 - 2
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",

+ 1 - 1
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" ] }

+ 1 - 1
core/tauri/src/app.rs

@@ -1947,7 +1947,7 @@ fn on_event_loop_event<R: Runtime>(
           }
 
           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());
               }

+ 134 - 38
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.
+pub enum MouseButtonState {
+  /// Mouse button pressed.
+  Up,
+  /// Mouse button released.
+  Down,
+}
+
+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 click.
+  /// Right mouse button.
   Right,
-  /// Double left mouse click.
-  Double,
+  /// Middle mouse button.
+  Middle,
 }
 
-impl Default for ClickType {
+impl Default for MouseButton {
   fn default() -> Self {
     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 {
+    match value {
+      tray_icon::MouseButton::Left => MouseButton::Left,
+      tray_icon::MouseButton::Right => MouseButton::Right,
+      tray_icon::MouseButton::Middle => MouseButton::Middle,
+    }
+  }
+}
+
+/// 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.
-#[derive(Debug, Clone, Default, Serialize)]
+/// - **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")]
-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,
+#[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 {
-  /// Returns the id of the tray icon which triggered this event.
+  /// Get the id of the tray icon that triggered this event.
   pub fn id(&self) -> &TrayIconId {
-    &self.id
-  }
-}
-
-impl From<tray_icon::ClickType> 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,
+    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 {
   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(),
+      },
+      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(),
+        },
       },
-      click_type: value.click_type.into(),
+      _ => todo!(),
     }
   }
 }

+ 2 - 13
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",

+ 7 - 2
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<R: Runtime>(app: &tauri::AppHandle<R>) -> 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();

+ 72 - 20
tooling/api/src/tray.ts

@@ -5,16 +5,47 @@
 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. */
+  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
+  }
+  /** 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. */
@@ -22,20 +53,41 @@ 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'
 }
 
+/** 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.
  *