Files
YMhut-box-C-/参考/NexBox-main/src-tauri/src/tray.rs
T

144 lines
4.9 KiB
Rust

use std::sync::LazyLock;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
use tauri::{
tray::{TrayIcon, TrayIconBuilder},
AppHandle, Emitter, Manager, Runtime, Window,
};
static TRAY_INITIALIZED: AtomicBool = AtomicBool::new(false);
static CLOSE_BEHAVIOR: LazyLock<Mutex<String>> = LazyLock::new(|| Mutex::new(String::from("ask")));
static DONT_ASK_AGAIN: AtomicBool = AtomicBool::new(false);
pub fn init_tray<R: Runtime>(app: &AppHandle<R>) -> Result<TrayIcon<R>, Box<dyn std::error::Error>> {
if TRAY_INITIALIZED.load(Ordering::SeqCst) {
return Err("Tray already initialized".into());
}
let tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.on_tray_icon_event(|tray, event| {
let app = tray.app_handle();
match event {
tauri::tray::TrayIconEvent::Click {
button: tauri::tray::MouseButton::Left,
..
} => {
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.unminimize();
let _ = window.set_focus();
if let Some(widget) = app.get_webview_window("widget") {
let _ = widget.set_always_on_top(false);
let _ = widget.set_focus();
}
let _ = window.set_focus();
}
}
tauri::tray::TrayIconEvent::Click {
button: tauri::tray::MouseButton::Right,
rect,
..
} => {
if let Some(menu_window) = app.get_webview_window("tray-menu") {
let (px, py) = match rect.position {
tauri::Position::Physical(p) => (p.x, p.y),
tauri::Position::Logical(p) => (p.x as i32, p.y as i32),
};
let (sw, _sh) = match rect.size {
tauri::Size::Physical(s) => (s.width as i32, s.height as i32),
tauri::Size::Logical(s) => (s.width as i32, s.height as i32),
};
let x = (px + sw / 2 - 95).max(0);
let y = (py - 140).max(0);
let _ = menu_window.set_position(tauri::Position::Physical(tauri::PhysicalPosition {
x,
y,
}));
let _ = menu_window.set_always_on_top(true);
let _ = menu_window.show();
let _ = menu_window.set_focus();
}
}
_ => {}
}
})
.build(app)?;
TRAY_INITIALIZED.store(true, Ordering::SeqCst);
Ok(tray)
}
#[tauri::command]
pub async fn minimize_to_tray<R: Runtime>(window: Window<R>) -> Result<(), String> {
window.hide().map_err(|e| e.to_string())?;
Ok(())
}
#[tauri::command]
pub async fn show_window<R: Runtime>(window: Window<R>) -> Result<(), String> {
let app = window.app_handle();
window.show().map_err(|e| e.to_string())?;
window.unminimize().map_err(|e| e.to_string())?;
window.set_focus().map_err(|e| e.to_string())?;
if let Some(widget) = app.get_webview_window("widget") {
let _ = widget.set_always_on_top(false);
let _ = widget.set_focus();
}
let _ = window.set_focus();
Ok(())
}
#[tauri::command]
pub fn get_close_behavior() -> String {
CLOSE_BEHAVIOR.lock().unwrap().clone()
}
#[tauri::command]
pub fn set_close_behavior(behavior: String) {
if let Ok(mut b) = CLOSE_BEHAVIOR.lock() {
*b = behavior;
}
}
#[tauri::command]
pub fn get_dont_ask_again() -> bool {
DONT_ASK_AGAIN.load(Ordering::SeqCst)
}
#[tauri::command]
pub fn set_dont_ask_again(value: bool) {
DONT_ASK_AGAIN.store(value, Ordering::SeqCst);
}
#[tauri::command]
pub fn exit_app(app: tauri::AppHandle) {
// 先隐藏所有窗口,避免退出时 WebView2 销毁后短暂露出原生标题栏
for label in &["main", "widget", "tray-menu", "desktop-lyrics", "lyrics-unlock-btn", "vertical-overlay"] {
if let Some(w) = app.get_webview_window(label) {
let _ = w.hide();
}
}
// 给 Windows 消息队列一点时间处理隐藏操作
std::thread::sleep(std::time::Duration::from_millis(50));
app.exit(0);
}
#[tauri::command]
pub fn check_update_and_show(app: AppHandle) {
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.unminimize();
let _ = window.set_focus();
}
let _ = app.emit("check-update", ());
}
pub fn cleanup() {
TRAY_INITIALIZED.store(false, Ordering::SeqCst);
}