mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-21 16:34:21 +08:00
🐛 fix(window): 加固 Windows 冷启动半窗,原生最大化并兜底铺满工作区
- Windows 启动 WindowStartState 改为 Maximised,默认尺寸提升到 1440×900 - 无记忆/历史 1024×768/覆盖率过低的普通窗记忆改为启动最大化 - Maximise 多次失败时铺满工作区兜底,避免残留浮动半窗 - 用户刻意拉大的普通窗仍先 Unmaximise 再恢复尺寸位置
This commit is contained in:
@@ -5,6 +5,9 @@ import {
|
||||
isStartupWindowRestorePending,
|
||||
markStartupWindowRestorePending,
|
||||
resolveDefaultStartupWindowBounds,
|
||||
resolveWorkAreaFillWindowBounds,
|
||||
shouldPreferWindowsStartupMaximise,
|
||||
WINDOWS_STARTUP_MAXIMISE_AREA_RATIO,
|
||||
} from './windowStartupLayout';
|
||||
|
||||
describe('windowStartupLayout', () => {
|
||||
@@ -69,4 +72,61 @@ describe('windowStartupLayout', () => {
|
||||
vi.setSystemTime(new Date('2026-07-09T10:00:01.001Z'));
|
||||
expect(isStartupWindowRestorePending()).toBe(false);
|
||||
});
|
||||
|
||||
it('fills the OS work area as a maximise-failure fallback', () => {
|
||||
expect(resolveWorkAreaFillWindowBounds({
|
||||
availWidth: 1920,
|
||||
availHeight: 1040,
|
||||
availLeft: 0,
|
||||
availTop: 0,
|
||||
})).toEqual({
|
||||
width: 1920,
|
||||
height: 1040,
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
|
||||
expect(resolveWorkAreaFillWindowBounds({
|
||||
availWidth: 1600,
|
||||
availHeight: 900,
|
||||
availLeft: 1920,
|
||||
availTop: 40,
|
||||
})).toEqual({
|
||||
width: 1600,
|
||||
height: 900,
|
||||
x: 1920,
|
||||
y: 40,
|
||||
});
|
||||
});
|
||||
|
||||
it('prefers maximise for missing, legacy 1024×768, and undersized default windows', () => {
|
||||
const viewport = {
|
||||
availWidth: 1920,
|
||||
availHeight: 1080,
|
||||
availLeft: 0,
|
||||
availTop: 0,
|
||||
};
|
||||
|
||||
expect(shouldPreferWindowsStartupMaximise(null, viewport)).toBe(true);
|
||||
expect(shouldPreferWindowsStartupMaximise({
|
||||
width: 1024,
|
||||
height: 768,
|
||||
x: 0,
|
||||
y: 0,
|
||||
}, viewport)).toBe(true);
|
||||
|
||||
// 84%×84% default area ≈ 0.706 < 0.78 → 最大化
|
||||
const defaultBounds = resolveDefaultStartupWindowBounds(viewport);
|
||||
expect((defaultBounds.width * defaultBounds.height) / (1920 * 1080))
|
||||
.toBeLessThan(WINDOWS_STARTUP_MAXIMISE_AREA_RATIO);
|
||||
expect(shouldPreferWindowsStartupMaximise(defaultBounds, viewport)).toBe(true);
|
||||
|
||||
// 用户刻意拉大的普通窗应保留
|
||||
expect(shouldPreferWindowsStartupMaximise({
|
||||
width: 1760,
|
||||
height: 980,
|
||||
x: 80,
|
||||
y: 40,
|
||||
}, viewport)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,16 @@ export type StartupWindowBounds = {
|
||||
const MIN_STARTUP_WIDTH = 900;
|
||||
const MIN_STARTUP_HEIGHT = 600;
|
||||
|
||||
/**
|
||||
* 工作区覆盖率低于该阈值时,视为「半窗 / 默认小窗」记忆,Windows 启动改走最大化。
|
||||
* 84%×84% 居中默认窗的面积比约为 0.706,会被捕获;用户刻意拉大的普通窗通常更高。
|
||||
*/
|
||||
export const WINDOWS_STARTUP_MAXIMISE_AREA_RATIO = 0.78;
|
||||
|
||||
/** Align with historical main.go Width/Height defaults that look half-open on modern screens. */
|
||||
const LEGACY_DEFAULT_WIDTH = 1024;
|
||||
const LEGACY_DEFAULT_HEIGHT = 768;
|
||||
|
||||
/**
|
||||
* Resolve a usable first-launch window when no persisted bounds exist.
|
||||
* Windows defaults to top-left 1024x768 which looks "half open" on modern screens.
|
||||
@@ -50,6 +60,62 @@ export const resolveDefaultStartupWindowBounds = (
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Fill the OS work area (taskbar excluded). Used when Maximise API fails on Windows
|
||||
* so the shell still looks "full" instead of lingering at 1024×768 / 84% floating.
|
||||
*/
|
||||
export const resolveWorkAreaFillWindowBounds = (
|
||||
viewport: StartupVisibleViewport,
|
||||
): StartupWindowBounds => {
|
||||
const availWidth = Math.max(0, Math.trunc(Number(viewport.availWidth) || 0));
|
||||
const availHeight = Math.max(0, Math.trunc(Number(viewport.availHeight) || 0));
|
||||
const availLeft = Math.trunc(Number(viewport.availLeft) || 0);
|
||||
const availTop = Math.trunc(Number(viewport.availTop) || 0);
|
||||
|
||||
if (availWidth <= 0 || availHeight <= 0) {
|
||||
return resolveDefaultStartupWindowBounds(viewport);
|
||||
}
|
||||
|
||||
return {
|
||||
width: Math.max(MIN_STARTUP_WIDTH, availWidth),
|
||||
height: Math.max(MIN_STARTUP_HEIGHT, availHeight),
|
||||
x: availLeft,
|
||||
y: availTop,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Decide whether Windows cold-start should prefer maximise over restoring bounds.
|
||||
* - 无记忆 / 非法尺寸 → 最大化
|
||||
* - 仍像旧默认 1024×768 → 最大化
|
||||
* - 覆盖工作区面积过低(含历史 84% 居中默认窗)→ 最大化
|
||||
*/
|
||||
export const shouldPreferWindowsStartupMaximise = (
|
||||
bounds: StartupWindowBounds | null | undefined,
|
||||
viewport: StartupVisibleViewport,
|
||||
): boolean => {
|
||||
if (!bounds) {
|
||||
return true;
|
||||
}
|
||||
const width = Math.trunc(Number(bounds.width) || 0);
|
||||
const height = Math.trunc(Number(bounds.height) || 0);
|
||||
if (width < 400 || height < 300) {
|
||||
return true;
|
||||
}
|
||||
if (width <= LEGACY_DEFAULT_WIDTH && height <= LEGACY_DEFAULT_HEIGHT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const availWidth = Math.max(0, Math.trunc(Number(viewport.availWidth) || 0));
|
||||
const availHeight = Math.max(0, Math.trunc(Number(viewport.availHeight) || 0));
|
||||
if (availWidth <= 0 || availHeight <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const areaRatio = (width * height) / (availWidth * availHeight);
|
||||
return areaRatio < WINDOWS_STARTUP_MAXIMISE_AREA_RATIO;
|
||||
};
|
||||
|
||||
let startupWindowRestorePendingUntil = 0;
|
||||
|
||||
/** Mark a short grace window while startup maximise/fullscreen is still settling. */
|
||||
|
||||
Reference in New Issue
Block a user