mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
feat: unify window manager and optimize window show/hide logic
This commit is contained in:
@@ -272,10 +272,11 @@ impl Hotkey {
|
|||||||
|
|
||||||
if is_enable_global_hotkey {
|
if is_enable_global_hotkey {
|
||||||
f();
|
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_visible = WindowManager::is_main_window_visible();
|
||||||
let is_focused = window.is_focused().unwrap_or(false);
|
let is_focused = WindowManager::is_main_window_focused();
|
||||||
|
|
||||||
if is_focused && is_visible {
|
if is_focused && is_visible {
|
||||||
f();
|
f();
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use crate::{
|
|||||||
lightweight::{entry_lightweight_mode, is_in_lightweight_mode},
|
lightweight::{entry_lightweight_mode, is_in_lightweight_mode},
|
||||||
mihomo::Rate,
|
mihomo::Rate,
|
||||||
},
|
},
|
||||||
resolve,
|
|
||||||
utils::{dirs::find_target_icons, i18n::t, resolve::VERSION},
|
utils::{dirs::find_target_icons, i18n::t, resolve::VERSION},
|
||||||
Type,
|
Type,
|
||||||
};
|
};
|
||||||
@@ -653,13 +652,14 @@ impl Tray {
|
|||||||
"system_proxy" => feat::toggle_system_proxy(),
|
"system_proxy" => feat::toggle_system_proxy(),
|
||||||
"tun_mode" => feat::toggle_tun_mode(None),
|
"tun_mode" => feat::toggle_tun_mode(None),
|
||||||
"main_window" => {
|
"main_window" => {
|
||||||
|
use crate::utils::window_manager::WindowManager;
|
||||||
log::info!(target: "app", "Tray点击事件: 显示主窗口");
|
log::info!(target: "app", "Tray点击事件: 显示主窗口");
|
||||||
if crate::module::lightweight::is_in_lightweight_mode() {
|
if crate::module::lightweight::is_in_lightweight_mode() {
|
||||||
log::info!(target: "app", "当前在轻量模式,正在退出轻量模式");
|
log::info!(target: "app", "当前在轻量模式,正在退出轻量模式");
|
||||||
crate::module::lightweight::exit_lightweight_mode();
|
crate::module::lightweight::exit_lightweight_mode();
|
||||||
}
|
}
|
||||||
let result = resolve::create_window(true);
|
let result = WindowManager::show_main_window();
|
||||||
log::info!(target: "app", "窗口创建/显示结果: {}", result);
|
log::info!(target: "app", "窗口显示结果: {:?}", result);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -920,12 +920,16 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
|||||||
feat::change_clash_mode(mode.into());
|
feat::change_clash_mode(mode.into());
|
||||||
}
|
}
|
||||||
"open_window" => {
|
"open_window" => {
|
||||||
|
use crate::utils::window_manager::WindowManager;
|
||||||
|
log::info!(target: "app", "托盘菜单点击: 打开窗口");
|
||||||
// 如果在轻量模式中,先退出轻量模式
|
// 如果在轻量模式中,先退出轻量模式
|
||||||
if crate::module::lightweight::is_in_lightweight_mode() {
|
if crate::module::lightweight::is_in_lightweight_mode() {
|
||||||
|
log::info!(target: "app", "当前在轻量模式,正在退出");
|
||||||
crate::module::lightweight::exit_lightweight_mode();
|
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(),
|
"system_proxy" => feat::toggle_system_proxy(),
|
||||||
"tun_mode" => feat::toggle_tun_mode(None),
|
"tun_mode" => feat::toggle_tun_mode(None),
|
||||||
|
|||||||
@@ -5,53 +5,29 @@ use crate::{
|
|||||||
core::{handle, sysopt, CoreManager},
|
core::{handle, sysopt, CoreManager},
|
||||||
logging,
|
logging,
|
||||||
module::mihomo::MihomoManager,
|
module::mihomo::MihomoManager,
|
||||||
utils::{logging::Type, resolve},
|
utils::logging::Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Open or close the dashboard window
|
/// Open or close the dashboard window
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn open_or_close_dashboard() {
|
pub fn open_or_close_dashboard() {
|
||||||
|
use crate::utils::window_manager::WindowManager;
|
||||||
|
|
||||||
log::info!(target: "app", "Attempting to open/close dashboard");
|
log::info!(target: "app", "Attempting to open/close dashboard");
|
||||||
|
|
||||||
// 检查是否在轻量模式下
|
// 检查是否在轻量模式下
|
||||||
if crate::module::lightweight::is_in_lightweight_mode() {
|
if crate::module::lightweight::is_in_lightweight_mode() {
|
||||||
log::info!(target: "app", "Currently in lightweight mode, exiting lightweight mode");
|
log::info!(target: "app", "Currently in lightweight mode, exiting lightweight mode");
|
||||||
|
|
||||||
crate::module::lightweight::exit_lightweight_mode();
|
crate::module::lightweight::exit_lightweight_mode();
|
||||||
|
|
||||||
log::info!(target: "app", "Creating new window after exiting 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(window) = handle::Handle::global().get_window() {
|
// 使用统一的窗口管理器切换窗口状态
|
||||||
log::info!(target: "app", "Found existing window");
|
let result = WindowManager::toggle_main_window();
|
||||||
|
log::info!(target: "app", "Window toggle result: {:?}", result);
|
||||||
// 如果窗口存在,则切换其显示状态
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 异步优化的应用退出函数
|
/// 异步优化的应用退出函数
|
||||||
|
|||||||
@@ -93,10 +93,18 @@ pub fn disable_auto_light_weight_mode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry_lightweight_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 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") {
|
if let Some(webview) = window.get_webview_window("main") {
|
||||||
let _ = webview.destroy();
|
let _ = webview.destroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ pub mod network;
|
|||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod tmpl;
|
pub mod tmpl;
|
||||||
|
pub mod window_manager;
|
||||||
|
|||||||
272
src-tauri/src/utils/window_manager.rs
Normal file
272
src-tauri/src/utils/window_manager.rs
Normal file
@@ -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<WebviewWindow<Wry>> {
|
||||||
|
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<Wry>) -> 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user