// Persists BrowserWindow bounds + maximized state to userData/. // Saves are debounced 500ms on move/resize, and fired synchronously on close. // Validates loaded bounds against the current display layout to avoid // restoring a window onto a display that no longer exists. import { app, BrowserWindow, screen } from 'electron'; import { promises as fs } from 'node:fs'; import path from 'node:path'; interface State { x?: number; y?: number; width: number; height: number; maximized?: boolean; } const DEFAULT: State = { width: 1200, height: 800 }; function isOnAnyDisplay(bounds: { x: number; y: number; width: number; height: number }): boolean { for (const d of screen.getAllDisplays()) { const wa = d.workArea; if ( bounds.x >= wa.x && bounds.y >= wa.y && bounds.x + bounds.width <= wa.x + wa.width + 8 && bounds.y + bounds.height <= wa.y + wa.height + 8 ) { return true; } } return false; } export async function loadState(filename: string): Promise { const filePath = path.join(app.getPath('userData'), filename); try { const raw = await fs.readFile(filePath, 'utf8'); const parsed = JSON.parse(raw) as Partial; const width = typeof parsed.width === 'number' ? parsed.width : DEFAULT.width; const height = typeof parsed.height === 'number' ? parsed.height : DEFAULT.height; const state: State = { width, height }; if (typeof parsed.x === 'number' && typeof parsed.y === 'number') { if (isOnAnyDisplay({ x: parsed.x, y: parsed.y, width, height })) { state.x = parsed.x; state.y = parsed.y; } } if (parsed.maximized) state.maximized = true; return state; } catch { return { ...DEFAULT }; } } export function attach(win: BrowserWindow, filename: string): void { const filePath = path.join(app.getPath('userData'), filename); let saveTimer: NodeJS.Timeout | null = null; const writeNow = (): void => { if (win.isDestroyed()) return; const bounds = win.getNormalBounds(); const state: State = { x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height, maximized: win.isMaximized(), }; // Fire-and-forget; exceptions are logged but non-fatal. void fs .writeFile(filePath, JSON.stringify(state), 'utf8') .catch((err: unknown) => { console.warn('[window-state] write failed', err); }); }; const schedule = (): void => { if (saveTimer) clearTimeout(saveTimer); saveTimer = setTimeout(writeNow, 500); }; win.on('move', schedule); win.on('resize', schedule); win.on('maximize', schedule); win.on('unmaximize', schedule); win.on('close', () => { if (saveTimer) clearTimeout(saveTimer); writeNow(); }); }