diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index 84f646d9..070a049b 100755 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -272,10 +272,11 @@ impl Hotkey { if is_enable_global_hotkey { f(); - } else if let Some(window) = app_handle.get_webview_window("main") { + } else { + use crate::utils::window_manager::WindowManager; // 非轻量模式且未启用全局热键时,只在窗口可见且有焦点的情况下响应热键 - let is_visible = window.is_visible().unwrap_or(false); - let is_focused = window.is_focused().unwrap_or(false); + let is_visible = WindowManager::is_main_window_visible(); + let is_focused = WindowManager::is_main_window_focused(); if is_focused && is_visible { f(); diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 14db740d..52764917 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -10,7 +10,6 @@ use crate::{ lightweight::{entry_lightweight_mode, is_in_lightweight_mode}, mihomo::Rate, }, - resolve, utils::{dirs::find_target_icons, i18n::t, resolve::VERSION}, Type, }; @@ -653,13 +652,14 @@ impl Tray { "system_proxy" => feat::toggle_system_proxy(), "tun_mode" => feat::toggle_tun_mode(None), "main_window" => { + 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(); } - let result = resolve::create_window(true); - log::info!(target: "app", "窗口创建/显示结果: {}", result); + let result = WindowManager::show_main_window(); + log::info!(target: "app", "窗口显示结果: {:?}", result); } _ => {} } @@ -920,12 +920,16 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) { feat::change_clash_mode(mode.into()); } "open_window" => { + use crate::utils::window_manager::WindowManager; + log::info!(target: "app", "托盘菜单点击: 打开窗口"); // 如果在轻量模式中,先退出轻量模式 if crate::module::lightweight::is_in_lightweight_mode() { + log::info!(target: "app", "当前在轻量模式,正在退出"); crate::module::lightweight::exit_lightweight_mode(); } - // 然后创建窗口 - let _ = resolve::create_window(true); + // 使用统一的窗口管理器显示窗口 + let result = WindowManager::show_main_window(); + log::info!(target: "app", "窗口显示结果: {:?}", result); } "system_proxy" => feat::toggle_system_proxy(), "tun_mode" => feat::toggle_tun_mode(None), diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs index d537d806..69314afe 100644 --- a/src-tauri/src/feat/window.rs +++ b/src-tauri/src/feat/window.rs @@ -5,53 +5,29 @@ use crate::{ core::{handle, sysopt, CoreManager}, logging, module::mihomo::MihomoManager, - utils::{logging::Type, resolve}, + utils::logging::Type, }; /// Open or close the dashboard window #[allow(dead_code)] pub fn open_or_close_dashboard() { + use crate::utils::window_manager::WindowManager; + log::info!(target: "app", "Attempting to open/close dashboard"); // 检查是否在轻量模式下 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(); - log::info!(target: "app", "Creating new window after exiting lightweight mode"); - resolve::create_window(true); + let result = WindowManager::show_main_window(); + log::info!(target: "app", "Window operation result: {:?}", result); return; } - if let Some(window) = handle::Handle::global().get_window() { - log::info!(target: "app", "Found existing window"); - - // 如果窗口存在,则切换其显示状态 - match window.is_visible() { - Ok(visible) => { - log::info!(target: "app", "Window visibility status: {}", visible); - - if visible { - log::info!(target: "app", "Attempting to hide window"); - let _ = window.hide(); - } else { - log::info!(target: "app", "Attempting to show and focus window"); - if window.is_minimized().unwrap_or(false) { - let _ = window.unminimize(); - } - let _ = window.show(); - let _ = window.set_focus(); - } - } - Err(e) => { - log::error!(target: "app", "Failed to get window visibility: {:?}", e); - } - } - } else { - log::info!(target: "app", "No existing window found, creating new window"); - resolve::create_window(true); - } + // 使用统一的窗口管理器切换窗口状态 + let result = WindowManager::toggle_main_window(); + 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 529d006b..327dd7d8 100644 --- a/src-tauri/src/module/lightweight.rs +++ b/src-tauri/src/module/lightweight.rs @@ -93,10 +93,18 @@ pub fn disable_auto_light_weight_mode() { } pub 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 window.is_visible().unwrap_or(false) { - let _ = window.hide(); - } if let Some(webview) = window.get_webview_window("main") { let _ = webview.destroy(); } diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs index 6a0a09fb..3f7f6aa0 100644 --- a/src-tauri/src/utils/mod.rs +++ b/src-tauri/src/utils/mod.rs @@ -8,3 +8,4 @@ pub mod network; pub mod resolve; pub mod server; pub mod tmpl; +pub mod window_manager; diff --git a/src-tauri/src/utils/window_manager.rs b/src-tauri/src/utils/window_manager.rs new file mode 100644 index 00000000..d00656f6 --- /dev/null +++ b/src-tauri/src/utils/window_manager.rs @@ -0,0 +1,272 @@ +use crate::{core::handle, logging, utils::logging::Type}; +use tauri::{Manager, WebviewWindow, Wry}; + +#[cfg(target_os = "macos")] +use crate::AppHandleManager; + +/// 窗口操作结果 +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum WindowOperationResult { + /// 窗口已显示并获得焦点 + Shown, + /// 窗口已隐藏 + Hidden, + /// 创建了新窗口 + Created, + /// 操作失败 + Failed, + /// 无需操作 + NoAction, +} + +/// 窗口状态 +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum WindowState { + /// 窗口可见且有焦点 + VisibleFocused, + /// 窗口可见但无焦点 + VisibleUnfocused, + /// 窗口最小化 + Minimized, + /// 窗口隐藏 + Hidden, + /// 窗口不存在 + NotExist, +} + +/// 统一的窗口管理器 +pub struct WindowManager; + +impl WindowManager { + pub fn get_main_window_state() -> WindowState { + if let Some(window) = Self::get_main_window() { + if window.is_minimized().unwrap_or(false) { + WindowState::Minimized + } else if window.is_visible().unwrap_or(false) { + if window.is_focused().unwrap_or(false) { + WindowState::VisibleFocused + } else { + WindowState::VisibleUnfocused + } + } else { + WindowState::Hidden + } + } else { + WindowState::NotExist + } + } + + /// 获取主窗口实例 + pub fn get_main_window() -> Option> { + handle::Handle::global() + .app_handle() + .and_then(|app| app.get_webview_window("main")) + } + + /// 智能显示主窗口 + pub fn show_main_window() -> WindowOperationResult { + logging!(info, Type::Window, true, "开始智能显示主窗口"); + logging!( + debug, + Type::Window, + true, + "{}", + Self::get_window_status_info() + ); + + let current_state = Self::get_main_window_state(); + + match current_state { + WindowState::NotExist => { + logging!(info, Type::Window, true, "窗口不存在,创建新窗口"); + if Self::create_new_window() { + WindowOperationResult::Created + } else { + WindowOperationResult::Failed + } + } + WindowState::VisibleFocused => { + logging!(info, Type::Window, true, "窗口已经可见且有焦点,无需操作"); + WindowOperationResult::NoAction + } + WindowState::VisibleUnfocused | WindowState::Minimized | WindowState::Hidden => { + if let Some(window) = Self::get_main_window() { + Self::activate_window(&window) + } else { + WindowOperationResult::Failed + } + } + } + } + + /// 切换主窗口显示状态(显示/隐藏) + pub fn toggle_main_window() -> WindowOperationResult { + logging!(info, Type::Window, true, "开始切换主窗口显示状态"); + + let current_state = Self::get_main_window_state(); + logging!( + info, + Type::Window, + true, + "当前窗口状态: {:?}", + current_state + ); + + match current_state { + WindowState::NotExist => { + // 窗口不存在,创建新窗口 + if Self::create_new_window() { + WindowOperationResult::Created + } else { + WindowOperationResult::Failed + } + } + WindowState::VisibleFocused => { + // 窗口可见且有焦点,隐藏它 + if let Some(window) = Self::get_main_window() { + if window.hide().is_ok() { + logging!(info, Type::Window, true, "窗口已隐藏"); + WindowOperationResult::Hidden + } else { + WindowOperationResult::Failed + } + } else { + WindowOperationResult::Failed + } + } + WindowState::VisibleUnfocused | WindowState::Minimized | WindowState::Hidden => { + // 窗口存在但不可见或无焦点,激活它 + if let Some(window) = Self::get_main_window() { + Self::activate_window(&window) + } else { + WindowOperationResult::Failed + } + } + } + } + + /// 激活窗口(取消最小化、显示、设置焦点) + fn activate_window(window: &WebviewWindow) -> WindowOperationResult { + logging!(info, Type::Window, true, "开始激活窗口"); + + let mut operations_successful = true; + + // 1. 如果窗口最小化,先取消最小化 + if window.is_minimized().unwrap_or(false) { + logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化"); + if let Err(e) = window.unminimize() { + logging!(warn, Type::Window, true, "取消最小化失败: {}", e); + operations_successful = false; + } + } + + // 2. 显示窗口 + if let Err(e) = window.show() { + logging!(warn, Type::Window, true, "显示窗口失败: {}", e); + operations_successful = false; + } + + // 3. 设置焦点 + if let Err(e) = window.set_focus() { + logging!(warn, Type::Window, true, "设置窗口焦点失败: {}", e); + operations_successful = false; + } + + // 4. 平台特定的激活策略 + #[cfg(target_os = "macos")] + { + logging!(info, Type::Window, true, "应用 macOS 特定的激活策略"); + AppHandleManager::global().set_activation_policy_regular(); + } + + #[cfg(target_os = "windows")] + { + // Windows 尝试额外的激活方法 + if let Err(e) = window.set_always_on_top(true) { + logging!( + debug, + Type::Window, + true, + "设置置顶失败(非关键错误): {}", + e + ); + } + // 立即取消置顶 + if let Err(e) = window.set_always_on_top(false) { + logging!( + debug, + Type::Window, + true, + "取消置顶失败(非关键错误): {}", + e + ); + } + } + + if operations_successful { + logging!(info, Type::Window, true, "窗口激活成功"); + WindowOperationResult::Shown + } else { + logging!(warn, Type::Window, true, "窗口激活部分失败"); + WindowOperationResult::Failed + } + } + + /// 隐藏主窗口 + pub fn hide_main_window() -> WindowOperationResult { + logging!(info, Type::Window, true, "开始隐藏主窗口"); + + if let Some(window) = Self::get_main_window() { + if window.hide().is_ok() { + logging!(info, Type::Window, true, "窗口已隐藏"); + WindowOperationResult::Hidden + } else { + logging!(warn, Type::Window, true, "隐藏窗口失败"); + WindowOperationResult::Failed + } + } else { + logging!(info, Type::Window, true, "窗口不存在,无需隐藏"); + WindowOperationResult::NoAction + } + } + + /// 检查窗口是否可见 + pub fn is_main_window_visible() -> bool { + Self::get_main_window() + .map(|window| window.is_visible().unwrap_or(false)) + .unwrap_or(false) + } + + /// 检查窗口是否有焦点 + pub fn is_main_window_focused() -> bool { + Self::get_main_window() + .map(|window| window.is_focused().unwrap_or(false)) + .unwrap_or(false) + } + + /// 检查窗口是否最小化 + pub fn is_main_window_minimized() -> bool { + Self::get_main_window() + .map(|window| window.is_minimized().unwrap_or(false)) + .unwrap_or(false) + } + + /// 创建新窗口现有的实现 + fn create_new_window() -> bool { + use crate::utils::resolve; + resolve::create_window(true) + } + + /// 获取详细的窗口状态信息 + pub fn get_window_status_info() -> String { + let state = Self::get_main_window_state(); + let is_visible = Self::is_main_window_visible(); + let is_focused = Self::is_main_window_focused(); + let is_minimized = Self::is_main_window_minimized(); + + format!( + "窗口状态: {:?} | 可见: {} | 有焦点: {} | 最小化: {}", + state, is_visible, is_focused, is_minimized + ) + } +}