Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions openless-all/app/src-tauri/src/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ fn capsule_show_strategy_for_platform() -> CapsuleShowStrategy {
static CAPSULE_NO_ACTIVATE_FALLBACK_WARNED: AtomicBool = AtomicBool::new(false);
static CAPSULE_SUPPRESSED_BY_TOGGLE_LOGGED: AtomicBool = AtomicBool::new(false);
static CAPSULE_FIRST_SHOW_LOGGED: AtomicBool = AtomicBool::new(false);
// #470 诊断 v2:capsule webview 句柄取不到时的一次性门,区分「窗口压根没创建」(A0)。
static CAPSULE_WINDOW_MISSING_LOGGED: AtomicBool = AtomicBool::new(false);

/// 给 #470 诊断日志用的 capsule 状态短名。显式枚举每个变体到 &'static str,
/// 不走 `Debug` —— 哪天 CapsuleState 加了 `String` 字段,`:?` 会把 ASR / polish
Expand Down Expand Up @@ -4989,9 +4991,13 @@ fn show_capsule_window_no_activate<R: tauri::Runtime>(
};

let Ok(handle) = window.window_handle() else {
// #470 诊断 v2:Win32 show 路径最可能的暗点之一。此前静默 return,
// 无法观测「胶囊完全不显示」是否卡在这里。
log::warn!("[capsule] no_activate failed: window_handle() unavailable — Win32 show skipped");
return false;
};
let RawWindowHandle::Win32(raw) = handle.as_raw() else {
log::warn!("[capsule] no_activate failed: non-Win32 RawWindowHandle — Win32 show skipped");
return false;
};
let hwnd = HWND(raw.hwnd.get() as *mut _);
Expand Down Expand Up @@ -5226,6 +5232,14 @@ fn emit_capsule(
let app_for_main = app.clone();
let _ = app.run_on_main_thread(move || {
let Some(window) = app_for_main.get_webview_window("capsule") else {
// #470 诊断 v2:比 A/B/C 更靠前的暗点 A0 —— capsule webview 句柄取不到
// (窗口未创建/已销毁)。此前静默 return,无法观测。一次性 warn。
if !CAPSULE_WINDOW_MISSING_LOGGED.swap(true, Ordering::SeqCst) {
log::warn!(
"[capsule] capsule webview window not found — emit_capsule show path skipped (state={})",
capsule_state_log_name(state)
);
}
return;
};
let show_capsule = inner_for_main.prefs.get().show_capsule;
Expand Down
10 changes: 9 additions & 1 deletion openless-all/app/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,15 @@ pub(crate) fn position_capsule_bottom_center<R: tauri::Runtime>(
let offset_from_bottom =
(capsule_visual_height(translation_active) + 80.0 + bounds.bottom_inset) * scale;
let y = ((mon.bottom as f64) - offset_from_bottom).round() as i32;
window.set_position(PhysicalPosition::new(x, y.max(mon.top)))?;
let clamped_y = y.max(mon.top);
// #470 诊断 v2:当前只夹了上边(.max(mon.top)),未夹下/左/右。多显示器、
// 负坐标或异常 DPI 下胶囊可能被算到屏幕外却无任何观测。记录显示器几何与
// 最终落点,用于证伪/证实「胶囊定位到屏幕外」(C 子嫌疑)。
log::debug!(
"[capsule] win position: mon=({},{})..({},{}) scale={:.2} size=({}x{}) -> x={} y={} clamped_y={}",
mon.left, mon.top, mon.right, mon.bottom, scale, phys_w, phys_h, x, y, clamped_y
);
window.set_position(PhysicalPosition::new(x, clamped_y))?;
return Ok(());
}
// 仅当 Win32 取不到前台显示器时,落回下面的 current_monitor 逻辑。
Expand Down
9 changes: 9 additions & 0 deletions openless-all/app/src/components/Capsule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ function Pill({ os, state, level, insertedChars, message, onCancel, onConfirm }:
// 动画结束就 unmount → 用户看到半截动画被截断。
// v1.3.1-6: 从 240ms 加到 360ms 让用户看清退出动画(240ms 太快感知不到)。
const EXIT_ANIM_MS = 360;
// #470 诊断 v2:模块级一次性门,只在 webview 收到第一个 capsule:state 事件时打 log。
let capsuleStateFirstLogged = false;

// 初始可见 state:Tauri 内运行从 idle 开始(等后端 capsule:state 事件),
// 浏览器 dev 模式从 recording 开始以便直接看到胶囊。
const INITIAL_VISIBLE_STATE: CapsuleState = isTauri ? 'idle' : 'recording';
Expand Down Expand Up @@ -321,6 +324,12 @@ export function Capsule() {
const { listen } = await import('@tauri-apps/api/event');
const handle = await listen<CapsulePayload>('capsule:state', event => {
const p = event.payload;
if (!capsuleStateFirstLogged) {
capsuleStateFirstLogged = true;
// #470 诊断 v2:确认 capsule webview 确实收到了后端事件 —— 区分「后端没
// emit」与「emit 了但窗口没显示/没渲染」。配合后端 [capsule] 日志定位根因。
console.info('[capsule] first capsule:state received in webview, state=', p.state);
}
setState(p.state);
setLevel(p.level ?? 0);
setMessage(p.message ?? undefined);
Expand Down
Loading