mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 23:13:44 +08:00
fix: resolve lightweight mode recovery failure caused by white screen prevention
This commit is contained in:
parent
abe5cf1b84
commit
d05952e945
@ -222,3 +222,11 @@ pub fn notify_ui_ready() -> CmdResult<()> {
|
||||
crate::utils::resolve::mark_ui_ready();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 重置UI就绪状态
|
||||
#[tauri::command]
|
||||
pub fn reset_ui_ready_state() -> CmdResult<()> {
|
||||
log::info!(target: "app", "重置UI就绪状态");
|
||||
crate::utils::resolve::reset_ui_ready();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -7,3 +7,9 @@ pub async fn entry_lightweight_mode() -> CmdResult {
|
||||
lightweight::entry_lightweight_mode();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn exit_lightweight_mode() -> CmdResult {
|
||||
lightweight::exit_lightweight_mode();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -206,7 +206,14 @@ impl Tray {
|
||||
match tray_event.as_str() {
|
||||
"system_proxy" => feat::toggle_system_proxy(),
|
||||
"tun_mode" => feat::toggle_tun_mode(None),
|
||||
"main_window" => resolve::create_window(true),
|
||||
"main_window" => {
|
||||
// 如果在轻量模式中,先退出轻量模式
|
||||
if crate::module::lightweight::is_in_lightweight_mode() {
|
||||
crate::module::lightweight::exit_lightweight_mode();
|
||||
}
|
||||
// 然后创建窗口
|
||||
resolve::create_window(true)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -680,7 +687,14 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
||||
println!("change mode to: {}", mode);
|
||||
feat::change_clash_mode(mode.into());
|
||||
}
|
||||
"open_window" => resolve::create_window(true),
|
||||
"open_window" => {
|
||||
// 如果在轻量模式中,先退出轻量模式
|
||||
if crate::module::lightweight::is_in_lightweight_mode() {
|
||||
crate::module::lightweight::exit_lightweight_mode();
|
||||
}
|
||||
// 然后创建窗口
|
||||
resolve::create_window(true)
|
||||
}
|
||||
"system_proxy" => feat::toggle_system_proxy(),
|
||||
"tun_mode" => feat::toggle_tun_mode(None),
|
||||
"copy_env" => feat::copy_clash_env(),
|
||||
|
@ -160,10 +160,14 @@ pub fn run() {
|
||||
cmd::restart_app,
|
||||
// 添加新的命令
|
||||
cmd::notify_ui_ready,
|
||||
cmd::reset_ui_ready_state,
|
||||
cmd::get_running_mode,
|
||||
cmd::get_app_uptime,
|
||||
cmd::get_auto_launch_status,
|
||||
cmd::is_admin,
|
||||
// 添加轻量模式相关命令
|
||||
cmd::entry_lightweight_mode,
|
||||
cmd::exit_lightweight_mode,
|
||||
// service 管理
|
||||
cmd::install_service,
|
||||
cmd::uninstall_service,
|
||||
|
@ -9,12 +9,33 @@ use crate::{
|
||||
use anyhow::{Context, Result};
|
||||
use delay_timer::prelude::TaskBuilder;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
use tauri::{Listener, Manager};
|
||||
|
||||
pub static AUTO_LIGHT_WEIGHT_MODE_INIT: OnceCell<()> = OnceCell::new();
|
||||
|
||||
const LIGHT_WEIGHT_TASK_UID: &str = "light_weight_task";
|
||||
|
||||
// 轻量模式状态标志
|
||||
static IS_LIGHTWEIGHT_MODE: OnceCell<Arc<RwLock<bool>>> = OnceCell::new();
|
||||
|
||||
fn get_lightweight_mode() -> &'static Arc<RwLock<bool>> {
|
||||
IS_LIGHTWEIGHT_MODE.get_or_init(|| Arc::new(RwLock::new(false)))
|
||||
}
|
||||
|
||||
// 检查是否处于轻量模式
|
||||
pub fn is_in_lightweight_mode() -> bool {
|
||||
*get_lightweight_mode().read()
|
||||
}
|
||||
|
||||
// 设置轻量模式状态
|
||||
fn set_lightweight_mode(value: bool) {
|
||||
let mut mode = get_lightweight_mode().write();
|
||||
*mode = value;
|
||||
logging!(info, Type::Lightweight, true, "轻量模式状态: {}", value);
|
||||
}
|
||||
|
||||
pub fn enable_auto_light_weight_mode() {
|
||||
Timer::global().init().unwrap();
|
||||
logging!(info, Type::Lightweight, true, "开启自动轻量模式");
|
||||
@ -40,9 +61,21 @@ pub fn entry_lightweight_mode() {
|
||||
AppHandleManager::global().set_activation_policy_accessory();
|
||||
logging!(info, Type::Lightweight, true, "轻量模式已开启");
|
||||
}
|
||||
// 标记已进入轻量模式
|
||||
set_lightweight_mode(true);
|
||||
let _ = cancel_light_weight_timer();
|
||||
}
|
||||
|
||||
// 从轻量模式恢复
|
||||
pub fn exit_lightweight_mode() {
|
||||
// 标记退出轻量模式
|
||||
set_lightweight_mode(false);
|
||||
logging!(info, Type::Lightweight, true, "正在退出轻量模式");
|
||||
|
||||
// 重置UI就绪状态
|
||||
crate::utils::resolve::reset_ui_ready();
|
||||
}
|
||||
|
||||
pub fn add_light_weight_timer() {
|
||||
logging_error!(Type::Lightweight, setup_light_weight_timer());
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use percent_encoding::percent_decode_str;
|
||||
use serde_json;
|
||||
use serde_yaml::Mapping;
|
||||
use std::{net::TcpListener, sync::Arc};
|
||||
use tauri::{App, Manager};
|
||||
use tauri::{App, Emitter, Manager};
|
||||
|
||||
use tauri::Url;
|
||||
//#[cfg(not(target_os = "linux"))]
|
||||
@ -41,6 +41,13 @@ pub fn mark_ui_ready() {
|
||||
*ready = true;
|
||||
}
|
||||
|
||||
// 重置UI就绪状态
|
||||
pub fn reset_ui_ready() {
|
||||
let mut ready = get_ui_ready().write();
|
||||
*ready = false;
|
||||
logging!(info, Type::Window, true, "UI就绪状态已重置");
|
||||
}
|
||||
|
||||
pub fn find_unused_port() -> Result<u16> {
|
||||
match TcpListener::bind("127.0.0.1:0") {
|
||||
Ok(listener) => {
|
||||
@ -219,26 +226,30 @@ pub fn create_window(is_showup: bool) {
|
||||
#[cfg(target_os = "macos")]
|
||||
AppHandleManager::global().set_activation_policy_regular();
|
||||
|
||||
// 检查是否从轻量模式恢复
|
||||
let from_lightweight = crate::module::lightweight::is_in_lightweight_mode();
|
||||
if from_lightweight {
|
||||
logging!(info, Type::Window, true, "从轻量模式恢复窗口");
|
||||
crate::module::lightweight::exit_lightweight_mode();
|
||||
}
|
||||
|
||||
if let Some(window) = handle::Handle::global().get_window() {
|
||||
logging!(
|
||||
info,
|
||||
Type::Window,
|
||||
true,
|
||||
"Found existing window, attempting to restore visibility"
|
||||
);
|
||||
logging!(info, Type::Window, true, "Found existing window");
|
||||
|
||||
if window.is_minimized().unwrap_or(false) {
|
||||
logging!(
|
||||
info,
|
||||
Type::Window,
|
||||
true,
|
||||
"Window is minimized, restoring window state"
|
||||
);
|
||||
let _ = window.unminimize();
|
||||
}
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
return;
|
||||
|
||||
if from_lightweight {
|
||||
// 从轻量模式恢复需要销毁旧窗口以重建
|
||||
logging!(info, Type::Window, true, "销毁旧窗口以重建新窗口");
|
||||
let _ = window.close();
|
||||
} else {
|
||||
// 普通情况直接显示窗口
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 定义默认窗口大小
|
||||
@ -346,83 +357,65 @@ pub fn create_window(is_showup: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// 创建异步任务处理UI就绪和显示窗口
|
||||
let was_from_lightweight = from_lightweight;
|
||||
AsyncHandler::spawn(move || async move {
|
||||
use tauri::Emitter;
|
||||
|
||||
logging!(info, Type::Window, true, "UI gets ready.");
|
||||
// 处理启动完成
|
||||
handle::Handle::global().mark_startup_completed();
|
||||
|
||||
if let Some(window) = app_handle_clone.get_webview_window("main") {
|
||||
// 检查窗口大小
|
||||
match window.inner_size() {
|
||||
Ok(size) => {
|
||||
let width = size.width;
|
||||
let height = size.height;
|
||||
|
||||
let state_width = STATE_WIDTH.get().copied().unwrap_or(DEFAULT_WIDTH);
|
||||
let state_height =
|
||||
STATE_HEIGHT.get().copied().unwrap_or(DEFAULT_HEIGHT);
|
||||
|
||||
logging!(
|
||||
info,
|
||||
Type::Window,
|
||||
true,
|
||||
"异步任务中窗口尺寸: {}x{}, 状态文件尺寸: {}x{}",
|
||||
width,
|
||||
height,
|
||||
state_width,
|
||||
state_height
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(
|
||||
error,
|
||||
Type::Window,
|
||||
true,
|
||||
"Failed to get window size: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 发送启动完成事件
|
||||
let _ = window.emit("verge://startup-completed", ());
|
||||
|
||||
if is_showup {
|
||||
// 启动一个任务等待UI准备就绪再显示窗口
|
||||
let window_clone = window.clone();
|
||||
AsyncHandler::spawn(move || async move {
|
||||
async fn wait_for_ui_ready() {
|
||||
while !*get_ui_ready().read() {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
|
||||
}
|
||||
}
|
||||
|
||||
match tokio::time::timeout(
|
||||
std::time::Duration::from_secs(5),
|
||||
wait_for_ui_ready(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
logging!(info, Type::Window, true, "UI准备就绪,显示窗口");
|
||||
}
|
||||
Err(_) => {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Window,
|
||||
true,
|
||||
"等待UI准备就绪超时,强制显示窗口"
|
||||
);
|
||||
}
|
||||
}
|
||||
// 从轻量模式恢复时使用较短的超时,避免卡死
|
||||
let timeout_seconds = if was_from_lightweight {
|
||||
// 从轻量模式恢复只等待2秒,确保不会卡死
|
||||
2
|
||||
} else {
|
||||
5
|
||||
};
|
||||
|
||||
let _ = window_clone.show();
|
||||
let _ = window_clone.set_focus();
|
||||
});
|
||||
// 等待UI就绪
|
||||
async fn wait_for_ui_ready() {
|
||||
while !*get_ui_ready().read() {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用超时机制等待UI就绪
|
||||
match tokio::time::timeout(
|
||||
std::time::Duration::from_secs(timeout_seconds),
|
||||
wait_for_ui_ready(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
logging!(info, Type::Window, true, "UI准备就绪,显示窗口");
|
||||
}
|
||||
Err(_) => {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Window,
|
||||
true,
|
||||
"等待UI准备就绪超时({}秒),强制显示窗口",
|
||||
timeout_seconds
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 无论是否超时,都显示窗口
|
||||
let _ = window_clone.show();
|
||||
let _ = window_clone.set_focus();
|
||||
}
|
||||
} else {
|
||||
logging!(error, Type::Window, true, "无法获取主窗口");
|
||||
}
|
||||
});
|
||||
|
||||
logging!(info, Type::Window, true, "异步任务已创建");
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(
|
||||
|
@ -214,6 +214,8 @@ const Layout = () => {
|
||||
useEffect(() => {
|
||||
const notifyUiReady = async () => {
|
||||
try {
|
||||
await invoke("reset_ui_ready_state");
|
||||
console.log("已重置UI就绪状态");
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
await invoke("notify_ui_ready");
|
||||
console.log("已通知后端UI准备就绪");
|
||||
@ -224,12 +226,19 @@ const Layout = () => {
|
||||
|
||||
// 监听后端发送的启动完成事件
|
||||
const listenStartupCompleted = async () => {
|
||||
const unlisten = await listen("verge://startup-completed", () => {
|
||||
console.log("收到启动完成事件");
|
||||
});
|
||||
return unlisten;
|
||||
try {
|
||||
const unlisten = await listen("verge://startup-completed", () => {
|
||||
console.log("收到启动完成事件,开始通知UI就绪");
|
||||
notifyUiReady();
|
||||
});
|
||||
return unlisten;
|
||||
} catch (err) {
|
||||
console.error("监听启动完成事件失败:", err);
|
||||
return () => {};
|
||||
}
|
||||
};
|
||||
|
||||
console.log("页面初始加载,通知UI就绪");
|
||||
notifyUiReady();
|
||||
const unlistenPromise = listenStartupCompleted();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user