mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
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
This commit is contained in:
@@ -1,11 +1,8 @@
|
|||||||
## v2.4.3
|
## v2.4.3
|
||||||
|
|
||||||
### ⚠️ 已知问题
|
|
||||||
|
|
||||||
- 退出轻量可能程序无响应
|
|
||||||
|
|
||||||
### 🐞 修复问题
|
### 🐞 修复问题
|
||||||
|
|
||||||
|
- 修复轻量模式退出无响应的问题
|
||||||
- macOS intel Mihomo 兼容性
|
- macOS intel Mihomo 兼容性
|
||||||
|
|
||||||
## v2.4.2
|
## v2.4.2
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ enum FrontendEvent {
|
|||||||
NoticeMessage { status: String, message: String },
|
NoticeMessage { status: String, message: String },
|
||||||
ProfileChanged { current_profile_id: String },
|
ProfileChanged { current_profile_id: String },
|
||||||
TimerUpdated { profile_index: String },
|
TimerUpdated { profile_index: String },
|
||||||
StartupCompleted,
|
|
||||||
ProfileUpdateStarted { uid: String },
|
ProfileUpdateStarted { uid: String },
|
||||||
ProfileUpdateCompleted { uid: String },
|
ProfileUpdateCompleted { uid: String },
|
||||||
}
|
}
|
||||||
@@ -134,9 +133,6 @@ impl NotificationSystem {
|
|||||||
FrontendEvent::TimerUpdated { profile_index } => {
|
FrontendEvent::TimerUpdated { profile_index } => {
|
||||||
("verge://timer-updated", Ok(serde_json::json!(profile_index)))
|
("verge://timer-updated", Ok(serde_json::json!(profile_index)))
|
||||||
}
|
}
|
||||||
FrontendEvent::StartupCompleted => {
|
|
||||||
("verge://startup-completed", Ok(serde_json::json!(null)))
|
|
||||||
}
|
|
||||||
FrontendEvent::ProfileUpdateStarted { uid } => {
|
FrontendEvent::ProfileUpdateStarted { uid } => {
|
||||||
("profile-update-started", Ok(serde_json::json!({ "uid": 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) {
|
pub fn notify_profile_update_started(uid: String) {
|
||||||
let handle = Self::global();
|
let handle = Self::global();
|
||||||
if handle.is_exiting() {
|
if handle.is_exiting() {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ impl Hotkey {
|
|||||||
match function {
|
match function {
|
||||||
HotkeyFunction::OpenOrCloseDashboard => {
|
HotkeyFunction::OpenOrCloseDashboard => {
|
||||||
AsyncHandler::spawn(async move || {
|
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;
|
notify_event(app_handle, NotificationEvent::DashboardToggled).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -434,7 +434,6 @@ impl Timer {
|
|||||||
|
|
||||||
/// Emit update events for frontend notification
|
/// Emit update events for frontend notification
|
||||||
fn emit_update_event(_uid: &str, _is_start: bool) {
|
fn emit_update_event(_uid: &str, _is_start: bool) {
|
||||||
#[cfg(any(feature = "verge-dev", feature = "default"))]
|
|
||||||
{
|
{
|
||||||
if _is_start {
|
if _is_start {
|
||||||
super::handle::Handle::notify_profile_update_started(_uid.to_string());
|
super::handle::Handle::notify_profile_update_started(_uid.to_string());
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ use tauri::Emitter;
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub mod speed_rate;
|
pub mod speed_rate;
|
||||||
use crate::ipc::Rate;
|
use crate::ipc::Rate;
|
||||||
|
use crate::module::lightweight;
|
||||||
use crate::process::AsyncHandler;
|
use crate::process::AsyncHandler;
|
||||||
|
use crate::utils::window_manager::WindowManager;
|
||||||
use crate::{
|
use crate::{
|
||||||
cmd,
|
cmd,
|
||||||
config::Config,
|
config::Config,
|
||||||
@@ -532,14 +534,9 @@ impl Tray {
|
|||||||
feat::toggle_tun_mode(None).await;
|
feat::toggle_tun_mode(None).await;
|
||||||
}),
|
}),
|
||||||
"main_window" => Box::pin(async move {
|
"main_window" => Box::pin(async move {
|
||||||
use crate::utils::window_manager::WindowManager;
|
if !lightweight::exit_lightweight_mode().await {
|
||||||
log::info!(target: "app", "Tray点击事件: 显示主窗口");
|
WindowManager::toggle_main_window().await;
|
||||||
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:?}");
|
|
||||||
}),
|
}),
|
||||||
_ => Box::pin(async move {}),
|
_ => 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
|
feat::change_clash_mode(mode.into()).await; // Await async function
|
||||||
}
|
}
|
||||||
"open_window" => {
|
"open_window" => {
|
||||||
use crate::utils::window_manager::WindowManager;
|
|
||||||
log::info!(target: "app", "托盘菜单点击: 打开窗口");
|
log::info!(target: "app", "托盘菜单点击: 打开窗口");
|
||||||
|
|
||||||
if !should_handle_tray_click() {
|
if !should_handle_tray_click() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if !lightweight::exit_lightweight_mode().await {
|
||||||
if crate::module::lightweight::is_in_lightweight_mode() {
|
WindowManager::toggle_main_window().await;
|
||||||
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:?}");
|
|
||||||
}
|
}
|
||||||
"system_proxy" => {
|
"system_proxy" => {
|
||||||
feat::toggle_system_proxy().await; // Await async function
|
feat::toggle_system_proxy().await; // Await async function
|
||||||
@@ -1007,16 +999,7 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
|||||||
if !should_handle_tray_click() {
|
if !should_handle_tray_click() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
lightweight::entry_lightweight_mode().await; // Await async function
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"quit" => {
|
"quit" => {
|
||||||
feat::quit().await; // Await async function
|
feat::quit().await; // Await async function
|
||||||
|
|||||||
@@ -1,57 +1,21 @@
|
|||||||
|
use crate::utils::window_manager::WindowManager;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
core::{handle, sysopt, CoreManager},
|
core::{handle, sysopt, CoreManager},
|
||||||
ipc::IpcManager,
|
ipc::IpcManager,
|
||||||
logging,
|
logging,
|
||||||
|
module::lightweight,
|
||||||
utils::logging::Type,
|
utils::logging::Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Open or close the dashboard window
|
/// Open or close the dashboard window
|
||||||
#[allow(dead_code)]
|
|
||||||
pub async fn open_or_close_dashboard() {
|
pub async fn open_or_close_dashboard() {
|
||||||
open_or_close_dashboard_internal(false).await
|
open_or_close_dashboard_internal().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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal implementation for opening/closing dashboard
|
/// Internal implementation for opening/closing dashboard
|
||||||
async fn open_or_close_dashboard_internal(bypass_debounce: bool) {
|
async fn open_or_close_dashboard_internal() {
|
||||||
use crate::utils::window_manager::WindowManager;
|
let _ = lightweight::exit_lightweight_mode().await;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = WindowManager::toggle_main_window().await;
|
let result = WindowManager::toggle_main_window().await;
|
||||||
log::info!(target: "app", "Window toggle result: {result:?}");
|
log::info!(target: "app", "Window toggle result: {result:?}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,35 +4,86 @@ use crate::{
|
|||||||
log_err, logging,
|
log_err, logging,
|
||||||
process::AsyncHandler,
|
process::AsyncHandler,
|
||||||
state::proxy::ProxyRequestCache,
|
state::proxy::ProxyRequestCache,
|
||||||
utils::{logging::Type, window_manager::WindowManager},
|
utils::logging::Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
use crate::logging_error;
|
use crate::logging_error;
|
||||||
|
|
||||||
|
use crate::utils::window_manager::WindowManager;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use delay_timer::prelude::TaskBuilder;
|
use delay_timer::prelude::TaskBuilder;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicU32, AtomicU8, Ordering};
|
||||||
use tauri::{Listener, Manager};
|
use tauri::Listener;
|
||||||
|
|
||||||
const LIGHT_WEIGHT_TASK_UID: &str = "light_weight_task";
|
const LIGHT_WEIGHT_TASK_UID: &str = "light_weight_task";
|
||||||
|
|
||||||
// 添加退出轻量模式的锁,防止并发调用
|
#[repr(u8)]
|
||||||
static EXITING_LIGHTWEIGHT: AtomicBool = AtomicBool::new(false);
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum LightweightState {
|
||||||
static IS_IN_LIGHTWEIGHT: AtomicBool = AtomicBool::new(false);
|
Normal = 0,
|
||||||
|
In = 1,
|
||||||
fn inner_set_lightweight_mode(value: bool) -> bool {
|
Exiting = 2,
|
||||||
if value {
|
|
||||||
logging!(info, Type::Lightweight, true, "轻量模式已开启");
|
|
||||||
} else {
|
|
||||||
logging!(info, Type::Lightweight, true, "轻量模式已关闭");
|
|
||||||
}
|
|
||||||
IS_IN_LIGHTWEIGHT.store(value, Ordering::SeqCst);
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_get_lightweight_mode() -> bool {
|
impl From<u8> for LightweightState {
|
||||||
IS_IN_LIGHTWEIGHT.load(Ordering::SeqCst) || !WindowManager::is_main_window_exists()
|
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() {
|
pub async fn run_once_auto_lightweight() {
|
||||||
@@ -85,29 +136,13 @@ pub async fn auto_lightweight_mode_init() -> Result<()> {
|
|||||||
true,
|
true,
|
||||||
"非静默启动直接挂载自动进入轻量模式监听器!"
|
"非静默启动直接挂载自动进入轻量模式监听器!"
|
||||||
);
|
);
|
||||||
set_lightweight_mode(true).await;
|
set_state(LightweightState::Normal);
|
||||||
enable_auto_light_weight_mode().await;
|
enable_auto_light_weight_mode().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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() {
|
pub async fn enable_auto_light_weight_mode() {
|
||||||
if let Err(e) = Timer::global().init().await {
|
if let Err(e) = Timer::global().init().await {
|
||||||
logging!(error, Type::Lightweight, "Failed to initialize timer: {e}");
|
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, "关闭自动轻量模式");
|
logging!(info, Type::Lightweight, true, "关闭自动轻量模式");
|
||||||
let _ = cancel_light_weight_timer();
|
let _ = cancel_light_weight_timer();
|
||||||
cancel_window_close_listener();
|
cancel_window_close_listener();
|
||||||
|
cancel_webview_focus_listener();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn entry_lightweight_mode() {
|
pub async fn entry_lightweight_mode() -> bool {
|
||||||
use crate::utils::window_manager::WindowManager;
|
// 尝试从 Normal -> In
|
||||||
|
if LIGHTWEIGHT_STATE
|
||||||
let result = WindowManager::hide_main_window();
|
.compare_exchange(
|
||||||
logging!(
|
LightweightState::Normal as u8,
|
||||||
info,
|
LightweightState::In as u8,
|
||||||
Type::Lightweight,
|
Ordering::Acquire,
|
||||||
true,
|
Ordering::Relaxed,
|
||||||
"轻量模式隐藏窗口结果: {:?}",
|
)
|
||||||
result
|
.is_err()
|
||||||
);
|
{
|
||||||
|
logging!(info, Type::Lightweight, true, "无需进入轻量模式,跳过调用");
|
||||||
if let Some(window) = handle::Handle::global().get_window() {
|
return false;
|
||||||
if let Some(webview) = window.get_webview_window("main") {
|
|
||||||
let _ = webview.destroy();
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
handle::Handle::global().set_activation_policy_accessory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WindowManager::destroy_main_window();
|
||||||
|
|
||||||
set_lightweight_mode(true).await;
|
set_lightweight_mode(true).await;
|
||||||
let _ = cancel_light_weight_timer();
|
let _ = cancel_light_weight_timer();
|
||||||
|
|
||||||
|
// 回到 In
|
||||||
|
set_state(LightweightState::In);
|
||||||
|
|
||||||
ProxyRequestCache::global().clean_default_keys();
|
ProxyRequestCache::global().clean_default_keys();
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加从轻量模式恢复的函数
|
// 添加从轻量模式恢复的函数
|
||||||
pub async fn exit_lightweight_mode() {
|
pub async fn exit_lightweight_mode() -> bool {
|
||||||
// 使用原子操作检查是否已经在退出过程中,防止并发调用
|
// 尝试从 In -> Exiting
|
||||||
if EXITING_LIGHTWEIGHT
|
if LIGHTWEIGHT_STATE
|
||||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
.compare_exchange(
|
||||||
|
LightweightState::In as u8,
|
||||||
|
LightweightState::Exiting as u8,
|
||||||
|
Ordering::Acquire,
|
||||||
|
Ordering::Relaxed,
|
||||||
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::Lightweight,
|
Type::Lightweight,
|
||||||
true,
|
true,
|
||||||
"轻量模式退出操作已在进行中,跳过重复调用"
|
"轻量模式不在退出条件(可能已退出或正在退出),跳过调用"
|
||||||
);
|
);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用defer确保无论如何都会重置标志
|
WindowManager::show_main_window().await;
|
||||||
let _guard = scopeguard::guard((), |_| {
|
WindowManager::toggle_main_window().await;
|
||||||
EXITING_LIGHTWEIGHT.store(false, Ordering::SeqCst);
|
println!("what the fuck you want");
|
||||||
});
|
|
||||||
|
|
||||||
// 确保当前确实处于轻量模式才执行退出操作
|
|
||||||
if !is_in_lightweight_mode() {
|
|
||||||
logging!(info, Type::Lightweight, true, "当前不在轻量模式,无需退出");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_lightweight_mode(false).await;
|
set_lightweight_mode(false).await;
|
||||||
|
let _ = cancel_light_weight_timer();
|
||||||
|
|
||||||
// macOS激活策略
|
// 回到 Normal
|
||||||
#[cfg(target_os = "macos")]
|
set_state(LightweightState::Normal);
|
||||||
handle::Handle::global().set_activation_policy_regular();
|
|
||||||
|
|
||||||
// 重置UI就绪状态
|
logging!(info, Type::Lightweight, true, "轻量模式退出完成");
|
||||||
crate::utils::resolve::ui::reset_ui_ready();
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@@ -190,7 +227,7 @@ pub async fn add_light_weight_timer() {
|
|||||||
logging_error!(Type::Lightweight, setup_light_weight_timer().await);
|
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() {
|
if let Some(window) = handle::Handle::global().get_window() {
|
||||||
let handler = window.listen("tauri://close-requested", move |_event| {
|
let handler = window.listen("tauri://close-requested", move |_event| {
|
||||||
std::mem::drop(AsyncHandler::spawn(|| async {
|
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() {
|
if let Some(window) = handle::Handle::global().get_window() {
|
||||||
let handler = window.listen("tauri://focus", move |_event| {
|
let handler = window.listen("tauri://focus", move |_event| {
|
||||||
log_err!(cancel_light_weight_timer());
|
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() {
|
if let Some(window) = handle::Handle::global().get_window() {
|
||||||
window.unlisten(setup_window_close_listener());
|
let handler = WEBVIEW_FOCUS_HANDLER.swap(0, Ordering::AcqRel);
|
||||||
logging!(info, Type::Lightweight, true, "取消了窗口关闭监听");
|
if handler != 0 {
|
||||||
|
window.unlisten(handler);
|
||||||
|
logging!(info, Type::Lightweight, true, "取消了窗口焦点监听");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 tauri::{Manager, WebviewWindow};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::handle,
|
core::handle,
|
||||||
logging,
|
logging,
|
||||||
module::lightweight,
|
module::lightweight,
|
||||||
process::AsyncHandler,
|
|
||||||
utils::{
|
utils::{
|
||||||
logging::Type,
|
logging::Type,
|
||||||
resolve::{
|
resolve::{
|
||||||
@@ -25,11 +23,16 @@ const DEFAULT_HEIGHT: f64 = 700.0;
|
|||||||
const MINIMAL_WIDTH: f64 = 520.0;
|
const MINIMAL_WIDTH: f64 = 520.0;
|
||||||
const MINIMAL_HEIGHT: f64 = 520.0;
|
const MINIMAL_HEIGHT: f64 = 520.0;
|
||||||
|
|
||||||
// 窗口创建锁,防止并发创建窗口
|
// 窗口创建状态,使用原子操作
|
||||||
static WINDOW_CREATING: OnceCell<Mutex<(bool, Instant)>> = 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
|
/// 检查是否已存在窗口,如果存在则显示并返回 true
|
||||||
@@ -56,32 +59,46 @@ fn check_existing_window(is_show: bool) -> Option<bool> {
|
|||||||
|
|
||||||
/// 获取窗口创建锁,防止并发创建
|
/// 获取窗口创建锁,防止并发创建
|
||||||
fn acquire_window_creation_lock() -> Result<(), bool> {
|
fn acquire_window_creation_lock() -> Result<(), bool> {
|
||||||
let creating_lock = get_window_creating_lock();
|
let current_time = get_current_timestamp();
|
||||||
let mut creating = creating_lock.lock();
|
let last_time = LAST_CREATION_TIME.load(Ordering::Acquire);
|
||||||
|
let elapsed_seconds = current_time.saturating_sub(last_time);
|
||||||
|
|
||||||
let (is_creating, last_time) = *creating;
|
// 检查是否正在创建窗口且时间间隔小于2秒
|
||||||
let elapsed = last_time.elapsed();
|
if WINDOW_CREATING.load(Ordering::Acquire) && elapsed_seconds < 2 {
|
||||||
|
|
||||||
if is_creating && elapsed < Duration::from_secs(2) {
|
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::Window,
|
Type::Window,
|
||||||
true,
|
true,
|
||||||
"窗口创建请求被忽略,因为最近创建过 ({:?}ms)",
|
"窗口创建请求被忽略,因为最近创建过 ({}秒前)",
|
||||||
elapsed.as_millis()
|
elapsed_seconds
|
||||||
);
|
);
|
||||||
return Err(false);
|
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() {
|
fn reset_window_creation_lock() {
|
||||||
let creating_lock = get_window_creating_lock();
|
WINDOW_CREATING.store(false, Ordering::Release);
|
||||||
let mut creating = creating_lock.lock();
|
LAST_CREATION_TIME.store(get_current_timestamp(), Ordering::Release);
|
||||||
*creating = (false, Instant::now());
|
|
||||||
logging!(debug, Type::Window, true, "窗口创建状态已重置");
|
logging!(debug, Type::Window, true, "窗口创建状态已重置");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,19 +148,10 @@ async fn setup_window_post_creation() {
|
|||||||
|
|
||||||
// 先运行轻量模式检测
|
// 先运行轻量模式检测
|
||||||
lightweight::run_once_auto_lightweight().await;
|
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 {
|
if !is_show {
|
||||||
logging!(
|
logging!(
|
||||||
debug,
|
debug,
|
||||||
@@ -185,11 +193,7 @@ fn handle_window_display_by_label(window_label: String, is_show: bool) {
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
handle::Handle::global().set_activation_policy_regular();
|
handle::Handle::global().set_activation_policy_regular();
|
||||||
|
|
||||||
let timeout_seconds = if crate::module::lightweight::is_in_lightweight_mode() {
|
let timeout_seconds = 8;
|
||||||
3
|
|
||||||
} else {
|
|
||||||
8
|
|
||||||
};
|
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
@@ -200,9 +204,7 @@ fn handle_window_display_by_label(window_label: String, is_show: bool) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 异步监控UI状态
|
// 异步监控UI状态
|
||||||
AsyncHandler::spawn(move || async move {
|
monitor_ui_loading(timeout_seconds).await;
|
||||||
monitor_ui_loading(timeout_seconds).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
logging!(info, Type::Window, true, "窗口显示流程完成");
|
logging!(info, Type::Window, true, "窗口显示流程完成");
|
||||||
}
|
}
|
||||||
@@ -250,8 +252,6 @@ pub async fn create_window(is_show: bool) -> bool {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if !is_show {
|
if !is_show {
|
||||||
lightweight::set_lightweight_mode(true).await;
|
|
||||||
handle::Handle::notify_startup_completed();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@ pub async fn create_window(is_show: bool) -> bool {
|
|||||||
|
|
||||||
// 异步处理窗口后续设置,只捕获必要的小数据
|
// 异步处理窗口后续设置,只捕获必要的小数据
|
||||||
setup_window_post_creation().await;
|
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
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ pub enum WindowOperationResult {
|
|||||||
Hidden,
|
Hidden,
|
||||||
/// 创建了新窗口
|
/// 创建了新窗口
|
||||||
Created,
|
Created,
|
||||||
|
/// 摧毁了窗口
|
||||||
|
Destroyed,
|
||||||
/// 操作失败
|
/// 操作失败
|
||||||
Failed,
|
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 {
|
pub fn is_main_window_visible() -> bool {
|
||||||
Self::get_main_window()
|
Self::get_main_window()
|
||||||
@@ -371,6 +346,22 @@ impl WindowManager {
|
|||||||
resolve::window::create_window(true).await
|
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 {
|
pub fn get_window_status_info() -> String {
|
||||||
let state = Self::get_main_window_state();
|
let state = Self::get_main_window_state();
|
||||||
|
|||||||
@@ -379,14 +379,6 @@ const Layout = () => {
|
|||||||
const setupEventListener = async () => {
|
const setupEventListener = async () => {
|
||||||
try {
|
try {
|
||||||
console.log("[Layout] 开始监听启动完成事件");
|
console.log("[Layout] 开始监听启动完成事件");
|
||||||
const unlisten = await listen("verge://startup-completed", () => {
|
|
||||||
if (!hasEventTriggered) {
|
|
||||||
console.log("[Layout] 收到启动完成事件,开始初始化");
|
|
||||||
hasEventTriggered = true;
|
|
||||||
performInitialization();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return unlisten;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("[Layout] 监听启动完成事件失败:", err);
|
console.error("[Layout] 监听启动完成事件失败:", err);
|
||||||
return () => {};
|
return () => {};
|
||||||
@@ -425,14 +417,11 @@ const Layout = () => {
|
|||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
const unlistenPromise = setupEventListener();
|
|
||||||
|
|
||||||
setTimeout(checkImmediateInitialization, 100);
|
setTimeout(checkImmediateInitialization, 100);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(backupInitialization);
|
clearTimeout(backupInitialization);
|
||||||
clearTimeout(emergencyInitialization);
|
clearTimeout(emergencyInitialization);
|
||||||
unlistenPromise.then((unlisten) => unlisten());
|
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user