From dfc1f736af5d2d247a2cd59b986711bb2ea367f1 Mon Sep 17 00:00:00 2001 From: Tunglies Date: Tue, 9 Sep 2025 18:50:24 +0800 Subject: [PATCH] fix: resolve from lightweight cause crash (#4682) * refactor: streamline lightweight mode handling and improve window management * refactor: replace mutex-based window creation lock with atomic operations for improved performance * refactor: remove startup completed event handling and simplify initialization logic * refactor: remove conditional compilation for emit_update_event function * refactor: simplify return statements and clean up commented code in lightweight and window manager modules * refactor: streamline lightweight mode handling by consolidating window management calls * refactor: prevent unnecessary window toggle when exiting lightweight mode * refactor: reorder imports for consistency in lightweight module * refactor: move macOS specific logging_error import for clarity --- UPDATELOG.md | 5 +- src-tauri/src/core/handle.rs | 20 --- src-tauri/src/core/hotkey.rs | 2 +- src-tauri/src/core/timer.rs | 1 - src-tauri/src/core/tray/mod.rs | 35 ++--- src-tauri/src/feat/window.rs | 46 +----- src-tauri/src/module/lightweight.rs | 216 ++++++++++++++++---------- src-tauri/src/utils/resolve/window.rs | 84 +++++----- src-tauri/src/utils/window_manager.rs | 45 +++--- src/pages/_layout.tsx | 11 -- 10 files changed, 209 insertions(+), 256 deletions(-) diff --git a/UPDATELOG.md b/UPDATELOG.md index aeaba943..5face628 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -1,11 +1,8 @@ ## v2.4.3 -### ⚠️ 已知问题 - -- 退出轻量可能程序无响应 - ### 🐞 修复问题 +- 修复轻量模式退出无响应的问题 - macOS intel Mihomo 兼容性 ## v2.4.2 diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs index 6405b6d4..736cb153 100644 --- a/src-tauri/src/core/handle.rs +++ b/src-tauri/src/core/handle.rs @@ -20,7 +20,6 @@ enum FrontendEvent { NoticeMessage { status: String, message: String }, ProfileChanged { current_profile_id: String }, TimerUpdated { profile_index: String }, - StartupCompleted, ProfileUpdateStarted { uid: String }, ProfileUpdateCompleted { uid: String }, } @@ -134,9 +133,6 @@ impl NotificationSystem { FrontendEvent::TimerUpdated { profile_index } => { ("verge://timer-updated", Ok(serde_json::json!(profile_index))) } - FrontendEvent::StartupCompleted => { - ("verge://startup-completed", Ok(serde_json::json!(null))) - } FrontendEvent::ProfileUpdateStarted { uid } => { ("profile-update-started", Ok(serde_json::json!({ "uid": uid }))) } @@ -366,22 +362,6 @@ impl Handle { } } - pub fn notify_startup_completed() { - let handle = Self::global(); - if handle.is_exiting() { - return; - } - - let system_opt = handle.notification_system.read(); - if let Some(system) = system_opt.as_ref() { - system.send_event(FrontendEvent::StartupCompleted); - } else { - log::warn!( - "Notification system not initialized when trying to send StartupCompleted event." - ); - } - } - pub fn notify_profile_update_started(uid: String) { let handle = Self::global(); if handle.is_exiting() { diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index ce6750e7..1a14ffca 100755 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -109,7 +109,7 @@ impl Hotkey { match function { HotkeyFunction::OpenOrCloseDashboard => { AsyncHandler::spawn(async move || { - crate::feat::open_or_close_dashboard_hotkey().await; + crate::feat::open_or_close_dashboard().await; notify_event(app_handle, NotificationEvent::DashboardToggled).await; }); } diff --git a/src-tauri/src/core/timer.rs b/src-tauri/src/core/timer.rs index 8d76705e..e8dc8e98 100644 --- a/src-tauri/src/core/timer.rs +++ b/src-tauri/src/core/timer.rs @@ -434,7 +434,6 @@ impl Timer { /// Emit update events for frontend notification fn emit_update_event(_uid: &str, _is_start: bool) { - #[cfg(any(feature = "verge-dev", feature = "default"))] { if _is_start { super::handle::Handle::notify_profile_update_started(_uid.to_string()); diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index a625a97e..ead412bb 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -4,7 +4,9 @@ use tauri::Emitter; #[cfg(target_os = "macos")] pub mod speed_rate; use crate::ipc::Rate; +use crate::module::lightweight; use crate::process::AsyncHandler; +use crate::utils::window_manager::WindowManager; use crate::{ cmd, config::Config, @@ -532,14 +534,9 @@ impl Tray { feat::toggle_tun_mode(None).await; }), "main_window" => Box::pin(async move { - use crate::utils::window_manager::WindowManager; - log::info!(target: "app", "Tray点击事件: 显示主窗口"); - if crate::module::lightweight::is_in_lightweight_mode() { - log::info!(target: "app", "当前在轻量模式,正在退出轻量模式"); - crate::module::lightweight::exit_lightweight_mode().await; - } - let result = WindowManager::show_main_window().await; - log::info!(target: "app", "窗口显示结果: {result:?}"); + if !lightweight::exit_lightweight_mode().await { + WindowManager::toggle_main_window().await; + }; }), _ => Box::pin(async move {}), }; @@ -971,19 +968,14 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) { feat::change_clash_mode(mode.into()).await; // Await async function } "open_window" => { - use crate::utils::window_manager::WindowManager; log::info!(target: "app", "托盘菜单点击: 打开窗口"); if !should_handle_tray_click() { return; } - - if crate::module::lightweight::is_in_lightweight_mode() { - logging!(info, Type::Lightweight, true, "Exiting Lightweight Mode"); - crate::module::lightweight::exit_lightweight_mode().await; // Await async function - } - let result = WindowManager::show_main_window().await; // Await async function - logging!(info, Type::Window, true, "Show Main Window: {result:?}"); + if !lightweight::exit_lightweight_mode().await { + WindowManager::toggle_main_window().await; + }; } "system_proxy" => { feat::toggle_system_proxy().await; // Await async function @@ -1007,16 +999,7 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) { if !should_handle_tray_click() { return; } - - let was_lightweight = crate::module::lightweight::is_in_lightweight_mode(); - if was_lightweight { - crate::module::lightweight::exit_lightweight_mode().await; // Await async function - use crate::utils::window_manager::WindowManager; - let result = WindowManager::show_main_window().await; // Await async function - logging!(info, Type::Window, true, "Show Main Window: {result:?}"); - } else { - crate::module::lightweight::entry_lightweight_mode().await; // Remove .await as it's not async - } + lightweight::entry_lightweight_mode().await; // Await async function } "quit" => { feat::quit().await; // Await async function diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs index e4391aa8..e9c228f5 100644 --- a/src-tauri/src/feat/window.rs +++ b/src-tauri/src/feat/window.rs @@ -1,57 +1,21 @@ +use crate::utils::window_manager::WindowManager; use crate::{ config::Config, core::{handle, sysopt, CoreManager}, ipc::IpcManager, logging, + module::lightweight, utils::logging::Type, }; /// Open or close the dashboard window -#[allow(dead_code)] pub async fn open_or_close_dashboard() { - open_or_close_dashboard_internal(false).await -} - -/// Open or close the dashboard window (hotkey call, dispatched to main thread) -#[allow(dead_code)] -pub async fn open_or_close_dashboard_hotkey() { - open_or_close_dashboard_internal(true).await + open_or_close_dashboard_internal().await } /// Internal implementation for opening/closing dashboard -async fn open_or_close_dashboard_internal(bypass_debounce: bool) { - use crate::utils::window_manager::WindowManager; - - log::info!(target: "app", "Attempting to open/close dashboard (绕过防抖: {bypass_debounce})"); - - // 热键调用调度到主线程执行,避免 WebView 创建死锁 - if bypass_debounce { - log::info!(target: "app", "热键调用,调度到主线程执行窗口操作"); - - log::info!(target: "app", "主线程中执行热键窗口操作"); - - if crate::module::lightweight::is_in_lightweight_mode() { - log::info!(target: "app", "Currently in lightweight mode, exiting lightweight mode"); - crate::module::lightweight::exit_lightweight_mode().await; - log::info!(target: "app", "Creating new window after exiting lightweight mode"); - let result = WindowManager::show_main_window().await; - log::info!(target: "app", "Window operation result: {result:?}"); - return; - } - - let result = WindowManager::toggle_main_window().await; - log::info!(target: "app", "Window toggle result: {result:?}"); - return; - } - if crate::module::lightweight::is_in_lightweight_mode() { - log::info!(target: "app", "Currently in lightweight mode, exiting lightweight mode"); - crate::module::lightweight::exit_lightweight_mode().await; - log::info!(target: "app", "Creating new window after exiting lightweight mode"); - let result = WindowManager::show_main_window().await; - log::info!(target: "app", "Window operation result: {result:?}"); - return; - } - +async fn open_or_close_dashboard_internal() { + let _ = lightweight::exit_lightweight_mode().await; let result = WindowManager::toggle_main_window().await; log::info!(target: "app", "Window toggle result: {result:?}"); } diff --git a/src-tauri/src/module/lightweight.rs b/src-tauri/src/module/lightweight.rs index 469450a9..f03337a9 100644 --- a/src-tauri/src/module/lightweight.rs +++ b/src-tauri/src/module/lightweight.rs @@ -4,35 +4,86 @@ use crate::{ log_err, logging, process::AsyncHandler, state::proxy::ProxyRequestCache, - utils::{logging::Type, window_manager::WindowManager}, + utils::logging::Type, }; +#[cfg(target_os = "macos")] use crate::logging_error; +use crate::utils::window_manager::WindowManager; use anyhow::{Context, Result}; use delay_timer::prelude::TaskBuilder; -use std::sync::atomic::{AtomicBool, Ordering}; -use tauri::{Listener, Manager}; +use std::sync::atomic::{AtomicU32, AtomicU8, Ordering}; +use tauri::Listener; const LIGHT_WEIGHT_TASK_UID: &str = "light_weight_task"; -// 添加退出轻量模式的锁,防止并发调用 -static EXITING_LIGHTWEIGHT: AtomicBool = AtomicBool::new(false); - -static IS_IN_LIGHTWEIGHT: AtomicBool = AtomicBool::new(false); - -fn inner_set_lightweight_mode(value: bool) -> bool { - if value { - logging!(info, Type::Lightweight, true, "轻量模式已开启"); - } else { - logging!(info, Type::Lightweight, true, "轻量模式已关闭"); - } - IS_IN_LIGHTWEIGHT.store(value, Ordering::SeqCst); - value +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum LightweightState { + Normal = 0, + In = 1, + Exiting = 2, } -fn inner_get_lightweight_mode() -> bool { - IS_IN_LIGHTWEIGHT.load(Ordering::SeqCst) || !WindowManager::is_main_window_exists() +impl From for LightweightState { + fn from(v: u8) -> Self { + match v { + 1 => LightweightState::In, + 2 => LightweightState::Exiting, + _ => LightweightState::Normal, + } + } +} + +impl LightweightState { + fn as_u8(self) -> u8 { + self as u8 + } +} + +static LIGHTWEIGHT_STATE: AtomicU8 = AtomicU8::new(LightweightState::Normal as u8); + +static WINDOW_CLOSE_HANDLER: AtomicU32 = AtomicU32::new(0); +static WEBVIEW_FOCUS_HANDLER: AtomicU32 = AtomicU32::new(0); + +fn set_state(new: LightweightState) { + LIGHTWEIGHT_STATE.store(new.as_u8(), Ordering::Release); + match new { + LightweightState::Normal => { + logging!(info, Type::Lightweight, true, "轻量模式已关闭"); + } + LightweightState::In => { + logging!(info, Type::Lightweight, true, "轻量模式已开启"); + } + LightweightState::Exiting => { + logging!(info, Type::Lightweight, true, "正在退出轻量模式"); + } + } +} + +fn get_state() -> LightweightState { + LIGHTWEIGHT_STATE.load(Ordering::Acquire).into() +} + +// 检查是否处于轻量模式 +pub fn is_in_lightweight_mode() -> bool { + get_state() == LightweightState::In +} + +// 设置轻量模式状态(仅 Normal <-> In) +async fn set_lightweight_mode(value: bool) { + let current = get_state(); + if value && current != LightweightState::In { + set_state(LightweightState::In); + } else if !value && current != LightweightState::Normal { + set_state(LightweightState::Normal); + } + + // 只有在状态可用时才触发托盘更新 + if let Err(e) = Tray::global().update_part().await { + log::warn!("Failed to update tray: {e}"); + } } pub async fn run_once_auto_lightweight() { @@ -85,29 +136,13 @@ pub async fn auto_lightweight_mode_init() -> Result<()> { true, "非静默启动直接挂载自动进入轻量模式监听器!" ); - set_lightweight_mode(true).await; + set_state(LightweightState::Normal); enable_auto_light_weight_mode().await; } Ok(()) } -// 检查是否处于轻量模式 -pub fn is_in_lightweight_mode() -> bool { - IS_IN_LIGHTWEIGHT.load(Ordering::SeqCst) -} - -// 设置轻量模式状态 -pub async fn set_lightweight_mode(value: bool) { - if inner_get_lightweight_mode() != value { - inner_set_lightweight_mode(value); - // 只有在状态可用时才触发托盘更新 - if let Err(e) = Tray::global().update_part().await { - log::warn!("Failed to update tray: {e}"); - } - } -} - pub async fn enable_auto_light_weight_mode() { if let Err(e) = Timer::global().init().await { logging!(error, Type::Lightweight, "Failed to initialize timer: {e}"); @@ -122,67 +157,69 @@ pub fn disable_auto_light_weight_mode() { logging!(info, Type::Lightweight, true, "关闭自动轻量模式"); let _ = cancel_light_weight_timer(); cancel_window_close_listener(); + cancel_webview_focus_listener(); } -pub async fn entry_lightweight_mode() { - use crate::utils::window_manager::WindowManager; - - let result = WindowManager::hide_main_window(); - logging!( - info, - Type::Lightweight, - true, - "轻量模式隐藏窗口结果: {:?}", - result - ); - - if let Some(window) = handle::Handle::global().get_window() { - if let Some(webview) = window.get_webview_window("main") { - let _ = webview.destroy(); - } - #[cfg(target_os = "macos")] - handle::Handle::global().set_activation_policy_accessory(); +pub async fn entry_lightweight_mode() -> bool { + // 尝试从 Normal -> In + if LIGHTWEIGHT_STATE + .compare_exchange( + LightweightState::Normal as u8, + LightweightState::In as u8, + Ordering::Acquire, + Ordering::Relaxed, + ) + .is_err() + { + logging!(info, Type::Lightweight, true, "无需进入轻量模式,跳过调用"); + return false; } + + WindowManager::destroy_main_window(); + set_lightweight_mode(true).await; let _ = cancel_light_weight_timer(); + + // 回到 In + set_state(LightweightState::In); + ProxyRequestCache::global().clean_default_keys(); + true } // 添加从轻量模式恢复的函数 -pub async fn exit_lightweight_mode() { - // 使用原子操作检查是否已经在退出过程中,防止并发调用 - if EXITING_LIGHTWEIGHT - .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) +pub async fn exit_lightweight_mode() -> bool { + // 尝试从 In -> Exiting + if LIGHTWEIGHT_STATE + .compare_exchange( + LightweightState::In as u8, + LightweightState::Exiting as u8, + Ordering::Acquire, + Ordering::Relaxed, + ) .is_err() { logging!( info, Type::Lightweight, true, - "轻量模式退出操作已在进行中,跳过重复调用" + "轻量模式不在退出条件(可能已退出或正在退出),跳过调用" ); - return; + return false; } - // 使用defer确保无论如何都会重置标志 - let _guard = scopeguard::guard((), |_| { - EXITING_LIGHTWEIGHT.store(false, Ordering::SeqCst); - }); - - // 确保当前确实处于轻量模式才执行退出操作 - if !is_in_lightweight_mode() { - logging!(info, Type::Lightweight, true, "当前不在轻量模式,无需退出"); - return; - } + WindowManager::show_main_window().await; + WindowManager::toggle_main_window().await; + println!("what the fuck you want"); set_lightweight_mode(false).await; + let _ = cancel_light_weight_timer(); - // macOS激活策略 - #[cfg(target_os = "macos")] - handle::Handle::global().set_activation_policy_regular(); + // 回到 Normal + set_state(LightweightState::Normal); - // 重置UI就绪状态 - crate::utils::resolve::ui::reset_ui_ready(); + logging!(info, Type::Lightweight, true, "轻量模式退出完成"); + true } #[cfg(target_os = "macos")] @@ -190,7 +227,7 @@ pub async fn add_light_weight_timer() { logging_error!(Type::Lightweight, setup_light_weight_timer().await); } -fn setup_window_close_listener() -> u32 { +fn setup_window_close_listener() { if let Some(window) = handle::Handle::global().get_window() { let handler = window.listen("tauri://close-requested", move |_event| { std::mem::drop(AsyncHandler::spawn(|| async { @@ -205,12 +242,22 @@ fn setup_window_close_listener() -> u32 { "监听到关闭请求,开始轻量模式计时" ); }); - return handler; + + WINDOW_CLOSE_HANDLER.store(handler, Ordering::Release); } - 0 } -fn setup_webview_focus_listener() -> u32 { +fn cancel_window_close_listener() { + if let Some(window) = handle::Handle::global().get_window() { + let handler = WINDOW_CLOSE_HANDLER.swap(0, Ordering::AcqRel); + if handler != 0 { + window.unlisten(handler); + logging!(info, Type::Lightweight, true, "取消了窗口关闭监听"); + } + } +} + +fn setup_webview_focus_listener() { if let Some(window) = handle::Handle::global().get_window() { let handler = window.listen("tauri://focus", move |_event| { log_err!(cancel_light_weight_timer()); @@ -220,15 +267,18 @@ fn setup_webview_focus_listener() -> u32 { "监听到窗口获得焦点,取消轻量模式计时" ); }); - return handler; + + WEBVIEW_FOCUS_HANDLER.store(handler, Ordering::Release); } - 0 } -fn cancel_window_close_listener() { +fn cancel_webview_focus_listener() { if let Some(window) = handle::Handle::global().get_window() { - window.unlisten(setup_window_close_listener()); - logging!(info, Type::Lightweight, true, "取消了窗口关闭监听"); + let handler = WEBVIEW_FOCUS_HANDLER.swap(0, Ordering::AcqRel); + if handler != 0 { + window.unlisten(handler); + logging!(info, Type::Lightweight, true, "取消了窗口焦点监听"); + } } } diff --git a/src-tauri/src/utils/resolve/window.rs b/src-tauri/src/utils/resolve/window.rs index eebaac5e..84a128fe 100644 --- a/src-tauri/src/utils/resolve/window.rs +++ b/src-tauri/src/utils/resolve/window.rs @@ -1,14 +1,12 @@ -use std::time::{Duration, Instant}; +use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; +use std::time::{SystemTime, UNIX_EPOCH}; -use once_cell::sync::OnceCell; -use parking_lot::Mutex; use tauri::{Manager, WebviewWindow}; use crate::{ core::handle, logging, module::lightweight, - process::AsyncHandler, utils::{ logging::Type, resolve::{ @@ -25,11 +23,16 @@ const DEFAULT_HEIGHT: f64 = 700.0; const MINIMAL_WIDTH: f64 = 520.0; const MINIMAL_HEIGHT: f64 = 520.0; -// 窗口创建锁,防止并发创建窗口 -static WINDOW_CREATING: OnceCell> = OnceCell::new(); +// 窗口创建状态,使用原子操作 +static WINDOW_CREATING: AtomicBool = AtomicBool::new(false); +static LAST_CREATION_TIME: AtomicU32 = AtomicU32::new(0); -fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> { - WINDOW_CREATING.get_or_init(|| Mutex::new((false, Instant::now()))) +/// 获取当前时间戳(秒) +fn get_current_timestamp() -> u32 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_secs() as u32 } /// 检查是否已存在窗口,如果存在则显示并返回 true @@ -56,32 +59,46 @@ fn check_existing_window(is_show: bool) -> Option { /// 获取窗口创建锁,防止并发创建 fn acquire_window_creation_lock() -> Result<(), bool> { - let creating_lock = get_window_creating_lock(); - let mut creating = creating_lock.lock(); + let current_time = get_current_timestamp(); + let last_time = LAST_CREATION_TIME.load(Ordering::Acquire); + let elapsed_seconds = current_time.saturating_sub(last_time); - let (is_creating, last_time) = *creating; - let elapsed = last_time.elapsed(); - - if is_creating && elapsed < Duration::from_secs(2) { + // 检查是否正在创建窗口且时间间隔小于2秒 + if WINDOW_CREATING.load(Ordering::Acquire) && elapsed_seconds < 2 { logging!( info, Type::Window, true, - "窗口创建请求被忽略,因为最近创建过 ({:?}ms)", - elapsed.as_millis() + "窗口创建请求被忽略,因为最近创建过 ({}秒前)", + elapsed_seconds ); return Err(false); } - *creating = (true, Instant::now()); - Ok(()) + // 尝试获取创建锁 + match WINDOW_CREATING.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) { + Ok(_) => { + // 成功获取锁,更新时间戳 + LAST_CREATION_TIME.store(current_time, Ordering::Release); + Ok(()) + } + Err(_) => { + // 锁已被占用 + logging!( + info, + Type::Window, + true, + "窗口创建请求被忽略,另一个创建过程正在进行" + ); + Err(false) + } + } } /// 重置窗口创建锁 fn reset_window_creation_lock() { - let creating_lock = get_window_creating_lock(); - let mut creating = creating_lock.lock(); - *creating = (false, Instant::now()); + WINDOW_CREATING.store(false, Ordering::Release); + LAST_CREATION_TIME.store(get_current_timestamp(), Ordering::Release); logging!(debug, Type::Window, true, "窗口创建状态已重置"); } @@ -131,19 +148,10 @@ async fn setup_window_post_creation() { // 先运行轻量模式检测 lightweight::run_once_auto_lightweight().await; - - // 发送启动完成事件,触发前端开始加载 - logging!( - debug, - Type::Window, - true, - "发送 verge://startup-completed 事件" - ); - handle::Handle::notify_startup_completed(); } /// 通过窗口标签处理窗口显示逻辑(减少任务大小的优化版本) -fn handle_window_display_by_label(window_label: String, is_show: bool) { +async fn handle_window_display_by_label(window_label: String, is_show: bool) { if !is_show { logging!( debug, @@ -185,11 +193,7 @@ fn handle_window_display_by_label(window_label: String, is_show: bool) { #[cfg(target_os = "macos")] handle::Handle::global().set_activation_policy_regular(); - let timeout_seconds = if crate::module::lightweight::is_in_lightweight_mode() { - 3 - } else { - 8 - }; + let timeout_seconds = 8; logging!( info, @@ -200,9 +204,7 @@ fn handle_window_display_by_label(window_label: String, is_show: bool) { ); // 异步监控UI状态 - AsyncHandler::spawn(move || async move { - monitor_ui_loading(timeout_seconds).await; - }); + monitor_ui_loading(timeout_seconds).await; logging!(info, Type::Window, true, "窗口显示流程完成"); } @@ -250,8 +252,6 @@ pub async fn create_window(is_show: bool) -> bool { ); if !is_show { - lightweight::set_lightweight_mode(true).await; - handle::Handle::notify_startup_completed(); return false; } @@ -292,7 +292,7 @@ pub async fn create_window(is_show: bool) -> bool { // 异步处理窗口后续设置,只捕获必要的小数据 setup_window_post_creation().await; - handle_window_display_by_label(window_label, is_show); + handle_window_display_by_label(window_label, is_show).await; true } diff --git a/src-tauri/src/utils/window_manager.rs b/src-tauri/src/utils/window_manager.rs index c19b8079..0540f784 100644 --- a/src-tauri/src/utils/window_manager.rs +++ b/src-tauri/src/utils/window_manager.rs @@ -18,6 +18,8 @@ pub enum WindowOperationResult { Hidden, /// 创建了新窗口 Created, + /// 摧毁了窗口 + Destroyed, /// 操作失败 Failed, /// 无需操作 @@ -316,33 +318,6 @@ impl WindowManager { } } - /// 隐藏主窗口 - pub fn hide_main_window() -> WindowOperationResult { - logging!(info, Type::Window, true, "开始隐藏主窗口"); - - match Self::get_main_window() { - Some(window) => match window.hide() { - Ok(_) => { - logging!(info, Type::Window, true, "窗口已隐藏"); - WindowOperationResult::Hidden - } - Err(e) => { - logging!(warn, Type::Window, true, "隐藏窗口失败: {}", e); - WindowOperationResult::Failed - } - }, - None => { - logging!(info, Type::Window, true, "窗口不存在,无需隐藏"); - WindowOperationResult::NoAction - } - } - } - - /// 检查窗口是否存在 - pub fn is_main_window_exists() -> bool { - Self::get_main_window().is_some() - } - /// 检查窗口是否可见 pub fn is_main_window_visible() -> bool { Self::get_main_window() @@ -371,6 +346,22 @@ impl WindowManager { resolve::window::create_window(true).await } + /// 摧毁窗口 + pub fn destroy_main_window() -> WindowOperationResult { + if let Some(window) = Self::get_main_window() { + let _ = window.destroy(); + logging!(info, Type::Window, true, "窗口已摧毁"); + #[cfg(target_os = "macos")] + { + logging!(info, Type::Window, true, "应用 macOS 特定的激活策略"); + handle::Handle::global().set_activation_policy_accessory(); + } + return WindowOperationResult::Destroyed; + } + logging!(warn, Type::Window, true, "窗口摧毁失败"); + WindowOperationResult::Failed + } + /// 获取详细的窗口状态信息 pub fn get_window_status_info() -> String { let state = Self::get_main_window_state(); diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index bf761d81..b9545518 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -379,14 +379,6 @@ const Layout = () => { const setupEventListener = async () => { try { console.log("[Layout] 开始监听启动完成事件"); - const unlisten = await listen("verge://startup-completed", () => { - if (!hasEventTriggered) { - console.log("[Layout] 收到启动完成事件,开始初始化"); - hasEventTriggered = true; - performInitialization(); - } - }); - return unlisten; } catch (err) { console.error("[Layout] 监听启动完成事件失败:", err); return () => {}; @@ -425,14 +417,11 @@ const Layout = () => { } }, 5000); - const unlistenPromise = setupEventListener(); - setTimeout(checkImmediateInitialization, 100); return () => { clearTimeout(backupInitialization); clearTimeout(emergencyInitialization); - unlistenPromise.then((unlisten) => unlisten()); }; }, []);