From e4a8c53079d51367cef27da56ebcacf5f942d3aa Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 2 Jun 2026 14:04:00 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(window):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20Windows=20=E6=81=A2=E5=A4=8D=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E5=90=8E=E5=AD=97=E4=BD=93=E6=A8=A1=E7=B3=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Windows 从任务栏恢复窗口时直接触发 WebView2 zoom reset - restore 场景不再依赖 viewport ratio drift 判断 - 覆盖最大化和非最大化窗口的恢复修复路径 - 保留最大化窗口零动画修复,避免二次最大化抖动 - 补充窗口恢复策略和 App 自动修复路径测试 --- frontend/package.json.md5 | 2 +- frontend/src/App.tool-center.test.ts | 8 ++++++++ frontend/src/App.tsx | 19 ++++++++++++++++--- frontend/src/utils/windowStateUi.test.ts | 6 ++++-- frontend/src/utils/windowStateUi.ts | 4 ++-- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/frontend/package.json.md5 b/frontend/package.json.md5 index 7396e24..bed8925 100755 --- a/frontend/package.json.md5 +++ b/frontend/package.json.md5 @@ -1 +1 @@ -d0464f9da25e9356e61652e638c99ffe \ No newline at end of file +0295a42fd931778d85157816d79d29e5 \ No newline at end of file diff --git a/frontend/src/App.tool-center.test.ts b/frontend/src/App.tool-center.test.ts index 16b7f1b..ed14916 100644 --- a/frontend/src/App.tool-center.test.ts +++ b/frontend/src/App.tool-center.test.ts @@ -183,6 +183,14 @@ describe('tool center menu entries', () => { expect(appSource).toContain('switchActiveTabByOffset, themeMode'); }); + it('automatically resets WebView2 zoom when a Windows taskbar restore returns focus', () => { + expect(appSource).toContain('shouldResetWebViewZoomForScaleFix(reason, hasViewportScaleDrift)'); + expect(appSource).toContain('const shouldResetWebViewZoom = shouldResetWebViewZoomForScaleFix(reason, hasViewportScaleDrift);'); + expect(appSource).toContain('if (shouldResetWebViewZoom && !isMaximised)'); + expect(appSource).toContain('const res = await (window as any).go?.app?.App?.ResetWebViewZoom?.();'); + expect(appSource).toContain('该异常不一定表现为 viewport ratio drift'); + }); + it('keeps titlebar double-click on maximise while shortcuts may enter macOS fullscreen', () => { expect(appSource).toContain('const handleTitleBarWindowToggle = async (options?: { allowMacNativeFullscreen?: boolean }) => {'); expect(appSource).toContain('const allowMacNativeFullscreen = options?.allowMacNativeFullscreen === true;'); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6a040d9..f120f06 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -883,15 +883,28 @@ function App() { devicePixelRatio: Number(window.devicePixelRatio) || 1, visualViewportScale: window.visualViewport?.scale, }); + const shouldResetWebViewZoom = shouldResetWebViewZoomForScaleFix(reason, hasViewportScaleDrift); + + if (shouldResetWebViewZoom && !isMaximised) { + try { + const res = await (window as any).go?.app?.App?.ResetWebViewZoom?.(); + if (!res?.success) { + console.warn('ResetWebViewZoom unavailable in fixWindowScaleIfNeeded:', res?.message); + } + } catch (e) { + console.warn('ResetWebViewZoom call failed in fixWindowScaleIfNeeded', e); + } + } if (isMaximised) { if (!shouldToggleMaximisedWindowForScaleFix(reason, hasViewportScaleDrift)) { - // restore + drift(任务栏点击恢复后字体异常变大)的零感知修复路径: + // restore(任务栏点击恢复后字体异常变大/变糊)的零感知修复路径: // 调 backend App.ResetWebViewZoom 触发 WebView2 ICoreWebView2Controller::put_ZoomFactor(1.0), - // 让 WebView2 重算 D2D/DirectWrite 字体度量。完全不动窗口、零动画。 + // 让 WebView2 重算 D2D/DirectWrite 字体度量。该异常不一定表现为 viewport ratio drift, + // 所以 restore 场景不能依赖 hasViewportScaleDrift。完全不动窗口、零动画。 // backend 失败(wails 升级破坏反射 / 非 Windows)时回退到 dispatch resize 兜底; // 用户仍可按 Ctrl+Shift+0 手动 toggle 修复。 - if (shouldResetWebViewZoomForScaleFix(reason, hasViewportScaleDrift)) { + if (shouldResetWebViewZoom) { try { const res = await (window as any).go?.app?.App?.ResetWebViewZoom?.(); if (!res?.success) { diff --git a/frontend/src/utils/windowStateUi.test.ts b/frontend/src/utils/windowStateUi.test.ts index 978855f..f197d73 100644 --- a/frontend/src/utils/windowStateUi.test.ts +++ b/frontend/src/utils/windowStateUi.test.ts @@ -27,9 +27,11 @@ describe('windowStateUi', () => { expect(shouldToggleMaximisedWindowForScaleFix('restore', true)).toBe(false); }); - it('only calls the backend WebView2 zoom reset after a real restore drift', () => { + it('calls the backend WebView2 zoom reset whenever a minimized window is restored', () => { expect(shouldResetWebViewZoomForScaleFix('restore', true)).toBe(true); - expect(shouldResetWebViewZoomForScaleFix('restore', false)).toBe(false); + // 字体模糊/DirectWrite 度量缓存异常不一定表现为 viewport ratio drift, + // 因此任务栏恢复场景必须直接走零动画 WebView2 zoom reset。 + expect(shouldResetWebViewZoomForScaleFix('restore', false)).toBe(true); expect(shouldResetWebViewZoomForScaleFix('activation', true)).toBe(false); expect(shouldResetWebViewZoomForScaleFix('ratio-change', true)).toBe(false); }); diff --git a/frontend/src/utils/windowStateUi.ts b/frontend/src/utils/windowStateUi.ts index a8b88e9..5f1d8e2 100644 --- a/frontend/src/utils/windowStateUi.ts +++ b/frontend/src/utils/windowStateUi.ts @@ -22,8 +22,8 @@ export const shouldToggleMaximisedWindowForScaleFix = ( export const shouldResetWebViewZoomForScaleFix = ( reason: WindowScaleFixReason, - hasViewportScaleDrift: boolean, -): boolean => reason === 'restore' && hasViewportScaleDrift; + _hasViewportScaleDrift: boolean, +): boolean => reason === 'restore'; export const resolveWindowsScaleCheckDelayMs = (trigger: WindowsScaleCheckTrigger): number => trigger === 'resize' ? 240 : 0;