mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-13 05:20:28 +08:00
* refactor: replace handle::Handle::get_window() with WindowManager::get_main_window() in multiple files * refactor: enhance WindowManager to return window state alongside the main window instance * refactor: update useProfiles and ProfilePage to support profile overrides and improve patchProfilesConfig return type * refactor: enhance handle_success to check main window existence before notifying profile changes * refactor: simplify get_main_window_with_state by using pattern matching and improve window state handling * refactor: fix window activation by removing unnecessary reference in activate_existing_main_window * refactor: remove redundant macOS conditional for window_manager import
341 lines
12 KiB
Rust
341 lines
12 KiB
Rust
use crate::{core::handle, utils::resolve::window::build_new_window};
|
|
use clash_verge_limiter::Limiter;
|
|
use clash_verge_logging::{Type, logging};
|
|
use once_cell::sync::Lazy;
|
|
use std::pin::Pin;
|
|
use std::time::Duration;
|
|
use tauri::{Manager as _, WebviewWindow, Wry};
|
|
|
|
/// 窗口操作结果
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum WindowOperationResult {
|
|
/// 窗口已显示并获得焦点
|
|
Shown,
|
|
/// 窗口已隐藏
|
|
Hidden,
|
|
/// 创建了新窗口
|
|
Created,
|
|
/// 摧毁了窗口
|
|
Destroyed,
|
|
/// 操作失败
|
|
Failed,
|
|
/// 无需操作
|
|
NoAction,
|
|
}
|
|
|
|
/// 窗口状态
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum WindowState {
|
|
/// 窗口可见且有焦点
|
|
VisibleFocused,
|
|
/// 窗口可见但无焦点
|
|
VisibleUnfocused,
|
|
/// 窗口最小化
|
|
Minimized,
|
|
/// 窗口隐藏
|
|
Hidden,
|
|
/// 窗口不存在
|
|
NotExist,
|
|
}
|
|
|
|
// 窗口操作防抖机制
|
|
const WINDOW_OPERATION_DEBOUNCE_MS: u64 = 625;
|
|
static WINDOW_OPERATION_LIMITER: Lazy<Limiter> = Lazy::new(|| {
|
|
Limiter::new(
|
|
Duration::from_millis(WINDOW_OPERATION_DEBOUNCE_MS),
|
|
clash_verge_limiter::SystemClock,
|
|
)
|
|
});
|
|
|
|
fn should_handle_window_operation() -> bool {
|
|
let allow = WINDOW_OPERATION_LIMITER.check();
|
|
if !allow {
|
|
logging!(debug, Type::Window, "window operation rate limited");
|
|
}
|
|
allow
|
|
}
|
|
|
|
/// 统一的窗口管理器
|
|
pub struct WindowManager;
|
|
|
|
impl WindowManager {
|
|
pub fn get_main_window_with_state() -> (Option<WebviewWindow<Wry>>, WindowState) {
|
|
let Some(window) = Self::get_main_window() else {
|
|
return (None, WindowState::NotExist);
|
|
};
|
|
|
|
let is_minimized = window.is_minimized().unwrap_or(false);
|
|
let is_visible = window.is_visible().unwrap_or(false);
|
|
let is_focused = window.is_focused().unwrap_or(false);
|
|
|
|
let state = if is_minimized {
|
|
WindowState::Minimized
|
|
} else if !is_visible {
|
|
WindowState::Hidden
|
|
} else if is_focused {
|
|
WindowState::VisibleFocused
|
|
} else {
|
|
WindowState::VisibleUnfocused
|
|
};
|
|
|
|
(Some(window), state)
|
|
}
|
|
|
|
pub fn get_main_window_state() -> WindowState {
|
|
match Self::get_main_window() {
|
|
Some(window) => {
|
|
let is_minimized = window.is_minimized().unwrap_or(false);
|
|
let is_visible = window.is_visible().unwrap_or(false);
|
|
let is_focused = window.is_focused().unwrap_or(false);
|
|
|
|
if is_minimized {
|
|
return WindowState::Minimized;
|
|
}
|
|
|
|
if !is_visible {
|
|
return WindowState::Hidden;
|
|
}
|
|
|
|
if is_focused {
|
|
WindowState::VisibleFocused
|
|
} else {
|
|
WindowState::VisibleUnfocused
|
|
}
|
|
}
|
|
None => WindowState::NotExist,
|
|
}
|
|
}
|
|
|
|
/// 获取主窗口实例
|
|
pub fn get_main_window() -> Option<WebviewWindow<Wry>> {
|
|
let app_handle = handle::Handle::app_handle();
|
|
app_handle.get_webview_window("main")
|
|
}
|
|
|
|
/// 智能显示主窗口
|
|
pub async fn show_main_window() -> WindowOperationResult {
|
|
// 防抖检查
|
|
if !should_handle_window_operation() {
|
|
return WindowOperationResult::NoAction;
|
|
}
|
|
|
|
logging!(info, Type::Window, "开始智能显示主窗口");
|
|
logging!(debug, Type::Window, "{}", Self::get_window_status_info());
|
|
|
|
let current_state = Self::get_main_window_state();
|
|
|
|
match current_state {
|
|
WindowState::NotExist => {
|
|
logging!(info, Type::Window, "窗口不存在,创建新窗口");
|
|
if Self::create_window(true).await {
|
|
logging!(info, Type::Window, "窗口创建成功");
|
|
std::thread::sleep(std::time::Duration::from_millis(50));
|
|
WindowOperationResult::Created
|
|
} else {
|
|
logging!(warn, Type::Window, "窗口创建失败");
|
|
WindowOperationResult::Failed
|
|
}
|
|
}
|
|
WindowState::VisibleFocused => {
|
|
logging!(info, Type::Window, "窗口已经可见且有焦点,无需操作");
|
|
WindowOperationResult::NoAction
|
|
}
|
|
WindowState::VisibleUnfocused | WindowState::Minimized | WindowState::Hidden => {
|
|
let (window, state_after_check) = Self::get_main_window_with_state();
|
|
if state_after_check == WindowState::VisibleFocused {
|
|
logging!(info, Type::Window, "窗口在检查期间已变为可见和有焦点状态");
|
|
return WindowOperationResult::NoAction;
|
|
}
|
|
if let Some(window) = window {
|
|
Self::activate_window(&window)
|
|
} else {
|
|
WindowOperationResult::Failed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 切换主窗口显示状态(显示/隐藏)
|
|
pub async fn toggle_main_window() -> WindowOperationResult {
|
|
if !should_handle_window_operation() {
|
|
return WindowOperationResult::NoAction;
|
|
}
|
|
|
|
let (window, state) = Self::get_main_window_with_state();
|
|
|
|
logging!(debug, Type::Window, "当前状态: {:?}", state);
|
|
|
|
match state {
|
|
WindowState::NotExist => Self::handle_not_exist_toggle().await,
|
|
WindowState::VisibleFocused | WindowState::VisibleUnfocused => Self::hide_main_window(window.as_ref()),
|
|
WindowState::Minimized | WindowState::Hidden => Self::activate_existing_main_window(window.as_ref()),
|
|
}
|
|
}
|
|
|
|
// 窗口不存在时创建新窗口
|
|
async fn handle_not_exist_toggle() -> WindowOperationResult {
|
|
logging!(info, Type::Window, "窗口不存在,将创建新窗口");
|
|
// 由于已经有防抖保护,直接调用内部方法
|
|
if Self::create_window(true).await {
|
|
WindowOperationResult::Created
|
|
} else {
|
|
WindowOperationResult::Failed
|
|
}
|
|
}
|
|
|
|
// 隐藏主窗口
|
|
fn hide_main_window(window: Option<&WebviewWindow<Wry>>) -> WindowOperationResult {
|
|
logging!(info, Type::Window, "窗口可见,将隐藏窗口");
|
|
if let Some(window) = window {
|
|
match window.hide() {
|
|
Ok(_) => {
|
|
logging!(info, Type::Window, "窗口已成功隐藏");
|
|
WindowOperationResult::Hidden
|
|
}
|
|
Err(e) => {
|
|
logging!(warn, Type::Window, "隐藏窗口失败: {}", e);
|
|
WindowOperationResult::Failed
|
|
}
|
|
}
|
|
} else {
|
|
logging!(warn, Type::Window, "无法获取窗口实例");
|
|
WindowOperationResult::Failed
|
|
}
|
|
}
|
|
|
|
// 激活已存在的主窗口
|
|
fn activate_existing_main_window(window: Option<&WebviewWindow<Wry>>) -> WindowOperationResult {
|
|
logging!(info, Type::Window, "窗口存在但被隐藏或最小化,将激活窗口");
|
|
if let Some(window) = window {
|
|
Self::activate_window(window)
|
|
} else {
|
|
logging!(warn, Type::Window, "无法获取窗口实例");
|
|
WindowOperationResult::Failed
|
|
}
|
|
}
|
|
|
|
/// 激活窗口(取消最小化、显示、设置焦点)
|
|
fn activate_window(window: &WebviewWindow<Wry>) -> WindowOperationResult {
|
|
logging!(info, Type::Window, "开始激活窗口");
|
|
|
|
let mut operations_successful = true;
|
|
|
|
// 1. 如果窗口最小化,先取消最小化
|
|
if window.is_minimized().unwrap_or(false) {
|
|
logging!(info, Type::Window, "窗口已最小化,正在取消最小化");
|
|
if let Err(e) = window.unminimize() {
|
|
logging!(warn, Type::Window, "取消最小化失败: {}", e);
|
|
operations_successful = false;
|
|
}
|
|
}
|
|
|
|
// 2. 显示窗口
|
|
if let Err(e) = window.show() {
|
|
logging!(warn, Type::Window, "显示窗口失败: {}", e);
|
|
operations_successful = false;
|
|
}
|
|
|
|
// 3. 设置焦点
|
|
if let Err(e) = window.set_focus() {
|
|
logging!(warn, Type::Window, "设置窗口焦点失败: {}", e);
|
|
operations_successful = false;
|
|
}
|
|
|
|
// 4. 平台特定的激活策略
|
|
#[cfg(target_os = "macos")]
|
|
{
|
|
logging!(info, Type::Window, "应用 macOS 特定的激活策略");
|
|
handle::Handle::global().set_activation_policy_regular();
|
|
}
|
|
|
|
#[cfg(target_os = "windows")]
|
|
{
|
|
// Windows 尝试额外的激活方法
|
|
if let Err(e) = window.set_always_on_top(true) {
|
|
logging!(debug, Type::Window, "设置置顶失败(非关键错误): {}", e);
|
|
}
|
|
// 立即取消置顶
|
|
if let Err(e) = window.set_always_on_top(false) {
|
|
logging!(debug, Type::Window, "取消置顶失败(非关键错误): {}", e);
|
|
}
|
|
}
|
|
|
|
if operations_successful {
|
|
logging!(info, Type::Window, "窗口激活成功");
|
|
WindowOperationResult::Shown
|
|
} else {
|
|
logging!(warn, Type::Window, "窗口激活部分失败");
|
|
WindowOperationResult::Failed
|
|
}
|
|
}
|
|
|
|
/// 检查窗口是否可见
|
|
pub fn is_main_window_visible(window: Option<&WebviewWindow<Wry>>) -> bool {
|
|
window.map(|w| w.is_visible().unwrap_or(false)).unwrap_or(false)
|
|
}
|
|
|
|
/// 检查窗口是否有焦点
|
|
pub fn is_main_window_focused(window: Option<&WebviewWindow<Wry>>) -> bool {
|
|
window.map(|w| w.is_focused().unwrap_or(false)).unwrap_or(false)
|
|
}
|
|
|
|
/// 检查窗口是否最小化
|
|
pub fn is_main_window_minimized(window: Option<&WebviewWindow<Wry>>) -> bool {
|
|
window.map(|w| w.is_minimized().unwrap_or(false)).unwrap_or(false)
|
|
}
|
|
|
|
/// 创建新窗口,防抖避免重复调用
|
|
pub fn create_window(is_show: bool) -> Pin<Box<dyn Future<Output = bool> + Send>> {
|
|
Box::pin(async move {
|
|
logging!(info, Type::Window, "开始创建/显示主窗口, is_show={}", is_show);
|
|
|
|
if !is_show {
|
|
return false;
|
|
}
|
|
|
|
let window = match build_new_window().await {
|
|
Ok(window) => {
|
|
logging!(info, Type::Window, "新窗口创建成功");
|
|
window
|
|
}
|
|
Err(e) => {
|
|
logging!(error, Type::Window, "新窗口创建失败: {}", e);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// 直接激活刚创建的窗口,避免因防抖导致首次显示被跳过
|
|
if WindowOperationResult::Failed == Self::activate_window(&window) {
|
|
return false;
|
|
}
|
|
|
|
true
|
|
})
|
|
}
|
|
|
|
/// 摧毁窗口
|
|
pub fn destroy_main_window() -> WindowOperationResult {
|
|
if let Some(window) = Self::get_main_window() {
|
|
let _ = window.destroy();
|
|
logging!(info, Type::Window, "窗口已摧毁");
|
|
#[cfg(target_os = "macos")]
|
|
{
|
|
logging!(info, Type::Window, "应用 macOS 特定的激活策略");
|
|
handle::Handle::global().set_activation_policy_accessory();
|
|
}
|
|
return WindowOperationResult::Destroyed;
|
|
}
|
|
WindowOperationResult::Failed
|
|
}
|
|
|
|
/// 获取详细的窗口状态信息
|
|
fn get_window_status_info() -> String {
|
|
let (window, state) = Self::get_main_window_with_state();
|
|
let is_visible = Self::is_main_window_visible(window.as_ref());
|
|
let is_focused = Self::is_main_window_focused(window.as_ref());
|
|
let is_minimized = Self::is_main_window_minimized(window.as_ref());
|
|
|
|
format!("窗口状态: {state:?} | 可见: {is_visible} | 有焦点: {is_focused} | 最小化: {is_minimized}")
|
|
}
|
|
}
|